golangのfloat64の丸誤差について
プログラムの小数点の計算や割り算において、丸誤差を認識する機会がたまにあります。
今回はgolangのプログラムを書いていて発生したので、検証してみました。
プログラムと検証
func main() { fmt.Printf("%f\n", getFloat() * 1000 ) fmt.Printf("%.10f\n", getFloat() * 1000 ) fmt.Printf("%f\n", getFloat2() * 1000 ) fmt.Printf("%.10f\n", getFloat2() * 1000 ) fmt.Printf("%f\n", getFloat3() * 1000 ) fmt.Printf("%.10f\n", getFloat3() * 1000 ) } func getFloat() float64 { return 340.785 } func getFloat2() float64 { return -1192.295 + 1766.96 -233.88 } func getFloat3() float64 { t1 := -1192.295 t2 := 1766.96 t3 := -233.88 return t1 + t2 + t3 }
340785.000000 340785.0000000000 340785.000000 340785.0000000000 340785.000000 340784.9999999999
まず変数に変換しなければ、期待した値になっています。
変数にいれて計算を行うことで、丸誤差が発生するようになっています。
またPrintfは、四捨五入をするためこのような結果になります。
printfの四捨五入
func main() { fmt.Printf("%f\n", 10.0000000000 ) fmt.Printf("%.10f\n", 10.0000000000 ) fmt.Printf("%f\n", 10.44444444444 ) fmt.Printf("%.10f\n", 10.44444444444 ) fmt.Printf("%f\n", 10.55555555555 ) fmt.Printf("%.10f\n", 10.55555555555 ) fmt.Printf("%f\n", 10.99999999999 ) fmt.Printf("%.10f\n", 10.99999999999 ) }
10.000000 10.0000000000 10.444444 10.4444444444 10.555556 10.5555555556 11.000000 11.0000000000
パラメータを指定しない場合は、小数点6桁で四捨五入する仕様になっています。
改めて実行してみると、動作がよくわかると思います。
対策も考えて調べてみましたが、math/bigで試しても同じような結果になったので、割り切るしかないのかな。
詳しく対策がわかったらまた記事を書きたいです。
頑張ります。