เหตุใด 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

68
หากคุณพิจารณาปัจจัยที่สำคัญในผลิตภัณฑ์คุณจะ2แสดงประมาณ 90 ครั้ง นั่นหมายความว่าคุณจะต้องมีตัวแปรอย่างน้อย 90 บิตเพื่อให้ได้ผลลัพธ์ที่ไม่ใช่ศูนย์ 32 และ 64 มีค่าน้อยกว่า 90 ในการคำนวณจำนวนเต็มที่มีขนาดใหญ่กว่าคำพื้นเมืองคุณต้องใช้คลาสจำนวนเต็มขนาดใหญ่ที่มีอยู่ในภาษาที่คุณเลือก
kasperd

62
ในทางเทคนิคนี่คือผลคูณของตัวเลขตั้งแต่ 10 ถึง 98
AShelly

45
อะไร? ทำไมคำถามนี้ปิดเป็นซ้ำของคำถามที่ซึ่งจะถูกปิดเป็นซ้ำของนี้คำถาม ?
Salman A

82
มีปัญหา 99 รายการและ 2147483648 aint 1.
glenatron

คำตอบ:


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
ใช่มันจะให้คำแนะนำมากกว่านี้ถ้าคุณแก้ไขโปรแกรมของคุณเพื่อพิมพ์ค่าฐานสิบหกในรายการแบบยาว
Hot Licks

4
คำตอบนี้ถูกต้อง แต่มีเพื่อความยุ่งเหยิงมาก ห้าบรรทัดสุดท้ายคือหัวใจของมันและไม่มีที่ไหนเลยที่จะแสดงให้เห็นว่ามันเข้ามามีบทบาทอย่างไร (แต่มีใครไขปริศนาออกจากโต๊ะยักษ์ได้)
Rex Kerr

6
อีกวิธีหนึ่งคือคุณสะสมตัวประกอบของ 2 ตัวเลขบางตัวให้ตัวประกอบของ 2 ทั้งหมดด้วยตัวมันเองเช่น 12, 16 และ 20 ทุกตัวประกอบของ 2 จะเลื่อนบิตทั้งหมดของผลลัพธ์ที่ตามมาทั้งหมดของคุณไปทางขวาโดยปล่อยให้ศูนย์เป็น ตัวยึดตำแหน่ง เมื่อคุณเลื่อนไปทางขวา 32 ครั้งคุณจะไม่เหลืออะไรเลยนอกจากศูนย์ตัวยึด 32 ตำแหน่ง
Keen

2
ผลที่คล้ายกันนี้ยังสามารถเห็นได้ในฐาน 10 ลองคูณอนุกรมของจำนวนเต็มติดต่อกันทุกครั้งที่คุณคูณด้วยจำนวนที่หารด้วย 10 คุณจะต้องเพิ่มศูนย์อย่างน้อยหนึ่งศูนย์ที่ส่วนท้ายของผลคูณและเป็นไปไม่ได้ที่จะลบศูนย์นั้นออก จากผลคูณด้วยการคูณจำนวนเต็ม ในบางจุดตัวเลขที่มีนัยสำคัญน้อยที่สุด n-th ทั้งหมดจะเต็มไปด้วยศูนย์และหากคุณกำลังคำนวณเลขคณิตเป็นโมดูโล 10 ** ม. (ซึ่งมีผลในการตัดทอนทุกอย่างยกเว้นเลขนัยสำคัญน้อยที่สุด m) แล้วมันจะกลายเป็นศูนย์ เช่นเดียวกันกับฐานอื่น ๆ
Lie Ryan

70

การคูณคอมพิวเตอร์กำลังเกิดขึ้นจริง ๆ โมดูโล 2 ^ 32 เมื่อคุณสะสมพลังของสองในตัวคูณได้เพียงพอแล้วค่าทั้งหมดจะเป็น 0

ที่นี่เรามีเลขคู่ทั้งหมดในอนุกรมพร้อมกับกำลังสูงสุดของสองที่หารจำนวนและกำลังสะสมของสอง

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

นี่เป็นคำตอบเดียวที่ถูกต้อง คนอื่น ๆ ไม่ได้อธิบายว่าทำไม
Olivier Grégoire

5
@ OlivierGrégoireฉันไม่เห็นด้วย; ฉันคิดว่าคำตอบที่ยอมรับนั้นถูกต้องและให้คำอธิบายที่ดีอย่างสมบูรณ์แบบ อันนี้ตรงกว่า
David Z

1
ฉันหวังว่าจะมีคนเห็นคำตอบนี้มากขึ้น สาเหตุที่แท้จริงระบุไว้ที่นี่!
lanpa

1
@DavidZ: เห็นด้วย; คำตอบที่ได้รับการยอมรับส่วนใหญ่ถูกต้อง - โพสต์ของฉันไม่ได้กล่าวถึง "ทำไม" ของประโยคเริ่มต้นของฉัน แต่คำตอบที่ได้รับการยอมรับคือสิ่งที่ใกล้เคียงที่สุดสำหรับคำตอบที่ว่า "ทำไมเป็นศูนย์" แต่ไม่ได้อธิบายว่า "ทำไมต้อง 42" - มีเพียง 16 เลขคู่ระหว่าง 10 ถึง 42
user295691

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

เป็นเพราะจำนวนเต็มล้น เมื่อคุณคูณเลขคู่จำนวนมากเข้าด้วยกันเลขฐานสองจะได้ศูนย์ต่อท้ายจำนวนมาก เมื่อคุณมีกว่า 32 เลขท้ายสำหรับมันม้วนมากกว่าที่จะint0

เพื่อช่วยให้คุณเห็นภาพสิ่งนี้นี่คือการคูณในฐานสิบหกที่คำนวณจากประเภทตัวเลขที่จะไม่ล้น ดูว่าศูนย์ต่อท้ายค่อยๆโตขึ้นอย่างไรและสังเกตว่าintเลขฐานสิบหกประกอบด้วย 8 หลักสุดท้าย หลังจากคูณด้วย 42 (0x2A) แล้ว 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
นี่เป็นเรื่องเล็กน้อยที่ทำให้เข้าใจผิด แม้ว่าจะแสดงให้เห็นอย่างถูกต้องว่าเหตุใดจึงไปที่ศูนย์ แต่แต่ละค่าจะอยู่ใน int 32 บิตหลังการคูณดังนั้นจึงควรถูกตัดทอนหลังจากแต่ละขั้นตอน วิธีที่คุณเขียนคำตอบหมายความว่าคำตอบนั้นจะไม่ถูกตัดทอนจนกว่า for loop จะสิ้นสุดลง จะดีกว่าถ้าคุณแสดงเฉพาะตัวเลข 8 หลักสุดท้ายสำหรับแต่ละขั้นตอน
RyNo

@KamikazeScotsman ฉันปรับปรุงคำตอบตามคำแนะนำของคุณ ศูนย์ที่ซ้ำซ้อนน้อยลงการมองเห็น int 32 บิตมากขึ้น
Tim S.

1
+1 สำหรับการแสดงค่าจริงเทียบกับค่า 32 บิตในแต่ละขั้นตอนโดยเน้นว่าค่ากำลังถูกตัดทอน ...
กิโลวัตต์

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

@KickButtowski - 0 คูณด้วยจำนวนอื่นจะส่งผลให้เป็น 0 ตลอดไปหลังจากที่โอเวอร์โฟลว์ส่งกลับ 0 ณ จุดใดก็ได้
Mr Moose

ฉันได้ แต่ฉันคิดว่าคุณควรจะให้ข้อมูลเพิ่มเติมเพื่อให้สามารถเรียนรู้อื่น ๆ เกินไป
เตะ Buttowski

@KickButtowski - อัปเดตคำตอบ ตรวจสอบส่วน OP
TheLostMind

8
@KickButtowski: เป็นเพราะการห่อล้นเกิดขึ้นด้วยกำลังสอง โดยพื้นฐานแล้ว OP จะคำนวณ {10 x 11 x 12 x ... x 98} โมดูโล 2 ^ 32 เนื่องจากผลคูณของ 2 ปรากฏมากกว่า 32 ครั้งในผลิตภัณฑ์นั้นผลลัพธ์จึงเป็นศูนย์
ruakh

12

เนื่องจากคำตอบที่มีอยู่จำนวนมากชี้ไปที่รายละเอียดการใช้งาน Java และเอาต์พุตการดีบักเรามาดูคณิตศาสตร์ที่อยู่เบื้องหลังการคูณไบนารีเพื่อตอบคำถามว่าทำไม

ความคิดเห็นของ @kasperd ไปในทิศทางที่ถูกต้อง สมมติว่าคุณไม่ได้คูณด้วยจำนวนโดยตรง แต่ใช้ตัวประกอบเฉพาะของจำนวนนั้นแทน กว่าจำนวนมากจะมี 2 เป็นปัจจัยเฉพาะ ในไบนารีจะเท่ากับกะซ้าย โดยการสับเปลี่ยนเราสามารถคูณด้วยปัจจัยเฉพาะของ 2 ตัวแรก นั่นหมายความว่าเราแค่เลื่อนซ้าย

เมื่อดูกฎการคูณไบนารีกรณีเดียวที่ 1 จะส่งผลให้เกิดตำแหน่งหลักเฉพาะคือเมื่อค่าตัวถูกดำเนินการทั้งสองเป็นหนึ่ง

ดังนั้นผลของการเลื่อนไปทางซ้ายคือตำแหน่งบิตต่ำสุดของ 1 เมื่อคูณผลลัพธ์เพิ่มเติมจะเพิ่มขึ้น

เนื่องจากจำนวนเต็มมีเพียงบิตลำดับที่ต่ำที่สุดพวกเขาทั้งหมดจะถูกตั้งค่าเป็น 0 เมื่อตัวประกอบเฉพาะ 2 ถูก cotnained บ่อยพอในผลลัพธ์

โปรดทราบว่าการแสดงส่วนเสริมของสองไม่น่าสนใจสำหรับการวิเคราะห์นี้เนื่องจากเครื่องหมายของผลลัพธ์การคูณสามารถคำนวณได้โดยไม่ขึ้นกับจำนวนผลลัพธ์ นั่นหมายความว่าถ้าค่าล้นและกลายเป็นลบบิตลำดับต่ำสุดจะแสดงเป็น 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

ใช่ แต่โอเวอร์โฟลว์ไม่ได้นำไปสู่หรือส่งผลให้เกิดผลคูณเป็นศูนย์จนกว่าจะถึงการวนซ้ำครั้งที่ 42
Trevor

ฉันเดาว่าสิ่งที่ฉันได้รับคือคุณไม่ได้ระบุว่า "ทำไม" - ทำไมผลิตภัณฑ์สะสมถึงต้องผ่าน 0? คำตอบของ Tim S. ให้ข้อบ่งชี้บางประการ แต่คำตอบที่แท้จริงอยู่ในเลขคณิตแบบแยกส่วน
user295691

คำถามไม่ได้ถามว่าทำไมสินค้าถึงผ่านศูนย์ มันถามว่าทำไมรหัสถึงสร้างศูนย์ กล่าวอีกนัยหนึ่งฉันคิดว่า OP สนใจพลวัตของภาษา Java มากกว่าการคำนวณแบบแยกส่วน แต่ฉันคิดผิด คงไม่ใช่ครั้งแรกที่ฉันตีความคำถามของใครบางคนผิด
Trevor

ตัวอย่างเช่นหากโปรแกรมนี้นำผลคูณของจำนวนคี่ทั้งหมดจาก 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 ) รวมคำถามจำนวนมากที่ดีมากซึ่งให้แนวทางปฏิบัติที่ดีเกี่ยวกับวิธีการ คิดถึงประเภทข้อมูลที่เหมาะสมที่จะใช้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.