Почему 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);
}
}
пожалуйста, может кто-нибудь объяснить, почему это происходит?
9 ответов:
вот что программа делает на каждом шаге:
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^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.
EDIT: чтобы понять, почему другие ответы на этот вопрос являются неполными, рассмотрим тот факт, что одна и та же программа, ограниченная только нечетными целыми числами, будет не сходятся к 0, несмотря на все переполнены.
похоже переполнение целого числа.
взгляните на это
BigDecimal product=new BigDecimal(1); for(int i=10;i<99;i++){ product=product.multiply(new BigDecimal(i)); } System.out.println(product);
выход:
25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000
выход больше не будет
int
значение. Тогда вы получите неправильное значение из-за переполнения.если он переполняется, он возвращается к минимальному значению и продолжается с там. Если он переполняется, он возвращается к максимальному значению и продолжается оттуда.
больше info
Edit.
Давайте изменим код следующим образом
int product = 1; for (int i = 10; i < 99; i++) { product *= i; System.out.println(product); }
Out put:
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
Это из-за переполнения целого числа. Когда вы умножаете много четных чисел вместе, двоичное число получает много конечных нулей. Когда у вас есть более 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)
где-то посередине вы получите
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
в качестве выходного.
поскольку многие из существующих ответов указывают на детали реализации Java и отладочного вывода, давайте посмотрим на математику за двоичным умножением, чтобы действительно ответить на вопрос "почему".
комментарий @kasperd идет в правильном направлении. Предположим, что вы не умножаете непосредственно на число,а на простые множители этого числа. Чем много чисел будет иметь 2 в качестве простого множителя. В двоичном формате это равно сдвигу влево. По коммутативности мы можем умножить на простое число факторы 2-го. Это значит, что мы просто делаем сдвиг влево.
когда вы смотрите на правила двоичного умножения, единственный случай, когда 1 приведет к определенной позиции цифры, - это когда оба значения операнда равны одному.
таким образом, эффект сдвига влево заключается в том, что самая низкая позиция бита 1 при дальнейшем умножении результата увеличивается.
Так как целое число содержит только биты самого низкого порядка, все они будут установлены в 0, когда простой фактор 2 часто привязан достаточно в результате.
обратите внимание, что представление дополнения до двух, не представляет интереса для анализа, так как знак результата умножения может быть вычислено независимо от полученного числа. Это означает, что если значение переполняется и становится отрицательным, биты самого низкого порядка представляются как 1, но во время умножения они снова обрабатываются как 0.
Если я запускаю этот код, что я вам всего -
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
В конце концов, расчет переполняется, и в конечном итоге это переполнение приводит к нулевому произведению; это происходит, когда
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); } }
Это целочисленное переполнение.
тип данных 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
примитивно.проблемы практики Хакерранка (www.hackerrank.com), такие как раздел практики алгоритмов, (https://www.hackerrank.com/domains/algorithms/warmup) включите несколько очень хороших вопросов большого числа, которые дают хорошую практику о том, как думать о соответствующем типе данных для использования.