Por que o Java pensa que o produto de todos os números de 10 a 99 é 0?


131

O seguinte bloco de códigos fornece a saída como 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);
    }
}

Por favor, alguém pode explicar por que isso acontece?


106
Você provavelmente tem um excesso de número inteiro.
TheLostMind 15/10

68
Se você considerar os fatores principais do produto, será 2exibido cerca de 90 vezes. Isso significa que você precisará de uma variável com pelo menos 90 bits para obter uma saída diferente de zero. 32 e 64 têm menos de 90. Para calcular números inteiros maiores que as palavras nativas, você deve usar qualquer classe inteira grande que esteja disponível no idioma escolhido.
kasperd

62
Tecnicamente, este é o produto de números de 10 a 98.
AShelly

45
O que? Por que esta questão foi encerrada como duplicada de uma pergunta que está sendo encerrada como duplicada desta pergunta ?
Salman A

82
Tenho 99 problemas e 2147483648 aint 1.
glenatron

Respostas:


425

Aqui está o que o programa faz em cada etapa:

          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

Observe que em algumas etapas a multiplicação resulta em um número menor (980179200 * 18 = 463356416) ou sinal incorreto (213837312 * 20 = -18221056), indicando que houve um estouro de número inteiro. Mas de onde vem o zero? Leia.

Tendo em mente que inttipo de dados é um 32-bit assinado , dois complemento inteiro, aqui está uma explicação de cada etapa:

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. é o resultado correto
  2. é a representação interna do resultado (64 bits são usados ​​para ilustração)
  3. é o resultado representado pelo complemento de dois dos 32 bits inferiores

Sabemos que multiplicar um número por um número par:

  • desloca os bits para a esquerda e adiciona zero bits para a direita
  • resulta em um número par

Então, basicamente, seu programa multiplica um número par por outro número repetidamente, o que zera os bits do resultado começando da direita.

PS: Se as multiplicações envolverem números ímpares, o resultado não será zero.


15
A Representação Hex foi o que me ajudou a entender o que estava acontecendo aqui. Obrigado por esclarecer!

1
Sim, seria mais instrutivo se você modificasse seu programa para também imprimir os valores hexadecimais na longa lista.
Hot Licks

4
Esta resposta está correta, mas não é assim muito desordem. As últimas cinco linhas são o coração disso, e em nenhum lugar ele realmente ilustra onde exatamente isso entra em jogo. (Mas pode-se confundir-lo para fora da mesa gigante.)
Rex Kerr

6
Em outras palavras, você acumula fatores de 2. Alguns números fornecem vários fatores de 2 sozinhos, como 12, 16 e 20. Todos os fatores de 2 deslocam à direita todos os bits de todos os resultados subsequentes, deixando zeros como espaços reservados. Depois de deslocar 32 vezes à direita, você fica com apenas zero zeros de espaço reservado.
Keen

2
Um efeito semelhante também pode ser visto na base 10. Tente multiplicar qualquer série de números inteiros consecutivos, toda vez que você multiplicar por um número divisível por 10, adicione pelo menos um zero ao final do produto e é impossível remover esse zero do produto pela multiplicação de números inteiros. Em algum momento, todos os n-ésimo dígitos menos significativos serão preenchidos com zeros e se você estiver fazendo a aritmética com um módulo de 10 ** m (que tem o efeito de cortar tudo, exceto os m-ésimos dígitos menos significativos), então acabará voltando para zero. Da mesma forma com outras bases.
Lie Ryan

70

A multiplicação por computador está realmente acontecendo no módulo 2 ^ 32. Depois de acumular potências suficientes de dois no multiplicando, todos os valores serão 0.

Aqui temos todos os números pares da série, junto com a potência máxima de dois que divide o número e a potência acumulada de dois

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

O produto até 42 é igual a x * 2 ^ 32 = 0 (mod 2 ^ 32). A sequência dos poderes de dois está relacionada aos códigos de Gray (entre outras coisas) e aparece como https://oeis.org/A001511 .

EDIT: para ver por que outras respostas a esta pergunta estão incompletas, considere o fato de que o mesmo programa, restrito apenas a números ímpares, não convergiria para 0, apesar de todo o transbordamento.


Yay! Finalmente, a resposta correta. As pessoas devem notar mais esta resposta!
Rex Kerr

Esta é a única resposta correta. Todos os outros não explicam o porquê .
Olivier Grégoire

5
@ OlivierGrégoire Não concordo; Eu acho que a resposta aceita está correta e dá uma explicação perfeitamente boa. Este é apenas mais direto.
David Z

1
Espero que mais pessoas vejam essa resposta. A causa raiz é declarada aqui!
lanpa

1
@ DavidZ: Concordado; a resposta aceita está na maior parte correta - minha postagem realmente não aborda o "porquê" da minha frase de abertura. Mas perto da resposta aceita é a coisa mais próxima de uma resposta à pergunta "por que zero", mas não explica "por 42" - há apenas 16 números pares entre 10 e 42
user295691

34

Parece um estouro inteiro .

Dê uma olhada neste

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

Resultado:

25977982938941930515945176761070443325092850981258133993315252362474391176210383043658995147728530422794328291965962468114563072000000000000000000000

A saída não será mais um intvalor. Então você obterá um valor errado por causa do estouro.

Se estourar, retornará ao valor mínimo e continuará a partir daí. Se o fluxo for insuficiente, ele retornará ao valor máximo e continuará a partir daí.

Mais informação

Edit .

Vamos mudar seu código da seguinte maneira

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

Resultado:

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

É por causa do estouro inteiro. Quando você multiplica muitos números pares, o número binário recebe muitos zeros à direita. Quando você tem mais de 32 zeros à direita para um int, ele passa para 0.

Para ajudá-lo a visualizar isso, aqui estão as multiplicações em hexadecimal calculadas em um tipo de número que não transbordará. Veja como os zeros à direita crescem lentamente e observe que um inté composto dos últimos 8 dígitos hexadecimais. Após multiplicar por 42 (0x2A), todos os 32 bits de um intsão zeros!

                                     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
Isso é um pouco enganador. Embora ele demonstre corretamente por que ele chega a zero, cada valor é mantido em um int de 32 bits após a multiplicação, portanto deve ser truncado após cada etapa. A maneira como você escreveu sua resposta implica que ela não será truncada até que o loop for termine. Seria melhor se você mostrasse apenas os últimos 8 dígitos para cada etapa.
Ryno

@KamikazeScotsman Melhorei minha resposta com base em sua sugestão. Zeros menos redundantes, mais visibilidade int de 32 bits.
Tim S.

1
+1 para mostrar o valor real vs valor de 32 bits em cada estágio, destacando que o valor está sendo truncado ...
kwah

14

Em algum lugar no meio, você obtém 0o produto. Portanto, todo o seu produto será 0.

No seu caso :

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

Toda vez que você multiplica o valor atual de icom o número que você obtém 0como saída.


@KickButtowski - Multiplique os números .. Você saberá o porquê: P
TheLostMind 15/10

@KickButtowski - 0 multiplicado por qualquer outro número resultará constantemente em 0 para sempre após o estouro retornar 0 a qualquer momento.
Moose

Eu fiz, mas eu acho que você deveria ser mais informativo para que outros podem aprender também
pontapé Buttowski

@KickButtowski - atualizou a resposta. Verifique a parte OP.
TheLostMind 15/10

8
@KickButtowski: É porque o empacotamento de transbordamento acontece na potência de dois. Essencialmente, o OP está computando {10 x 11 x 12 x ... x 98} módulo 2 ^ 32. Como múltiplos de 2 aparecem muito mais de 32 vezes nesse produto, o resultado é zero.
Ruakh 15/10

12

Como muitas das respostas existentes apontam para detalhes de implementação de Java e saída de depuração, vamos dar uma olhada na matemática por trás da multiplicação binária para realmente responder ao porquê.

O comentário de @kasperd vai na direção certa. Suponha que você não se multiplique diretamente com o número, mas com os fatores primos desse número. Muitos números terão 2 como fator primordial. Em binário, isso é igual a um deslocamento para a esquerda. Pela comutatividade, podemos multiplicar os fatores primos de 2 primeiro. Isso significa que apenas fazemos um desvio à esquerda.

Ao examinar as regras de multiplicação binária, o único caso em que um 1 resultará em uma posição específica de dígito é quando ambos os valores do operando são um.

Portanto, o efeito de um deslocamento para a esquerda é que a posição de bit mais baixa de 1 ao multiplicar ainda mais o resultado é aumentada.

Como o número inteiro contém apenas os bits de ordem mais baixa, todos eles serão configurados para 0 quando o fator principal 2 for co-retido com frequência suficiente no resultado.

Observe que a representação do complemento de dois não é interessante para esta análise, pois o sinal do resultado da multiplicação pode ser calculado independentemente do número resultante. Isso significa que se o valor exceder o valor e se tornar negativo, os bits de ordem mais baixa serão representados como 1, mas durante a multiplicação, eles serão tratados novamente como sendo 0.


7

Se eu executar esse código O que eu recebo tudo -

          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

Causa de estouro de número inteiro -

980179200 * 18 =   463356416 (should be 17643225600)

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

Produzir 0 causa -

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

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

6

Eventualmente, o cálculo transborda e, eventualmente, esse transbordo leva a um produto zero; isso acontece quando product == -2147483648e i == 42. Experimente este código para verificar por si mesmo (ou execute o código aqui ):

import java.math.BigInteger;

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

Uma vez que é zero, é claro que permanece zero. Aqui está um código que produzirá um resultado mais preciso (você pode executar o código aqui ):

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);
    }
}

Estouro (no sentido preciso da palavra) bem antes da 42ª iteração - aos 19 anos já está estourado, uma vez que f (19) <f (18) #
user295691

Sim, mas o estouro não leva a ou resulta em um produto zero até a 42ª iteração.
Trevor

Acho que estou entendendo que você não aborda o "por que" - por que o produto cumulativo passaria por 0? A resposta de Tim S. dá uma indicação do porquê, mas a resposta real está na aritmética modular.
usuário295691

A pergunta não pergunta por que o produto passa por zero. Ele pergunta por que o código produz zero. Em outras palavras, acho que o OP está mais interessado na dinâmica da linguagem Java do que na aritmética modular, mas talvez eu esteja errado. Não seria a primeira vez que eu interpretava mal a pergunta de alguém.
Trevor

por exemplo, se este programa utilizasse todos os números ímpares de 11 a 99, o programa não chegaria a zero. Sua resposta não aborda realmente por que isso aconteceria.
user295691

1

É um estouro inteiro.

O tipo de dados int é 4 bytes ou 32 bits. Portanto, números maiores que 2 ^ (32 - 1) - 1 (2.147.483.647) não podem ser armazenados nesse tipo de dados. Seus valores numéricos estarão incorretos.

Para números muito grandes, convém importar e usar a classe 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());

NOTA: Para valores numéricos ainda grandes demais para o tipo de dados int, mas pequenos o suficiente para caber em 8 bytes (valor absoluto menor ou igual a 2 ^ (64 - 1) - 1), você provavelmente deve usar a longprimitiva.

Os problemas de prática do HackerRank (www.hackerrank.com), como a seção prática de algoritmos, ( https://www.hackerrank.com/domains/algorithms/warmup ) incluem algumas perguntas de grande número muito boas que fornecem boas práticas sobre como pense no tipo de dados apropriado a ser usado.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.