4

我目前正在学习预微积分,并认为我会制作一个快速程序,该程序会给我阶乘 10 的结果。在测试它时,我注意到在第 5 次迭代后我得到了不正确的结果。但是,前 4 次迭代是正确的。

public class Factorial
{
    public static void main(String[] args)
    {

        int x = 1;
        int factorial;

        for(int n = 10; n!=1; n--)
        {

            factorial = n*(n-1);
            x = x * factorial;
            System.out.printf("%d ", x);

        }

    }//end of class main
}//end of class factorial

为什么我得到负值

4

4 回答 4

9

那是一个整数溢出问题。使用longorunsigned long代替int. (正如@Dunes 建议的那样,你最好的选择是BigInteger在处理非常大的数字时,因为理论上它永远不会溢出)

基本思想是signed int 存储 之间的数字-2,147,483,648 to 2,147,483,647,存储为二进制位(计算机中的所有信息都存储为1's和0's)

正数存储0在最高有效位中,负数存储1在最高有效位中。如果您的正数在二进制表示中变得太大,则数字将转移到有符号位并将您的正数转换为负数的二进制表示。

然后,当阶乘变得比 anunsigned int可以存储的更大时,它将“环绕”并丢失其最高有效(有符号)位的结转 - 这就是为什么您会看到有时在您的输出。

于 2012-12-07T23:25:49.163 回答
7

您超出了int类型 (2,147,483,647) 的容量,因此您的结果将返回到最小值int。尝试long改用。

话虽如此,您当前使用的方法不会得出正确的答案:实际上,您当前正在计算10! ^ 2

为什么要把事情复杂化?你可以很容易地做这样的事情:

long x = 1L;

for(int n = 1; n < 10; n++)
{
    x *= n;
    System.out.println(x);
}
1
2
6
24
120
720
5040
40320
362880

它显示了连续的阶乘,直到10!达到。

此外,正如其他人所提到的,如果您需要的值大于long可以支持的值,则应该使用BigInteger支持任意精度的值。

于 2012-12-07T23:26:07.057 回答
3

您的阶乘公式不正确。你将拥有的是:

  1. 第 1 步:n*(n-1) = 10 * 9 = 90 => x = 1*90 = 90
  2. 第 2 步:n*(n-1) = 9 * 8 = 72 => x = 90*72 = 6480 或者,它应该是:10 * 9 * 8 => 720

但是错误的结果来自您达到了其他人指出的 int 类型的最大值这一事实

你的代码应该是

public class Factorial
{
    public static void main(String[] args)
    {
        double factorial = 1;

        for(int n = factorial; n>=1; n--)
        {
            factorial = factorial * n;
            System.out.printf("%d ", factorial );

        }
    }
}
于 2012-12-07T23:27:28.277 回答
2

除了其他答案提到的溢出之外,您的阶乘算法也是不正确的。10!应该计算10*9*8*7*6*5*4*3*2*1,你在做(10*9)*(9*8)*(8*7)*(7*6)*...

尝试将循环更改为以下内容:

int x = 1;
for(int n = 10; n > 1 ; n--)
{
    x = x * n;
    System.out.printf("%d ", x);
}

如果您尝试计算更高数字的阶乘,您最终会溢出,但int足够大以计算 10 的阶乘。

于 2012-12-07T23:31:36.557 回答