Почему Java считает, что произведение всех чисел от 10 до 99 равно 0?
Следующий блок кодов дает выход как 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);
}
}
Пожалуйста, объясните, почему это происходит?
Ответы
Ответ 1
Вот что делает программа на каждом шаге:
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
- - правильный результат
- - внутреннее представление результата (для иллюстрации используются 64 бита)
- - результат, представленный двумя дополнениями младших 32 бит
Мы знаем, что умножение числа на четное число:
- сдвигает биты влево и добавляет нулевые биты вправо
- приводит к четному числу
Таким образом, в основном ваша программа умножает четное число на другой номер, который нулевым образом удаляет исходные биты справа.
PS: Если умножения включают нечетные числа, тогда результат не станет равным нулю.
Ответ 2
Компьютерное умножение действительно происходит по модулю 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). Последовательность степеней 2 связана с кодами Grey (среди прочего) и выглядит как https://oeis.org/A001511.
EDIT: чтобы узнать, почему другие ответы на этот вопрос неполны, рассмотрим тот факт, что одна и та же программа, ограниченная только нечетными целыми числами, не будет сходиться к 0, несмотря на все переполнения.
Ответ 3
Он выглядит как целочисленное переполнение.
Взгляните на это
BigDecimal product=new BigDecimal(1);
for(int i=10;i<99;i++){
product=product.multiply(new BigDecimal(i));
}
System.out.println(product);
Вывод:
25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000
Выход больше не является значением int
. Тогда вы получите неправильное значение из-за переполнения.
Если он переполняется, он возвращается к минимальному значению и продолжается от там. Если он переполняется, он возвращается к максимальному значению и продолжается оттуда.
Подробнее информация
Edit.
Измените свой код следующим образом
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
Ответ 4
Это из-за целочисленного переполнения. Когда вы умножаете много четных чисел вместе, двоичное число получает много конечных нулей. Когда у вас есть более 32 конечных нулей для int
, он переходит к 0
.
Чтобы помочь вам визуализировать это, вот умножения в шестнадцатеричном формате, рассчитанные на тип номера, который не будет переполняться. Посмотрите, как медленно растут конечные нули, и обратите внимание, что 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)
Ответ 5
Где-то посередине вы получаете 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 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
в качестве вывода.
Ответ 6
Поскольку многие из существующих точек ответа на детали реализации Java и отладочного вывода позволяют взглянуть на математику за двоичным умножением, чтобы действительно ответить на вопрос почему.
Комментарий @kasperd идет в правильном направлении. Предположим, вы не размножаетесь напрямую с номером, а вместо этого с основными факторами этого числа. Чем много цифр будет иметь 2 в качестве основного фактора. В двоичном формате это равно левому сдвигу. Коммутативностью мы можем сначала умножить на простые множители 2. Это означает, что мы просто делаем сдвиг влево.
При взгляде на правила двоичного умножения единственный случай, когда 1 приведет к определенной позиции цифр, - это когда оба значения операнда равны единице.
Таким образом, эффект сдвига влево заключается в том, что младшая битовая позиция 1 при дальнейшем умножении результата увеличивается.
Так как целое число содержит только биты младшего порядка, все они будут установлены в 0, когда простой коэффициент 2 достаточно часто встречается в результате.
Обратите внимание, что для этого анализа не представляет интереса представление двух дополнительных представлений, так как знак результата умножения может быть вычислен независимо от полученного числа. Это означает, что если значение переполняется и становится отрицательным, биты младшего порядка представляются как 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
Ответ 8
В конце концов, вычисление переполняется, и в конечном итоге это переполнение приводит к нулевому продукту; это происходит, когда 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);
}
}
Ответ 9
Это переполнение целых чисел.
Тип данных 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) включают некоторые очень хорошие большие - количество вопросов, которые дают хорошую практику о том, как думать о соответствующем типе данных для использования.