为什么 for 循环对于 1 到 50 的简单乘法不能正常工作?

why for loop is not work correctly for a simple multiplication numbers 1 to 50?

代码:

#include <iostream>
using namespace std;

int main() {
  int answer = 1;
  int i = 1;
  for (; i <= 50; i++){
    answer = answer * i;
  }
  cout << answer << endl;
  
  return 0;
}

结果:

0

...Program finished with exit code 0
Press ENTER to exit console.

当我 运行 此代码在 online c++ compiler 中时, 它在控制台 中显示为零 (0)。为什么?

我会专门回答“为什么?”这个问题。而不是评论中添加的“如何?”。

你得到结果 0,因为 answer 的中间值之一是 0 并且与它相乘将保持 0。

这是中间值(我通过将您的输出移到循环中找到它们。):

1
2
6
24
120
720
5040
40320
362880
3628800
39916800
479001600
1932053504
1278945280
2004310016
2004189184
-288522240
-898433024
109641728
-2102132736
-1195114496
-522715136
862453760
-775946240
2076180480
-1853882368
1484783616
-1375731712
-1241513984
1409286144
738197504
-2147483648
-2147483648
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0

例如这里 https://www.tutorialspoint.com/compile_cpp_online.php

现在解释为什么其中一个是0开头:
由于值的原因,院系的序列很快离开了所选数据类型中可表示的值范围(请注意,小数位数在某些时候不会增加;尽管二进制数字是相关的)。
在那之后,这些值不再与正确的值真正相关,看到它们甚至跳到零以下并返回...
...其中之一恰好是 0.

对于“如何?”请查看评论(也许还有其他有价值的答案)。

简答: 您的代码无法正常工作,因为它执行 50 个阶乘,答案是 3.04*10^64。此数字大于 int 大小,即 2^31 - 1.

长答案 您可以检查记录中间答案的问题。这可以帮助您对代码情况有一些了解。在这里您可以看到数字从正数旋转到负数,这显示了此代码策略的最大可能乘法。 https://onlinegdb.com/ycnNADKmX

答案 30414093201713378043612608166064768844377641568960512000000000000

要存档任何阶乘案例的正确答案,您需要有一些策略来操作大数。 事实上,如果你在一家大公司工作,你可能有一些库来处理大量数据。在这种情况下,使用这个库来保持代码的一致性非常重要。 另一方面,假设这是一个学术作业,你可以选择互联网上的任何策略。在这种情况下,我使用了使用字符串来表示大数字的策略。您可以在此处查看解决方案 https://www.geeksforgeeks.org/multiply-large-numbers-represented-as-strings

计算50的最终程序!以正确的方式使用字符串策略来表示大数,您可以在此处找到 https://onlinegdb.com/XRL9akYKb


PS:我会把完整的答案放在这里,以存档代码以备将来参考。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;

//@see https://www.geeksforgeeks.org/multiply-large-numbers-represented-as-strings/
// Multiplies str1 and str2, and prints result.
string multiply(string num1, string num2)
{
    int len1 = num1.size();
    int len2 = num2.size();
    if (len1 == 0 || len2 == 0)
    return "0";
 
    // will keep the result number in vector
    // in reverse order
    vector<int> result(len1 + len2, 0);
 
    // Below two indexes are used to find positions
    // in result.
    int i_n1 = 0;
    int i_n2 = 0;
     
    // Go from right to left in num1
    for (int i=len1-1; i>=0; i--)
    {
        int carry = 0;
        int n1 = num1[i] - '0';
 
        // To shift position to left after every
        // multiplication of a digit in num2
        i_n2 = 0;
         
        // Go from right to left in num2            
        for (int j=len2-1; j>=0; j--)
        {
            // Take current digit of second number
            int n2 = num2[j] - '0';
 
            // Multiply with current digit of first number
            // and add result to previously stored result
            // at current position.
            int sum = n1*n2 + result[i_n1 + i_n2] + carry;
 
            // Carry for next iteration
            carry = sum/10;
 
            // Store result
            result[i_n1 + i_n2] = sum % 10;
 
            i_n2++;
        }
 
        // store carry in next cell
        if (carry > 0)
            result[i_n1 + i_n2] += carry;
 
        // To shift position to left after every
        // multiplication of a digit in num1.
        i_n1++;
    }
 
    // ignore '0's from the right
    int i = result.size() - 1;
    while (i>=0 && result[i] == 0)
    i--;
 
    // If all were '0's - means either both or
    // one of num1 or num2 were '0'
    if (i == -1)
    return "0";
 
    // generate the result string
    string s = "";
     
    while (i >= 0)
        s += std::to_string(result[i--]);
 
    return s;
}
// Calculates the factorial of an inputed number
string fact(int in) {
  string answer = "1";
  for (int i = 2 ; i <= in; i++) {
    string tmp = std::to_string(i);
    answer = multiply(answer, tmp);
  }
  return answer;
}

int main()
{
  string answer = fact(50);
  cout << answer << endl;
  return 0;
}