2012-05-10 12 views
7

Ho sperimentato con Python come begninner nelle ultime ore. Ho scritto una funzione ricorsiva, che restituisce recurse (x) come x! in Python e in Java, per confrontare i due. I due pezzi di codice sono identici, ma per qualche ragione, il Python funziona, mentre quello Java no. In Python, ho scritto:Perché questi due pezzi di codice simili producono risultati diversi?

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

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

    return num 

print recurse(x) 

Dove variabile num si moltiplica per num-1 fino a raggiungere 0, ed emette il risultato. In Java, il codice è molto simile, solo più a lungo:

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; 

} 

}

Se entro il 25, il codice Python ritorna 1.5511x10E25, che è la risposta corretta, ma il codice Java ritorna 2.076.180,48 mila, che non è la risposta corretta, e non sono sicuro del perché.

Entrambi i codici vanno circa lo stesso processo:

  • Controllare se num è pari a zero
  • Se num non è zero
    • num = num moltiplicato per la ricorsione di num - 1
  • Se num è zero
    • Restituisce 1, terminando lo stack di chiamate recurse e c ausing ogni num tornato per iniziare moltiplicando
  • ritorno num

Non ci sono staffe in pitone; Ho pensato che in qualche modo ha cambiato le cose, quindi ho rimosso le parentesi dal codice Java, ma non è cambiato. Cambiare il valore booleano (num! = 0) in (num> 0) non ha modificato nulla. L'aggiunta di un'istruzione if all'altra forniva più contesto, ma il valore era sempre lo stesso.

Stampa dei valori di num in ogni punto dà un'idea di come la funzione va storto:

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 costante aumento. In 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 

Non un aumento costante. Infatti, num restituisce numeri negativi, come se la funzione restituisse numeri negativi, anche se num non dovrebbe essere sotto zero.

Entrambi i codici Python e Java procedono con la stessa procedura, tuttavia restituiscono valori molto diversi. Perché sta succedendo?

+6

Overflow intero ... – Mysticial

+3

Python promuove da int a long automaticamente mentre java no. – jamylak

+0

Questa è una grande domanda in quanto è qualcosa in cui tutte le domande-rispondenti qui capiscono immediatamente il problema, ma è qualcosa che non si può veramente cercare a meno che non si sappia già quale sia il problema chiamato. –

risposta

11

due parole - integer overflow

Pur non esperto di pitone, che assumono può espandere le dimensioni del tipo intero secondo le sue esigenze.

In Java, tuttavia, le dimensioni di un tipo int sono fisse - a 32 bit e dal momento che è firmato int, in realtà abbiamo solo 31 bit per rappresentare i numeri positivi. Una volta che il numero che assegni è più grande del massimo, esso trabocca l'int (che è - non c'è posto per rappresentare l'intero numero).

Mentre nel linguaggio C il comportamento in questo caso è indefinito, in Java è ben definito e richiede solo 4 byte minimi del risultato.

Ad esempio:

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

risultati in:

-2147483648 
// 0x7fffffff + 1 = 0x800000000 

Modifica

solo per renderlo più chiaro, qui è un altro esempio. Il seguente codice:

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

uscite:

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 

e si può vedere che la seconda uscita è meno di 4 byte del 4 uscite

+1

Interessante. Puoi fornire un contesto? – Zolani13

+0

Seriamente, OP dichiara che lui è un principiante - dai un po 'più di dettagli qui. – kaveman

+1

@ Zolani13 - vedi modifica. – MByD

2

A differenza di Java, Python ha il supporto incorporato per long integers di precisione illimitata. In Java, un numero intero è limitato a 32 bit e sarà overflow.

1

Come già scritto, si ottiene un overflow; i numeri semplicemente non si adattano alla rappresentazione dei tipi di dati di java. Python ha una capacità incorporata di bignum su dove non ha java.

Provate alcuni valori più piccoli e vedrete che java-code funziona bene.

1

int gamma di Java

int 4 byte, firmato (complemento a due). -2.147.483.648 a 2.147.483.647. Come tutti i tipi numerici, è possibile eseguire il cast in altri tipi numerici (byte, short, long, float, double). Quando si eseguono calcoli con perdita (ad esempio int a byte) la conversione viene eseguita modulo la lunghezza del tipo più piccolo.

Qui la gamma di int è limitata

0

Il problema è molto semplice ..
coz in java il limite massimo di numero intero è 2147483647 u può stampare facendo System.out.println(Integer.MAX_VALUE); e minimo è System.out.println(Integer.MIN_VALUE);

0

Perché nella versione java si memorizza il numero come int che credo sia 32 bit. Considera il numero più grande (senza segno) che puoi memorizzare con due bit in binario: 11 che è il numero 3 in decimale. Il numero più grande che può essere memorizzato quattro bit in binario è 1111, che è il numero 15 in decimale. Un numero (firmato) a 32 bit non può archiviare nulla più grande di 2.147.483.647. Quando si tenta di memorizzare un numero più grande di questo, si riavvolge improvvisamente e inizia a contare dai numeri negativi. Questo è chiamato overflow.

Se si desidera provare a memorizzare numeri più grandi, provare a lungo.

Problemi correlati