Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

результат выходит за пределы допустимых значений для типа переменной

11K
17 апреля 2008 года
zuze
84 / / 07.03.2008
Я сделал функцию вычисления факториала

Вот код

 
Код:
unsigned short factorial(unsigned short num)
{
    unsigned short i, f;
    f = 1;
    for (i = 2; i <= num; i++)
        f = f*i;
    return f;
}


Если я ввожу например 8 функция возратит правельное значение, так как оно входит в диапазон unsigned short.
Если я ввожу например 9 будет ошибка результат выходит за пределы допустимых значений для типа.

Как мне сделать, что при ситуации когда результат выходит за пределы допустимых значений для типа, выскакивало бы сообщение например "Факториал не может быть вычеслин".

Помогите пожалуйста.
535
17 апреля 2008 года
Нездешний
537 / / 17.01.2008
Первое, что пришло в голову -- проверять флаг переноса CF. Но для этого придется воспользоваться ассемблером

Код:
unsigned short factorial(unsigned short num)
{
    unsigned short i, f;
    f = 1;
    for (i = 2; i <= num; i++)
    {
        __asm
                {
            mov ax, f
            mov cx, i
            mul cx

            jnc __local
            jmp __carry
            __local: mov f, ax
        }
    }

    return f;

    __carry:    MessageBox(NULL, "Out of range", NULL, NULL);
    return 0;
}


Если извращаться не хочешь ;) , запоминай предыдущее значение f, сравнивай с полученным -- если полученное на очередном шаге меньше предыдущего, то out of range

Код:
unsigned short factorial(unsigned short num)
{
    unsigned short i, f, prev_f;
    f = 1;
    for (i = 2; i <= num; i++)
    {
        prev_f = f;
        f = f * i;

        if(prev_f >= f)
        {
            MessageBox(NULL, "Out of range", NULL, NULL);
            return 0;
        }
    }

    return f;
}
247
17 апреля 2008 года
wanja
1.2K / / 03.02.2003
Возьми тип побольше, long, например.
11
17 апреля 2008 года
oxotnik333
2.9K / / 03.08.2007
легких путей не ищем называется....

try {/*вычисления*/}
catch (...){/*сообщение об исключении*/}
3
17 апреля 2008 года
Green
4.8K / / 20.01.2000
Цитата: zuze

Как мне сделать, что при ситуации когда результат выходит за пределы допустимых значений для типа, выскакивало бы сообщение например "Факториал не может быть вычеслин".

Помогите пожалуйста.


Код:
unsigned short factorial(unsigned short num)
{
    if(num > 8) {
        throw "Факториал не может быть вычЕслИн"
    }

    unsigned short i, f;
    f = 1;
    for (i = 2; i <= num; i++)
        f = f*i;
    return f;
}
11K
17 апреля 2008 года
zuze
84 / / 07.03.2008
Я сделал так

Вот код

Код:
#include <iostream.h>

unsigned short factorial(unsigned short num);

int main(void)
{
   unsigned short numfactorial;
   cout << "Enter number factorial: ";
   cin >> numfactorial;
   unsigned short temp = factorial(numfactorial);
    try
    {
       throw temp;
    }
    catch (unsigned short temp)
    {
       cout << "Factorial algoritm: " << temp;
    }
    catch (...)
    {
      cout << "Error Factorial!";
    }

    return 0;
}
unsigned short factorial(unsigned short num)
{
    unsigned short result = 1;
    for (unsigned short i = 2; i <= num; i++)
        result = result*i;
    return result;
}


Я ввожу 9, а программа пишет 35200, а должна писать "Error Factorial!"

Подскажите пожалуйста, где я ошибся.
11K
17 апреля 2008 года
zuze
84 / / 07.03.2008
Было сделано так

Код:
#ifndef _FACTORIAL_H_
#define _FACTORIAL_H_

class Factorial
{
      private:
           int num;
      public:
           Factorial();
           ~Factorial();
           unsigned int recfactorial(unsigned short num);
           unsigned int factorial(unsigned short num);
};
Factorial :: Factorial()
{
    num = 0;
}
Factorial :: ~Factorial()
{
}
unsigned int Factorial :: recfactorial(unsigned short num)
{
   unsigned short result;
   if (num == 1 || num == 0)
      result = 1;
   else
      result = num*recfactorial(num-1);
   return result;  
}
unsigned int Factorial :: factorial(unsigned short num)
{
    typedef unsigned short mytype;
    unsigned int result = 1;
    for (unsigned short i = 2; i <= num; i++)
    {
        result = result*i;
        if (result != mytype(result))
           throw "Error Factorial!";
    }
    return result;
}

#endif


и

Код:
#include <iostream.h>
#include "factorial.h"

int main(void)
{
    unsigned short numfactorial;
    cout << "Enter number factorial: ";
    cin >> numfactorial;
    Factorial Factorial1;
    unsigned short temp = 0 ;
    try
    {
       temp =  Factorial1.factorial(numfactorial);
    }
    catch (const char *)
    {
      cout << "Error Factorial!";
    }
    if (temp > 0)
       cout << "Factorial (not recursiv algoritm): " << temp;
    return 0;
}


Работает.

Только у меня один маленький вопросик.
Хотелось бы уточнить одну вещь результат факториала лежит в переменной типа unsigned int, вводимое значение имеет тип unsigned short. Если я введу самое большое значение которое можно ввести unsigned short это 65535, значение фактариала не выдет за значение типа, unsigned int или выдет? Может надо указать другой тип?
3
17 апреля 2008 года
Green
4.8K / / 20.01.2000
Жуть! Зачем здесь класс?!
С единственным и НЕИСПОЛЬЗУЕМЫМ полем!
31K
23 апреля 2008 года
volga
15 / / 09.10.2007
Код:
#include <boost/numeric/conversion/cast.hpp>

...

unsigned short factorial(unsigned short num)
{
    unsigned short i, f;
    f = 1;
try{
    for (i = 2; i <= num; i++)
        f = boost::numeric_cast<short>(f*i);
}
catch(boost::numeric::bad_numeric_cast& e)
{
std::cout << "Error in factorial: " << e.what() << std::endl;

return 0; // нет такого числа, факториал которого равен нулю (ну или сделай то, что считаешь нужным)
}
    return f;
}


boost::numeric_cast
3
23 апреля 2008 года
Green
4.8K / / 20.01.2000
Цитата: volga
Код:
#include <boost/numeric/conversion/cast.hpp>

...

unsigned short factorial(unsigned short num)
{
    unsigned short i, f;
    f = 1;
try{
    for (i = 2; i <= num; i++)
        f = boost::numeric_cast<short>(f*i);
}
catch(boost::numeric::bad_numeric_cast& e)
{
std::cout << "Error in factorial: " << e.what() << std::endl;

return 0; // нет такого числа, факториал которого равен нулю (ну или сделай то, что считаешь нужным)
}
    return f;
}


boost::numeric_cast



Ещё один пример того, как простые вещи делаются через сложную задницу.

31K
24 апреля 2008 года
volga
15 / / 09.10.2007
При всем уважении...
имхо, нет ничего хуже изобретения велосипеда, тогда как есть стандартные решения для стандартных задач.
Код:
unsigned short factorial(unsigned short num)
{
    if(num > 8) {
        throw "Факториал не может быть вычЕслИн"
    }

    unsigned short i, f;
    f = 1;
    for (i = 2; i <= num; i++)
        f = f*i;
    return f;
}


Есть повод гордиться расширяемостью и легкостью дальнейшего сопровождения.
3
24 апреля 2008 года
Green
4.8K / / 20.01.2000
Цитата: volga
При всем уважении...
имхо, нет ничего хуже изобретения велосипеда, тогда как есть стандартные решения для стандартных задач.


Нет ничего хуже применения стандартных решений не по месту и усложнение кода без необходимости. Вот это настоящее зло.

Цитата: volga

Есть повод гордиться расширяемостью и легкостью дальнейшего сопровождения.


Поговорим о расширяемости и сопровождении варианта с numeric_cast?

562
24 апреля 2008 года
tarekon
175 / / 19.08.2003
Код:
typedef TFactorialResult unsigned short;

TFactorialResult factorial( const unsigned short num )
{
    TFactorialResult result = 1;
    for( unsigned short i = 1; i < num; ++i ) {

        TFactorialResult currentStepResult = result * i;
        if( currentStepResult < result ) {
            throw "Error";
        }
        result = currentStepResult;
    }
    return result;
}

Этот код тоже ошибочен - нельзя быть уверенным, что результат переполнения не окажется в интервале [result;UINT_MAX] для какого-нибудь шага итерации. Как вариант уменьшения вероятности этого можно подсчет вести с конца, а не начала. Для unsigned short его использовать можно :)

Другой, более правильный, но менее быстрый способ - на каждом шаге делать проверку
 
Код:
if( currentStepResult / i != result )

В принципе для unsigned short накладные расходы будут невелики, но код - более надежным. Будет и более безопасна замена на unsigned int, на __uint64 или на <что-там-будет-дальше>.
3
24 апреля 2008 года
Green
4.8K / / 20.01.2000
Да для 9 валидных входных значений, которые нужны автору топика, вообще, ничего не надо делать в рантайме. Достаточно создать таблицу в компилед-тайме, а в рантайме проверять лишь валидность входных значений.
Проблема яйца выеденного не стоит, а шуму...

Что касается подхода вообще, то проще проверить входные значения, если функция имеет монотонность и не имеет разрывов (как в случае с факториалом), чем на каждом шаге (ну нифига себе) проверять не вышли ли мы за границы.
31K
25 апреля 2008 года
volga
15 / / 09.10.2007
Весьма вероятно, что однажды автору захочется сделать что-то вроде этого:
 
Код:
template<typename A, typename R>
R factorial(A arg)
{
    R f = 1;
    for (A i = 2; i <= arg; ++i)
        f *= i;

    return f;
}


Какие тут проверки входного значения будем ставить?
3
25 апреля 2008 года
Green
4.8K / / 20.01.2000
Цитата: volga
Весьма вероятно, что однажды автору захочется сделать что-то вроде этого:
 
Код:
template<typename A, typename R>
R factorial(A arg)
{
    R f = 1;
    for (A i = 2; i <= arg; ++i)
        f *= i;

    return f;
}


Совсем невероятно. Но когда такая необходимость появится, тогда и будем её решать.
Ты читал Джоэла Спольски? У него есть хорошая заметка, которая подойдет и к твоему посту:
http://www.joelonsoftware.com/articles/fog0000000018.html

Цитата: volga

Какие тут проверки входного значения будем ставить?


Так вот, если необходимость появится, проще, опять же, проверить соответствие входных данных разрядности типа результата. Причем можно так же использовать компилед-тайм, а можно и в ран-тайме с помощью того факта, что log(n!) = log(1) + log(2) + ... + log(n).
Другой вариант - проверять промежуточные значения вычисления на непревышение максимально возможного значения, но он мне нравится меньше.

А теперь покажи, пожалуйста, как ты собираешься решать эту же задачу с помощью boost::numeric_cast ? :)

31K
25 апреля 2008 года
volga
15 / / 09.10.2007
Да, спасибо, интересная статейка.
Я архитектурный астронавт? ну уж нет - это это точно не про меня :)

Цитата:

Совсем невероятно. Но когда такая необходимость появится, тогда и будем её решать.


Почему невероятно? Я часто пишу сначала нешаблонную функцию для того, чтобы проверить алгоритм, а потом её обощаю для удобства дальнейшего использования.
Бывает полезно подумать о наиболее вероятных изменениях, которые захочется позже сделать. ИМХО, переделывать функции на шаблонные - весьма вероятное изменение.

Как с numeric_cast? Ну так весь прикол в том, что практически точно также:

Код:
template<typename A, typename R>
R factorial(A arg)
{
    R f = 1;
    try{
        for (A i = 2; i <= arg; ++i)
            f = boost::numeric_cast<R>(f*i);
    }
    catch(boost::numeric::bad_numeric_cast& e)
    {
        std::cout << "Error in factorial: " << e.what() << std::endl;
        return 0;
    }

    return f;
}


Или вообще так: (если потом не лениться ловить у себя в коде исключения)

 
Код:
template<typename A, typename R>
R factorial(A arg)
{
    R f = 1;
    for (A i = 2; i <= arg; ++i)
        f = boost::numeric_cast<R>(f*i);

    return f;
}


Единственный минус этого решения я вижу в том, что клиентам этой функции прийдётся явно указывать тип возвращаемого значения.
5
25 апреля 2008 года
hardcase
4.5K / / 09.08.2005
Цитата: volga
ИМХО, переделывать функции на шаблонные - весьма вероятное изменение.


Разрабатываю на C# (в настоящий момент веб проект с самописным ORM). Сколько шаблонных функций пришлось мне реализовать? Одну. Для постраничного чтения запроса в БД. В остальном кое где отражение, кое где рантаймное кодогенерирование.

Цитата: volga

Как с numeric_cast? Ну так весь прикол в том, что практически точно также:

Код:
template<typename A, typename R>
R factorial(A arg)
{
    R f = 1;
    try{
        for (A i = 2; i <= arg; ++i)
            f = boost::numeric_cast<R>(f*i);
    }
    catch(boost::numeric::bad_numeric_cast& e)
    {
        std::cout << "Error in factorial: " << e.what() << std::endl;
        return 0;
    }

    return f;
}


Минут 5 вникал чего делается тут.

Зачем тут нумерик каст?
С каких это пор факторил будет вычисляться для дофигища типов чисел. Вещественные вычисления существеннее медленнее целочисленных. Тогда какой смысл нам использовать их для малых значений факториала?
Гораздо удобнее использовать наиболее широкий целочисленный тип наподобие int64 либо вообще свести к табличному поиску значений функции. Факториал - он вроде не меняется у нас на протяжении пары сотен лет.

63
25 апреля 2008 года
Zorkus
2.6K / / 04.11.2006
Цитата: hardcase
Разрабатываю на C# (в настоящий момент веб проект с самописным ORM).


Это к вопросу о неиспользовании существующих решений? Неиспользование NHiberbante, например?

Цитата:

Сколько шаблонных функций пришлось мне реализовать? Одну. Для постраничного чтения запроса в БД. В остальном кое где отражение, кое где рантаймное кодогенерирование.


Похожий опыт. 98% нужды в generic types покрывается типизированными коллекциями.

Цитата:

Зачем тут нумерик каст?
С каких это пор факторил будет вычисляться для дофигища типов чисел. Вещественные вычисления существеннее медленнее целочисленных. Тогда какой смысл нам использовать их для малых значений факториала?
Гораздо удобнее использовать наиболее широкий целочисленный тип наподобие int64 либо вообще свести к табличному поиску значений функции. Факториал - он вроде не меняется у нас на протяжении пары сотен лет.


Да чего тут обсуждать. Для нецелых чисел факториал не определен, для целых стандартых типов - настолько тривиальная функция, что и не знаю чего тут можно обсуждать. Я еще понимаю - вычисление факториала от на длинной арифметике. Но даже и в этом случае сводится к элементарным операциями умножения длинных чисел.

3
25 апреля 2008 года
Green
4.8K / / 20.01.2000
Цитата: volga
Да, спасибо, интересная статейка.
Я архитектурный астронавт? ну уж нет - это это точно не про меня :)


Не стоит все трактовать слишком буквально.
Я привел ссылку на эту статью потому, что её смысл в том, что не стоит увлекаться обобщениями и абстракциями. Нужно в первую очередь решить конкретную задачу, и очень часто этого бывает достаточно.

Цитата: volga

Почему невероятно? Я часто пишу сначала нешаблонную функцию для того, чтобы проверить алгоритм, а потом её обощаю для удобства дальнейшего использования.
Бывает полезно подумать о наиболее вероятных изменениях, которые захочется позже сделать. ИМХО, переделывать функции на шаблонные - весьма вероятное изменение.


Подумать полезно, реализовывать задуманное без необходимости - нет.

Цитата: volga

Как с numeric_cast? Ну так весь прикол в том, что практически точно также:

Код:
template<typename A, typename R>
R factorial(A arg)
{
    R f = 1;
    try{
        for (A i = 2; i <= arg; ++i)
            f = boost::numeric_cast<R>(f*i);
    }
    catch(boost::numeric::bad_numeric_cast& e)
    {
        std::cout << "Error in factorial: " << e.what() << std::endl;
        return 0;
    }

    return f;
}


Или вообще так: (если потом не лениться ловить у себя в коде исключения)

 
Код:
template<typename A, typename R>
R factorial(A arg)
{
    R f = 1;
    for (A i = 2; i <= arg; ++i)
        f = boost::numeric_cast<R>(f*i);

    return f;
}


Единственный минус этого решения я вижу в том, что клиентам этой функции прийдётся явно указывать тип возвращаемого значения.


Ну так весь прикол в том, что этот код неработоспособный. В этом же его основной минус.

Тест №1:

 
Код:
cout << factorial<int, int>(40) << endl;

Вот уже не думал, что ответом будет 0.

Тест №2:
 
Код:
cout << factorial<int, int>(33) << endl;

Ну уж точно не подумал бы, что ответом будет -2147483648.

Ты же хотел решить обобщенную задачу, не оговаривая рамок этой обобщенности, поэтому ...
Тест №3:
 
Код:
cout << factorial<float, float>(2.5f) << endl;

Ответ 2 ???
Даже google знает, что это не так:
http://www.google.ru/search?aq=-1&oq=&complete=1&hl=ru&newwindow=1&q=2.5%21
5
26 апреля 2008 года
hardcase
4.5K / / 09.08.2005
[SIZE=1]offtop[/SIZE]
Цитата: Zorkus
Это к вопросу о неиспользовании существующих решений? Неиспользование NHiberbante, например?


Просто продемонстировал, что размер проекта достаточный для оценки.
Шеф сказал без NHibernate - я организовал архитектуру без NHibernate. Неплохо получилось :) - задачу система решает в разумных масштабах. Кстати одна из фишек - интеграция вызова хранимых процедур в C#: от программиста требуется только прототип объявить.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог