2012-05-10 14 views
7

He estado experimentando con Python como un begninner en las últimas horas. Escribí una función recursiva, que devuelve recurse (x) como x! en Python y en Java, para comparar los dos. Los dos pedazos de código son idénticos, pero por alguna razón, el de Python funciona, mientras que el de Java no. En Python, escribí:¿Por qué estos dos pedazos de código similares producen resultados diferentes?

x = int(raw_input("Enter: ")) 

def recurse(num): 
    if num != 0: 
     num = num * recurse(num-1) 
    else: 
     return 1 

    return num 

print recurse(x) 

Donde la variable num se multiplica por num-1 hasta llegar a 0, y muestra el resultado. En Java, el código es muy similar, sólo que más largo:

public class Default { 
    static Scanner input = new Scanner(System.in); 
    public static void main(String[] args){ 

      System.out.print("Enter: "); 
      int x = input.nextInt(); 
      System.out.print(recurse(x)); 


} 

    public static int recurse(int num){ 

    if(num != 0){ 
    num = num * recurse(num - 1); 
    } else { 
     return 1; 
    } 

    return num; 

} 

}

Si entro en el 25, el Código Python vuelve 1.5511x10E25, que es la respuesta correcta, pero el código de Java vuelve 2076180480, el cual no es la respuesta correcta, y no estoy seguro de por qué.

Ambos códigos van sobre el mismo proceso:

  • Comprobar si num es cero
  • Si num no es cero
    • num = num multiplicado por la recursividad de num - 1
  • Si num es cero
    • Devuelve 1, terminando esa pila de llamadas recurrentes, y c ausing cada num vuelto a comenzar a multiplicarse
  • retorno num

No hay paréntesis en pitón; Pensé que de alguna manera había cambiado las cosas, así que quité los corchetes del código de Java, pero no cambió. Cambiar el booleano (num! = 0) a (num> 0) tampoco cambió nada. Agregar una instrucción if al else proporcionó más contexto, pero el valor seguía siendo el mismo.

Impresión de los valores de num en cada punto da una idea de cómo la función va mal:

Python:

1 
2 
6 
24 
120 
720 
5040 
40320 
362880 
3628800 
39916800 
479001600 
6227020800 
87178291200 
1307674368000 
20922789888000 
355687428096000 
6402373705728000 
121645100408832000 
2432902008176640000 
51090942171709440000 
1124000727777607680000 
25852016738884976640000 
620448401733239439360000 
15511210043330985984000000 
15511210043330985984000000 

Un aumento constante. En Java:

1 
2 
6 
24 
120 
720 
5040 
40320 
362880 
3628800 
39916800 
479001600 
1932053504 
1278945280 
2004310016 
2004189184 
-288522240 
-898433024 
109641728 
-2102132736 
-1195114496 
-522715136 
862453760 
-775946240 
2076180480 
2076180480 

No se produce un aumento constante. De hecho, num devuelve números negativos, como si la función devolviera números negativos, aunque num no debería estar por debajo de cero.

Tanto los códigos de Python como los de Java están siguiendo el mismo procedimiento, sin embargo, están devolviendo valores muy diferentes. ¿Por qué está pasando esto?

+6

Desbordamiento de enteros ... – Mysticial

+3

Python promueve de int a long automáticamente mientras java no. – jamylak

+0

Esta es una gran pregunta, ya que es algo en que todos los que responden preguntas de inmediato comprenden el problema, pero es algo que no puedes buscar a menos que ya sepas cómo se llama el problema. –

Respuesta

11

dos palabras - desbordamiento de entero

Aunque no es un experto en Python, que supongo que puede ampliar el tamaño del tipo entero de acuerdo a sus necesidades.

En Java, sin embargo, el tamaño de un tipo int es fijo - 32 bits, y dado que int está firmado, en realidad solo tenemos 31 bits para representar números positivos. Una vez que el número que asigna es más grande que el máximo, desborda el int (que es - no hay lugar para representar el número entero).

Mientras que en el lenguaje C el comportamiento en tal caso no está definido, en Java está bien definido, y solo toma los 4 bytes como mínimo del resultado.

Por ejemplo:

System.out.println(Integer.MAX_VALUE + 1); 
// Integer.MAX_VALUE = 0x7fffffff 

resultados en:

-2147483648 
// 0x7fffffff + 1 = 0x800000000 

Editar

Sólo para que quede más claro, aquí es otro ejemplo. El siguiente código:

int a = 0x12345678; 
int b = 0x12345678; 
System.out.println("a*b as int multiplication (overflown) [DECIMAL]: " + (a*b)); 
System.out.println("a*b as int multiplication (overflown) [HEX]: 0x" + Integer.toHexString(a*b)); 
System.out.println("a*b as long multiplication (overflown) [DECIMAL]: " + ((long)a*b)); 
System.out.println("a*b as long multiplication (overflown) [HEX]: 0x" + Long.toHexString((long)a*b)); 

salidas:

a*b as int multiplication (overflown) [DECIMAL]: 502585408 
a*b as int multiplication (overflown) [HEX]: 0x1df4d840 
a*b as long multiplication (overflown) [DECIMAL]: 93281312872650816 
a*b as long multiplication (overflown) [HEX]: 0x14b66dc1df4d840 

y se puede ver que la segunda salida es los 4 bytes menos del 4 de salida

+1

Interesante. ¿Puedes proporcionar contexto? – Zolani13

+0

Hablando en serio, OP dice que es un principiante; da un poco más de detalle aquí. – kaveman

+1

@ Zolani13 - ver edición. – MByD

2

diferencia de Java, Python ha incorporado en el soporte para long integers de precisión ilimitada. En Java, un número entero está limitado a 32 bits y será overflow.

1

Como ya escribieron otros, obtiene desbordamiento; los números simplemente no caben dentro de la representación del tipo de datos de Java. Python tiene una capacidad incorporada de bignum para saber dónde java no.

Pruebe con algunos valores más pequeños y verá que java-code funciona bien.

1

de Java gama int

int 4 bytes, con signo (complemento a dos). -2,147,483,648 a 2,147,483,647. Como todos los tipos numéricos, los elementos pueden ser convertidos en otros tipos numéricos (byte, corto, largo, flotante, doble). Cuando se realizan conversiones con pérdidas (por ejemplo, int a byte), la conversión se realiza a la longitud del tipo más pequeño.

Aquí la gama de int es limitada

0

El problema es muy simple ..
coz en java el límite máximo de número entero es 2147483647 u puede imprimirlo por System.out.println(Integer.MAX_VALUE); y el mínimo es System.out.println(Integer.MIN_VALUE);

0

Debido en la versión java, almacena el número como int, que creo que es de 32 bits. Considere el número más grande (sin firmar) que puede almacenar con dos bits en binario: 11, que es el número 3 en decimal. El número más grande que puede almacenarse en cuatro bits en binario es 1111, que es el número 15 en decimal. Un número de 32 bits (firmado) no puede almacenar nada más grande que 2,147,483,647. Cuando intentas almacenar un número más grande que este, de repente se envuelve y comienza a contar desde los números negativos. Esto se llama desbordamiento.

Si quiere intentar almacenar números más grandes, intente de largo.

Cuestiones relacionadas