考慮以下兩種情況:爲什麼這兩個float64具有不同的值?
fmt.Println(912 * 0.01)
fmt.Println(float64(912) * 0.01)
第二個打印9.120000000000001,這實際上是細,I understand why that is happening。
但是,爲什麼第一行打印9.12,最後沒有... 01? Go是否會乘以兩個無類型常量,並且在編譯時用9.12字面替換它們?
考慮以下兩種情況:爲什麼這兩個float64具有不同的值?
fmt.Println(912 * 0.01)
fmt.Println(float64(912) * 0.01)
第二個打印9.120000000000001,這實際上是細,I understand why that is happening。
但是,爲什麼第一行打印9.12,最後沒有... 01? Go是否會乘以兩個無類型常量,並且在編譯時用9.12字面替換它們?
根據spec:
常量表達式總是精確計算;中間值和常量本身的精度可能要比語言中任何預先聲明的類型支持的精度要大得多。
由於
912 * 0.01
是常量表達式,它被精確地進行評價。因此,編寫fmt.Println(912 * 0.01)
與編寫fmt.Println(9.12)
具有相同的效果。當您將912
鎖定爲float64
時,浮點乘法的另一個操作數也隱含固定爲float64
。因此,表達式float64(912) * 0.01
的行爲如同float64(912) * float64(0.01)
。 0.01在float64
中不能完全表示,因此在第一個示例中的fmt.Println()
參數中出現的表達式float64(912 * 0.01)
中的精度會丟失,這說明了不同的結果。
不同輸出的原因是,在第一種情況下,912 * 0.01
是2個任意精度的無類型常量值的乘積,只有在將值傳遞給Println()
時,結果才轉換爲float64
。 (詳情請參見語言規範的Constant expressions部分。)
在第二種情況下float64(912) * 0.01
第一912
轉換爲float64
,那麼無類型的恆定0.01
被轉換爲float64
和具有float64
相乘這兩個值是不是任意的精確度,並不會給出確切的結果。
注:
在第一種情況傳遞給Println()
當結果將被轉換爲float64
:
fmt.Printf("%T %v\n", 912 * 0.01, 912 * 0.01)
輸出:
float64 9.12
「在第一種情況下,結果將傳遞給'Println()''時轉換爲'float64'」 - 您的意思是將兩個無類型常量相乘的結果,對吧? –
@AtitiOO。是的,乘法的結果。當它傳遞給'Println()'函數時,它必須被轉換爲一個類型值。還編輯添加代碼以顯示結果的類型。 – icza
可能重複[浮點數學是否被破壞?](http://stackoverflow.com/questions/588004/is-floating-point-math-broken) – asawyer
@asawyer不是。 OP在想,爲什麼這兩個產生不同的結果,而不是爲什麼其中一個結果不完全是9.12。 – fuz