2015-07-27 3 views
2

как домашняя работа Мне нужна программа, которая читает неотрицательное целое число и вычисляет и печатает его факториал. Пока я написал код, но если попытаюсь ввести 50! результат равен 0. Он работает с меньшими числами. Любая помощь приветствуется.Простая C++ факторная программа

#include <iostream> 

using namespace std; 

int main() 
{ 
    int counter = 1; 
    int number; 

    cout << "Please enter a number: "; 
    cin >> number; 

    int factorial = number; 
    while (counter != number) 
    { 
     factorial = factorial * (number - counter); 
     counter++; 

    } 

    cout << "The factorial of " << number << "! is: " << factorial << endl; 
    return 0; 
} 
+2

Какой * должен * результат быть для '50'? Какое наибольшее число, в котором ваша домашняя работа должна быть способна вычислять факториал? –

+1

Максимальное значение 'int' - [' INT_MAX'] (http://en.cppreference.com/w/cpp/types/climits), которое обычно составляет немногим более двух миллиардов (для систем с 32-разрядной ' int', который почти всех нормальных систем). –

+0

В нем не указано определенное число. Я должен использовать операторы while и тип переменных, которые я изучил до сих пор: int, double/float или bool. – im2shae

ответ

9

50! является 30414093201713378043612608166064768844377641568960512000000000000, слишком велик для междунар. Из-за целочисленного переполнения результат равен 0.

+3

Из-за целочисленного переполнения ... и того факта, что 50! делится на 2^32. – Barry

+0

Я так и думал. Благодарю вас за разъяснение. Я узнал только типы int, float или bool. будет ли он работать лучше с переменной double/float? – im2shae

+2

@ im2shae Обратите внимание, что 50! намного больше, чем даже беззнаковое долгое время, я бы рекомендовал класс BigInteger, если вам нужна точность. – yizzlez

4

Если вы хотите вычислить большие факториалы, вам нужно использовать класс BigInteger. Посмотрите на: Thread

+0

Спасибо, но я еще не знаком с классами. – im2shae

+0

Если вы хотите использовать C++, я рекомендую вам ознакомиться с ними как можно быстрее. Тем временем вы можете написать свою собственную функцию, которая будет обрабатывать большие числа. – gandgandi

0

Попробуйте использовать двойные или длинные типы данных в классе или структуре. Вы также должны соответствующим образом изменить свой код.

+1

Двойной, очевидно, слишком маленький. Используйте некоторые пунктуации при написании ответов. – gandgandi

+0

Извините за мой английский. yes double is to small Я думаю, что предпочтительнее использовать класс или структуру с несколькими длинными длинными типами данных и модифицировать код соответственно –

1

Выберите тип данных большего диапазона, который не будет превышать значение, сохраненное в переменной «факторного»

Вы должны объявить его как, **long long int factorial = number ;**

Теперь он показывает ноль, потому что Int (здесь подпись) поэтому он имеет диапазон от -32568 до +32567 для системы, которая сохраняет тип данных int как 2 байта. И с помощью модификатора «long long» вы фактически увеличиваете свои байты хранения до 8 байтов, что приводит к большему диапазону.

Теперь, если значение, которое должно храниться в любой переменной, превышает свой диапазон, то оно выполняет циклическое вращение, начиная значение, которое должно храниться с наименьшего диапазона (здесь это -32568).

И вы также можете использовать **unsigned long long int factorial = number ;**, чтобы сделать его гораздо большим. Поскольку unsigned будет считать отрицательный диапазон с положительным диапазоном, который приводит к значительно большему положительному диапазону.

2

Есть уже некоторые ответы. Тем не менее, им не хватает какого-либо важного факта (imho):

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

На обычных карманных калькуляторах 69! это самый большой фактор, который они могут отображать (потому что он самый большой с показателем двух цифр). Просить чего-нибудь большего просто приведет к ошибке или NaN. На самом деле это прекрасно, потому что на практике вам редко нужны такие огромные факториалы с совершенной точностью. Часто можно использовать аппликацию Стирлинга или использовать другие трюки, чтобы избежать длительных вычислений (btw 69! Также является хорошим эталоном для карманных калькуляторов, потому что он может занять до нескольких секунд на более медленных).

Заключение: Ваш код отлично подходит для разумного ввода. Если вам действительно нужно идти на более высокие факториалы, есть способы, но я полагаю, что ваше задание действительно не просит об этом. Более того, независимо от того, как вы это делаете, вы всегда попадаете в лимит. Таким образом, чтобы сделать ваш код «без ошибок», я бы добавил что-то вроде

assert(number < 50 && "Sorry, this number is too big"); 

перед расчетом.

+1

+1, но 50 - довольно магическое число и не переносимо, поскольку размер 'int' варьируется между различными системами. Я предполагаю, что математически склонный может вызывать вызов портативного утверждения с помощью 'std :: numeric_limits'. –

+0

@ChristianHackl yep, конечно. Я почему-то «оставил это для заинтересованного читателя» заменить «50» чем-то более значимым. Лучшая магия, чем сломанная: P – user463035818

0

Факториал просто производит безумно большие цифры. Вы можете попробовать с более широкими или, возможно, более широкими типами данных (например, long), но это только отложит проблему. Это будет сбой в некоторой точке. Возможно, в 51!, возможно, в 60!.И давайте даже не будем говорить о 1000!. Такова природа факториала.

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

Что вы, , можете очень хорошо, однако, это безопасно, если ваша программа достигает предела вашего компьютера и печатает сообщение об ошибке, если это так. C++ предоставляет механизм, называемый std::numeric_limits, который сообщает вам самое большое возможное значение, которое может представлять тип данных.

Вот простой пример, основанный на коде:

#include <iostream> 
#include <limits> // needed for std::numeric_limits 

using namespace std; 

int main() 
{ 
    int counter = 1; 
    int number; 

    cout << "Please enter a number: "; 
    cin >> number; 

    int factorial = number; 
    while (counter != number) 
    { 
     if (std::numeric_limits<int>::max()/factorial < (number - counter)) { 
      std::cout << "cannot handle such large numbers\n"; 
      return 0; 
     }  
     factorial = factorial * (number - counter); 
     counter++; 

    } 

    cout << "The factorial of " << number << "! is: " << factorial << endl; 
    return 0; 
} 

Что произойдет, когда было обнаружено условие ошибки здесь не важно, а как вы обнаружить:

std::numeric_limits<int>::max()/factorial < (number - counter) 

Это предотвращает переполнение целых чисел. Это математически эквивалентно:

std::numeric_limits<int>::max() < factorial * (number - counter) // wrong! 

Однако, последняя версия, очевидно, не работает, потому что factorial * (number - counter) уже может производить переполнение. Поворотом умножения справа на деление слева, вы изящно избегаете проблемы.


Кстати, все это все равно не поможет, если пользователь вводит очень большое число. Поэтому вы должны проверить состояние std::cin перед использованием number, а также распечатать сообщение об ошибке, если вход не может быть интерпретирован как int. Это делает вашу программу более надежной. Он не будет просто терпеть крах или давать бессмысленные результаты, если кто-то войдет в большие числа.

Смежные вопросы