Java为什么认为从10到99的所有数字的乘积为0?


131

以下代码块将输出设置为0。

public class HelloWorld{

    public static void main(String []args){
        int product = 1;
        for (int i = 10; i <= 99; i++) {
            product *= i;
        }
        System.out.println(product);
    }
}

请有人可以解释为什么会这样吗?


106
您最有可能发生整数溢出。
TheLostMind 2014年

68
如果您考虑产品中的主要因素,那么您会2出现大约90次。这意味着您将需要一个至少具有90位的变量以获取非零输出。32和64都小于90。为了计算比本地单词大的整数,您必须使用所选语言中可用的任何大整数类。
卡巴斯德(Kasperd)2014年

62
从技术上讲,这是从10到98的数字的乘积
。– AShelly

45
什么?为什么将这个问题作为一个问题的副本关闭,而将其作为这个问题的副本关闭呢?
Salman A

82
得到99个问题和2147483648 AINT 1
glenatron

Answers:


425

程序在每个步骤执行的操作如下:

          1 * 10 =          10
         10 * 11 =         110
        110 * 12 =        1320
       1320 * 13 =       17160
      17160 * 14 =      240240
     240240 * 15 =     3603600
    3603600 * 16 =    57657600
   57657600 * 17 =   980179200
  980179200 * 18 =   463356416
  463356416 * 19 =   213837312
  213837312 * 20 =   -18221056
  -18221056 * 21 =  -382642176
 -382642176 * 22 =   171806720
  171806720 * 23 =  -343412736
 -343412736 * 24 =   348028928
  348028928 * 25 =   110788608
  110788608 * 26 = -1414463488
-1414463488 * 27 =   464191488
  464191488 * 28 =   112459776
  112459776 * 29 = -1033633792
-1033633792 * 30 =  -944242688
 -944242688 * 31 =   793247744
  793247744 * 32 =  -385875968
 -385875968 * 33 =   150994944
  150994944 * 34 =   838860800
  838860800 * 35 =  -704643072
 -704643072 * 36 =   402653184
  402653184 * 37 =  2013265920
 2013265920 * 38 =  -805306368
 -805306368 * 39 = -1342177280
-1342177280 * 40 = -2147483648
-2147483648 * 41 = -2147483648
-2147483648 * 42 =           0
          0 * 43 =           0
          0 * 44 =           0
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
          0 * 97 =           0
          0 * 98 =           0

请注意,在某些步骤上,相乘会导致较小的数字(980179200 * 18 = 463356416)或错误的符号(213837312 * 20 = -18221056),表明存在整数溢出。但是零从何而来呢?继续阅读。

牢记int数据类型是签署了32位整,这里是每一个步骤的说明:

Operation         Result(1)     Binary Representation(2)                                           Result(3)
----------------  ------------  -----------------------------------------------------------------  ------------
          1 * 10            10                                                               1010            10
         10 * 11           110                                                            1101110           110
        110 * 12          1320                                                        10100101000          1320
       1320 * 13         17160                                                    100001100001000         17160
      17160 * 14        240240                                                 111010101001110000        240240
     240240 * 15       3603600                                             1101101111110010010000       3603600
    3603600 * 16      57657600                                         11011011111100100100000000      57657600
   57657600 * 17     980179200                                     111010011011000101100100000000     980179200
  980179200 * 18   17643225600                               100 00011011100111100100001000000000     463356416
  463356416 * 19    8803771904                                10 00001100101111101110011000000000     213837312
  213837312 * 20    4276746240                                   11111110111010011111100000000000     -18221056
  -18221056 * 21    -382642176  11111111111111111111111111111111 11101001001100010101100000000000    -382642176
 -382642176 * 22   -8418127872  11111111111111111111111111111110 00001010001111011001000000000000     171806720
  171806720 * 23    3951554560                                   11101011100001111111000000000000    -343412736
 -343412736 * 24   -8241905664  11111111111111111111111111111110 00010100101111101000000000000000     348028928
  348028928 * 25    8700723200                                10 00000110100110101000000000000000     110788608
  110788608 * 26    2880503808                                   10101011101100010000000000000000   -1414463488
-1414463488 * 27  -38190514176  11111111111111111111111111110111 00011011101010110000000000000000     464191488
  464191488 * 28   12997361664                                11 00000110101101000000000000000000     112459776
  112459776 * 29    3261333504                                   11000010011001000000000000000000   -1033633792
-1033633792 * 30  -31009013760  11111111111111111111111111111000 11000111101110000000000000000000    -944242688
 -944242688 * 31  -29271523328  11111111111111111111111111111001 00101111010010000000000000000000     793247744
  793247744 * 32   25383927808                               101 11101001000000000000000000000000    -385875968
 -385875968 * 33  -12733906944  11111111111111111111111111111101 00001001000000000000000000000000     150994944
  150994944 * 34    5133828096                                 1 00110010000000000000000000000000     838860800
  838860800 * 35   29360128000                               110 11010110000000000000000000000000    -704643072
 -704643072 * 36  -25367150592  11111111111111111111111111111010 00011000000000000000000000000000     402653184
  402653184 * 37   14898167808                                11 01111000000000000000000000000000    2013265920
 2013265920 * 38   76504104960                             10001 11010000000000000000000000000000    -805306368
 -805306368 * 39  -31406948352  11111111111111111111111111111000 10110000000000000000000000000000   -1342177280
-1342177280 * 40  -53687091200  11111111111111111111111111110011 10000000000000000000000000000000   -2147483648
-2147483648 * 41  -88046829568  11111111111111111111111111101011 10000000000000000000000000000000   -2147483648
-2147483648 * 42  -90194313216  11111111111111111111111111101011 00000000000000000000000000000000             0
          0 * 43             0                                                                  0             0
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
          0 * 98             0                                                                  0             0
  1. 是个 正确的结果
  2. 是结果的内部表示形式(用于说明的是64位)
  3. 是由低32位的二进制补码表示的结果

我们知道,将数字乘以偶数:

  • 向左移动位,向右添加零位
  • 结果为偶数

因此,基本上,您的程序会反复将偶数与另一个数相乘,从而从右开始将结果位清零。

PS:如果乘法仅涉及奇数,则结果将不会为零。


15
十六进制表示法帮助我了解了这里发生的事情。感谢您的澄清!

1
是的,如果您修改程序以在长列表中也打印出十六进制值,则将更具启发性。
热门点击

4
这个答案是正确的,但有这么多的混乱。最后五行是它的核心,并且没有任何地方可以真正说明它在哪里发挥了作用。(但人们可以从巨型桌子上把它弄出来。)
Rex Kerr 2014年

6
换句话说,您将因子2累加起来。某些数字本身给您多个因子2,例如12、16和20。每个因子2会将所有后续结果的所有位右移,而将零保留为占位符。右移32次后,除了32个占位符零外,您什么都没有。
Keen 2014年

2
在基数10中也可以看到类似的效果。尝试将任意系列的连续整数相乘,每次乘以可被10整除的数字,就必须在乘积的末尾至少添加一个零,并且不可能删除该零。从乘积乘以整数。在某个时候,所有第n个最低有效数字都将填充为零,并且如果您对10 ** m取模,则算术运算(这会斩除除第m个最低有效数字之外的所有内容),然后最终变成零。其他任何基地也是如此。
Lie Ryan

70

计算机乘法的确以2 ^ 32为模。一旦您在被乘数中积累了足够的2的幂,则所有值将为0。

在这里,我们拥有序列中的所有偶数,以及将数字除以2的最大乘方,以及2的累积乘方

num   max2  total
10    2     1
12    4     3
14    2     4
16    16    8
18    2     9
20    4    11
22    2    12
24    8    15
26    2    16
28    4    18
30    2    19
32    32   24
34    2    25
36    4    27
38    2    28
40    8    31
42    2    32

乘积最大为42等于x * 2 ^ 32 = 0(mod 2 ^ 32)。二者的幂序与格雷码有关(除其他外),并显示为https://oeis.org/A001511

编辑:要了解为什么对此问题的其他回答不完整,请考虑以下事实:尽管全部溢出,但仅限于奇数整数的同一程序将不会收敛为0。


好极了!最后,正确答案。人们应该更多地注意这个答案!
Rex Kerr 2014年

这是唯一正确的答案。其他人都没有解释原因
OlivierGrégoire2014年

5
@OlivierGrégoire我不同意;我认为已接受的答案是正确的,并且给出了很好的解释。这一点更直接。
David Z

1
我希望更多的人看到这个答案。根本原因在这里说明!
兰帕

1
@DavidZ:同意;可接受的答案大部分是正确的-我的帖子并没有真正解决开篇句子的“为什么”。但是,已接受的答案接近于答案“为什么为零”,但并不能解释“为什么为42”-10和42之间只有16个偶数
user295691 2014年

34

看起来像是整数溢出

看看这个

BigDecimal product=new BigDecimal(1);
for(int i=10;i<99;i++){
    product=product.multiply(new BigDecimal(i));
}
System.out.println(product);

输出:

25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000

输出不再是int值。然后,由于溢出,您将获得错误的值。

如果溢出,它将返回最小值并从那里继续。如果下溢,它将返回最大值并从那里继续。

更多资讯

编辑

让我们如下更改代码

int product = 1;
for (int i = 10; i < 99; i++) {
   product *= i;
   System.out.println(product);
}

输出:

10
110
1320
17160
240240
3603600
57657600
980179200
463356416
213837312
-18221056
-382642176
171806720
-343412736
348028928
110788608
-1414463488
464191488
112459776
-1033633792
-944242688
793247744
-385875968
150994944
838860800
-704643072
402653184
2013265920
-805306368
-1342177280
-2147483648
-2147483648>>>binary representation is 11111111111111111111111111101011 10000000000000000000000000000000 
 0 >>> here binary representation will become 11111111111111111111111111101011 00000000000000000000000000000000 
 ----
 0

22

这是因为整数溢出。当您将许多偶数相乘时,二进制数会得到很多尾随零。当您的an有超过32个尾随零时int,它将翻转为0

为了帮助您直观地看到,这里是根据不会溢出的数字类型计算的十六进制乘法。查看尾随零如何缓慢增长,并注意an int由后8个十六进制数字组成。乘以42(0x2A)后,an的所有32位int均为零!

                                     1 (int: 00000001) * 0A =
                                     A (int: 0000000A) * 0B =
                                    6E (int: 0000006E) * 0C =
                                   528 (int: 00000528) * 0D =
                                  4308 (int: 00004308) * 0E =
                                 3AA70 (int: 0003AA70) * 0F =
                                36FC90 (int: 0036FC90) * 10 =
                               36FC900 (int: 036FC900) * 11 =
                              3A6C5900 (int: 3A6C5900) * 12 =
                             41B9E4200 (int: 1B9E4200) * 13 =
                            4E0CBEE600 (int: 0CBEE600) * 14 =
                           618FEE9F800 (int: FEE9F800) * 15 =
                          800CE9315800 (int: E9315800) * 16 =
                         B011C0A3D9000 (int: 0A3D9000) * 17 =
                        FD1984EB87F000 (int: EB87F000) * 18 =
                      17BA647614BE8000 (int: 14BE8000) * 19 =
                     25133CF88069A8000 (int: 069A8000) * 1A =
                    3C3F4313D0ABB10000 (int: ABB10000) * 1B =
                   65AAC1317021BAB0000 (int: 1BAB0000) * 1C =
                  B1EAD216843B06B40000 (int: 06B40000) * 1D =
                142799CC8CFAAFC2640000 (int: C2640000) * 1E =
               25CA405F8856098C7B80000 (int: C7B80000) * 1F =
              4937DCB91826B2802F480000 (int: 2F480000) * 20 =
             926FB972304D65005E9000000 (int: E9000000) * 21 =
           12E066E7B839FA050C309000000 (int: 09000000) * 22 =
          281CDAAC677B334AB9E732000000 (int: 32000000) * 23 =
         57BF1E59225D803376A9BD6000000 (int: D6000000) * 24 =
        C56E04488D526073CAFDEA18000000 (int: 18000000) * 25 =
      1C88E69E7C6CE7F0BC56B2D578000000 (int: 78000000) * 26 =
     43C523B86782A6DBBF4DE8BAFD0000000 (int: D0000000) * 27 =
    A53087117C4E76B7A24DE747C8B0000000 (int: B0000000) * 28 =
  19CF951ABB6C428CB15C2C23375B80000000 (int: 80000000) * 29 =
 4223EE1480456A88867C311A3DDA780000000 (int: 80000000) * 2A =
AD9E50F5D0B637A6610600E4E25D7B00000000 (int: 00000000)

1
这有点误导。尽管可以正确说明为什么它会变为零,但每个值在乘法后都保留在32位int中,因此在每个步骤之后都应将其截断。您编写答案的方式意味着直到for循环终止,它才会被截断。如果您只显示每个步骤的最后8位数字,那会更好。
RyNo 2014年

@KamikazeScotsman我根据您的建议改善了答案。更少的冗余零,更多的32位int可见性。
Tim S.

1
+1用于显示每个阶段的实际值与32位值,突出显示该值已被截断...
kwah 2014年

14

您会在中间某处获得0产品。因此,您的整个产品将为0。

在您的情况下:

for (int i = 10; i < 99; i++) {
    if (product < Integer.MAX_VALUE)
        System.out.println(product);
    product *= i;
}
// System.out.println(product);

System.out.println(-2147483648 * EvenValueOfi); // --> this is the culprit (Credits : Kocko's answer )

O/P :
1
10
110
1320
17160
240240
3603600
57657600
980179200
463356416
213837312
-18221056
-382642176
171806720
-343412736
348028928
110788608
-1414463488
464191488
112459776
-1033633792
-944242688
793247744
-385875968
150994944
838860800
-704643072
402653184
2013265920
-805306368
-1342177280  --> Multiplying this and the current value of `i` will also give -2147483648 (INT overflow)
-2147483648  --> Multiplying this and the current value of `i` will also give -2147483648 (INT overflow)

-2147483648  ->  Multiplying this and the current value of 'i' will give 0 (INT overflow)
0
0
0

每次将的当前值乘以作为输出i的数字0


@KickButtowski-将数字相乘。.您会知道为什么:P
TheLostMind 2014年

@KickButtowski-0乘以任何其他数字将在溢出在任何点返回0之后永远永远为0。
穆斯先生2014年

我做到了,但我认为您应该提供更多信息,以便其他人也可以学习
Kick Buttowski

@KickButtowski-更新了答案。检查OP部分。
TheLostMind 2014年

8
@KickButtowski:这是因为溢出包装以2的幂进行。本质上,OP正在计算{10 x 11 x 12 x ... x 98}模2 ^ 32。由于2的倍数在该乘积中出现的次数超过32次,因此结果为零。
ruakh 2014年

12

由于许多现有答案都指向Java和调试输出的实现细节,因此让我们看一下二进制乘法背后的数学运算法则,可以真正回答原因。

@kasperd的评论朝着正确的方向发展。假设您没有直接与数字相乘,而是与那个数字的素数相乘。许多数字将2作为素数。在二进制中,这等于左移。通过可交换性,我们可以先乘以2的素数。这意味着我们只是左移。

查看二进制乘法规则时,唯一的1导致特定数字位置的情况是两个操作数值均为1时。

因此,左移的效果是当进一步乘以结果时1的最低位位置会增加。

由于整数仅包含最低阶位,因此当结果中的质因数2足够频繁地交织时,它们都将被设置为0。

请注意,对于本分析而言,二进制补码表示法无关紧要,因为可以独立于结果数来计算乘法结果的符号。这意味着,如果该值溢出并变为负数,则最低位表示为1,但在乘法过程中,它们再次被视为0。


7

如果我运行这段代码,我得到的一切-

          1 * 10 =          10
         10 * 11 =         110
        110 * 12 =        1320
       1320 * 13 =       17160
      17160 * 14 =      240240
     240240 * 15 =     3603600
    3603600 * 16 =    57657600
   57657600 * 17 =   980179200
  980179200 * 18 =   463356416 <- Integer Overflow (17643225600)
  463356416 * 19 =   213837312
  213837312 * 20 =   -18221056
  -18221056 * 21 =  -382642176
 -382642176 * 22 =   171806720
  171806720 * 23 =  -343412736
 -343412736 * 24 =   348028928
  348028928 * 25 =   110788608
  110788608 * 26 = -1414463488
-1414463488 * 27 =   464191488
  464191488 * 28 =   112459776
  112459776 * 29 = -1033633792
-1033633792 * 30 =  -944242688
 -944242688 * 31 =   793247744
  793247744 * 32 =  -385875968
 -385875968 * 33 =   150994944
  150994944 * 34 =   838860800
  838860800 * 35 =  -704643072
 -704643072 * 36 =   402653184
  402653184 * 37 =  2013265920
 2013265920 * 38 =  -805306368
 -805306368 * 39 = -1342177280
-1342177280 * 40 = -2147483648
-2147483648 * 41 = -2147483648
-2147483648 * 42 =           0 <- produce 0 
          0 * 43 =           0

整数溢出原因-

980179200 * 18 =   463356416 (should be 17643225600)

17643225600 : 10000011011100111100100001000000000 <-Actual
MAX_Integer :     1111111111111111111111111111111
463356416   :     0011011100111100100001000000000 <- 32 bit Integer

产生0个原因-

-2147483648 * 42 =           0 (should be -90194313216)

-90194313216: 1010100000000000000000000000000000000 <- Actual
MAX_Integer :       1111111111111111111111111111111
0           :      00000000000000000000000000000000 <- 32 bit Integer

6

最终,计算溢出,最终该溢出导致乘积为零。发生在product == -2147483648和时i == 42。尝试以下代码以自行验证(或在此处运行代码):

import java.math.BigInteger;

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        System.out.println("Result: " + (-2147483648 * 42));
    }
}

一旦为零,则当然保持为零。这是一些将产生更准确结果的代码(您可以在此处运行代码):

import java.math.BigInteger;

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        BigInteger p = BigInteger.valueOf(1);
        BigInteger start = BigInteger.valueOf(10);
        BigInteger end = BigInteger.valueOf(99);
        for(BigInteger i = start; i.compareTo(end) < 0; i = i.add(BigInteger.ONE)){
            p = p.multiply(i);
            System.out.println("p: " + p);
        }
        System.out.println("\nProduct: " + p);
    }
}

它在第42次迭代之前很早就溢出了(确切地说是单词)-在19点已经溢出了,因为f(19)<f(18)
user295691 2014年

是的,但是直到第42次迭代,溢出才会导致零或导致结果为零。
特雷弗

我想我要问的是您没有解决“为什么”的问题-为什么累积乘积会通过0?蒂姆·S。(Tim S.)的答案说明了为什么,但真正的答案在于模块化算术。
user295691

问题不问为什么乘积为零。它询问为什么代码产生零。换句话说,我认为OP对Java语言的动态性比对模块化算术更感兴趣,但也许我错了。这不是我第一次误解某人的问题。
特雷弗2014年

例如,如果该程序采用了从11到99的所有奇数的乘积,则它将不会达到零。您的答案并没有真正解决为什么会发生这种情况。
user295691

1

这是整数溢出。

int数据类型为4字节或32位。因此,大于2 ^(32-1)-1(2,147,483,647)的数字不能存储在此数据类型中。您的数值将不正确。

对于非常大的数字,您将需要导入和使用该类 java.math.BigInteger:

BigInteger product = BigInteger.ONE;
for (long i = 10; i < 99; i++) 
    product = product.multiply(BigInteger.valueOf(i));
System.out.println(product.toString());

注意:对于对于int数据类型而言仍然太大而又小到足以容纳8个字节(绝对值小于或等于2 ^(64-1)-1)的数值,您可能应该使用long原语。

HackerRank的练习问题(www.hackerrank.com),例如“算法练习”部分(https://www.hackerrank.com/domains/algorithms/warmup)包括一些非常好的大量问题,这些问题为如何实现考虑要使用的适当数据类型。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.