2015-01-07 22 views
9

Considerare questi due casi:Perché questi due float64 hanno valori diversi?

fmt.Println(912 * 0.01) 
fmt.Println(float64(912) * 0.01) 

(Go Playground link)

la seconda stampe 9.120000000000001, che in realtà è bene, I understand why that is happening.

Tuttavia, perché la prima riga stampa 9.12, senza il ... 01 alla fine? Go moltiplicare le due costanti non tipizzate e semplicemente sostituirle con un letterale 9.12 durante la compilazione?

+0

possibile duplicato di [La matematica in virgola mobile è rotta?] (Http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – asawyer

+1

@asawyer Non proprio. OP si sta chiedendo perché questi due producono risultati diversi, non perché uno dei risultati non è esattamente 9.12. – fuz

risposta

14

come da spec:

Le espressioni costanti vengono sempre valutate esattamente; valori intermedi e le costanti stesse possono richiedere precisione significativamente maggiore di quella supportata da qualsiasi tipo predetto nella lingua.

Da

912 * 0.01 

è un'espressione costante, viene calcolata esattamente. Pertanto, scrivere fmt.Println(912 * 0.01) ha lo stesso effetto della scrittura fmt.Println(9.12). Quando si preme 912 su float64, anche l'altro operando della moltiplicazione in virgola mobile viene bloccato implicitamente su float64. Pertanto, l'espressione float64(912) * 0.01 si comporta come float64(912) * float64(0.01). 0,01 non è esattamente rappresentabile in un float64, quindi la precisione viene persa in un posto diverso rispetto all'espressione float64(912 * 0.01) che si pone nell'argomento di fmt.Println() nel primo esempio, che spiega i diversi risultati.

6

La ragione per la diversa uscita è che nel primo caso 912 * 0.01 è la moltiplicazione di 2 valori costanti senza tipo che è di precisione arbitraria, e solo il risultato viene convertito float64 quando il valore viene passato a Println(). (Vedere Constant expressions sezione della specifica lingua per i dettagli.)

Nel secondo caso float64(912) * 0.01 primo 912 viene convertito in float64, quindi la costante non tipizzata 0.01 viene convertito in float64 e questi due valori essendo float64 vengono moltiplicati che non è arbitraria precisione, e non darà risultati esatti.

Nota:

Nel primo caso il risultato sarà convertita float64 quando passata alla Println():

fmt.Printf("%T %v\n", 912 * 0.01, 912 * 0.01) 

uscita:

float64 9.12 

Test it on Go Playground

+0

"Nel primo caso il risultato sarà convertito in' float64' quando viene passato a 'Println()' "- si intende il risultato di moltiplicare due costanti non tipizzate, giusto? –

+0

@AttilaO. Sì, il risultato della moltiplicazione. Quando viene passato alla funzione 'Println()', deve essere convertito in un valore digitato. Anche modificato per aggiungere codice per mostrare il tipo del risultato. – icza