Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 14480] ファイルの概要

コミット

このコミットは、Go言語のテストスイートに、浮動小数点定数の丸めに関する新しいテストケースを追加するものです。具体的には、float32からfloat64への型変換における0.01の丸め挙動が、gccgoコンパイラで正しく扱われていなかった問題に対応するためのテストです。

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/76fa4f430ad1768450dd052f0fefefba0cc022b7

元コミット内容

commit 76fa4f430ad1768450dd052f0fefefba0cc022b7
Author: Ian Lance Taylor <iant@golang.org>
Date:   Mon Nov 26 08:31:15 2012 -0800

    test: add test for floating point rounding of constants
    
    Failed with gccgo.
    
    R=golang-dev, remyoudompheng, rsc
    CC=golang-dev
    https://golang.org/cl/6855053
---
 test/fixedbugs/bug470.go | 26 ++++++++++++++++++++++++++\n 1 file changed, 26 insertions(+)\n\ndiff --git a/test/fixedbugs/bug470.go b/test/fixedbugs/bug470.go
new file mode 100644
index 0000000000..0a359184c6
--- /dev/null
+++ b/test/fixedbugs/bug470.go
@@ -0,0 +1,26 @@
+// run
+\n+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+\n+// Converting constants between types must introduce rounding.
+\n+package main
+\n+import "fmt"\n+\n+const (\n+    F32 = 0.00999999977648258209228515625
+    F64 = 0.01000000000000000020816681711721685132943093776702880859375
+)\n+\n+var F = float64(float32(0.01))\n+\n+func main() {\n+\t// 0.01 rounded to float32 then to float64 is F32.
+\t// 0.01 represented directly in float64 is F64.
+\tif F != F32 {\n+\t\tpanic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))\n+\t}\n+}\n

変更の背景

このコミットの背景には、Go言語のコンパイラの一つであるgccgoにおける浮動小数点数の丸め処理の不正確さがありました。浮動小数点数は、コンピュータ内部で厳密な十進数として表現できない場合が多く、近似値として格納されます。この近似値の計算や型変換の際に、丸め誤差が発生します。

特に問題となったのは、0.01という十進数をfloat32(単精度浮動小数点数)に変換し、さらにそれをfloat64(倍精度浮動小数点数)に変換する際の挙動です。Go言語の仕様では、定数の型変換において適切な丸めが行われることが期待されます。しかし、gccgoではこの丸め処理が期待通りに行われず、結果として異なる値が生成されてしまうバグが存在していました。

このバグは、数値計算の正確性が求められるアプリケーションにおいて、予期せぬ結果や誤動作を引き起こす可能性がありました。そのため、この問題を特定し、将来的に同様のバグが再発しないように、テストケースを追加する必要がありました。このテストは、gccgoだけでなく、Go言語の他のコンパイラ(例: gc)でも同様の挙動が保証されることを確認するためにも重要です。

前提知識の解説

浮動小数点数 (Floating-Point Numbers)

浮動小数点数は、実数をコンピュータで表現するための形式です。IEEE 754規格が広く用いられており、Go言語のfloat32float64もこの規格に準拠しています。

  • float32 (単精度浮動小数点数): 32ビットで表現され、約7桁の十進精度を持ちます。表現できる数値の範囲は広いですが、精度は限定的です。
  • float64 (倍精度浮動小数点数): 64ビットで表現され、約15〜17桁の十進精度を持ちます。float32よりも高い精度と広い範囲を持ちます。

浮動小数点数の表現と丸め誤差

多くの十進数は、二進数では無限小数になります(例: 0.1は二進数では0.00011001100...と無限に続きます)。コンピュータは有限のビット数で数値を表現するため、無限小数を途中で打ち切る必要があり、この際に丸め誤差 (Rounding Error) が発生します。

例えば、0.01という十進数をfloat32で表現しようとすると、最も近いfloat32の値に丸められます。この丸められたfloat32の値をさらにfloat64に変換すると、そのfloat32の正確な値がfloat64で表現されます。これは、元の0.01を直接float64で表現した場合とは異なる値になる可能性があります。

gccgo

gccgoは、GCC (GNU Compiler Collection) のフロントエンドとして実装されたGo言語のコンパイラです。Go言語の公式コンパイラであるgcとは異なる実装であり、Go言語の仕様に準拠しつつも、GCCの最適化やバックエンドを利用します。異なるコンパイラ実装が存在することで、言語仕様の解釈や数値計算の挙動に微妙な差異が生じることがあり、今回の浮動小数点数の丸め問題もその一例でした。

技術的詳細

このコミットが対処している技術的な問題は、Go言語における浮動小数点定数の型変換時の丸め挙動の一貫性です。特に、0.01という十進数のリテラルがfloat32に変換され、その後float64に変換される際の正確な値が、Go言語の仕様に沿っているかどうかが焦点です。

Go言語の定数は、型付けされていない場合、その値が表現できる最も広い精度で扱われます。しかし、明示的に型変換が行われる場合、その型の精度に合わせて値が丸められます。

今回のケースでは、以下の2つの値が比較されています。

  1. float64(float32(0.01)):
    • まず、十進数の0.01float32に変換されます。この際、0.01に最も近いfloat32の値に丸められます。この値は0.00999999977648258209228515625です。
    • 次に、このfloat32の値がfloat64に変換されます。float32で表現された値は、float64の精度であれば正確に表現できるため、値はそのまま0.00999999977648258209228515625となります。
  2. 0.01を直接float64で表現した場合:
    • 十進数の0.01を直接float64で表現すると、0.01000000000000000020816681711721685132943093776702880859375という値になります。

この2つの値は、見た目は似ていますが、浮動小数点数の内部表現においては異なる値です。Go言語の仕様では、定数の型変換は予測可能な方法で丸めを行うべきであり、float64(float32(0.01))の結果は、0.01float32に丸めた結果をfloat64で表現した値と一致する必要があります。

gccgoがこのテストで失敗したということは、gccgoのコンパイラがfloat64(float32(0.01))の計算において、期待される0.00999999977648258209228515625ではなく、0.01000000000000000020816681711721685132943093776702880859375に近い、あるいはそれと等しい値を生成してしまっていたことを示唆しています。これは、gccgoが中間的なfloat32への丸めを正しく行っていなかったか、あるいは最適化の過程で丸め挙動が変化してしまっていた可能性を意味します。

このテストの追加により、Go言語の異なるコンパイラ実装間での浮動小数点定数の丸め挙動の一貫性が保証され、数値計算の信頼性が向上します。

コアとなるコードの変更箇所

このコミットでは、test/fixedbugs/bug470.goという新しいテストファイルが追加されています。

--- /dev/null
+++ b/test/fixedbugs/bug470.go
@@ -0,0 +1,26 @@
+// run
+\n+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+\n+// Converting constants between types must introduce rounding.
+\n+package main
+\n+import "fmt"\n+\n+const (\n+    F32 = 0.00999999977648258209228515625
+    F64 = 0.01000000000000000020816681711721685132943093776702880859375
+)\n+\n+var F = float64(float32(0.01))\n+\n+func main() {\n+\t// 0.01 rounded to float32 then to float64 is F32.
+\t// 0.01 represented directly in float64 is F64.
+\tif F != F32 {\n+\t\tpanic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))\n+\t}\n+}\n

コアとなるコードの解説

test/fixedbugs/bug470.goファイルは、浮動小数点数の丸め挙動を検証するためのシンプルなGoプログラムです。

  1. パッケージとインポート:

    • package main: 実行可能なプログラムであることを示します。
    • import "fmt": フォーマットされたI/O(入出力)を行うためのパッケージをインポートしています。fmt.Sprintf関数がエラーメッセージの整形に使用されます。
  2. 定数の定義:

    const (
        F32 = 0.00999999977648258209228515625
        F64 = 0.01000000000000000020816681711721685132943093776702880859375
    )
    
    • F32: これは、十進数の0.01float32に丸めた後、そのfloat32の値をfloat64で正確に表現したものです。この値は、0.01に最も近いfloat32のバイナリ表現を十進数で表したものです。
    • F64: これは、十進数の0.01を直接float64で表現したものです。0.01は二進数で正確に表現できないため、float64の精度で最も近い値に丸められています。
  3. 変数の定義:

    var F = float64(float32(0.01))
    
    • F: この変数は、テストの対象となる計算結果を保持します。0.01というリテラルをまずfloat32に明示的に型変換し、その結果をさらにfloat64に型変換しています。Go言語の仕様では、このFの値がF32と厳密に一致することが期待されます。
  4. main関数:

    func main() {
    	// 0.01 rounded to float32 then to float64 is F32.
    	// 0.01 represented directly in float64 is F64.
    	if F != F32 {
    		panic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))
    	}
    }
    
    • このmain関数がテストの本体です。
    • if F != F32: Fの値がF32と等しいかどうかを比較しています。もし等しくなければ、期待される丸め挙動が実現されていないことを意味します。
    • panic(fmt.Sprintf(...)): FF32が一致しない場合、プログラムはパニック(異常終了)します。エラーメッセージには、実際に得られたFの値と、期待されるF32の値が、非常に高い精度(小数点以下1000桁)で表示されます。これにより、丸め誤差の具体的な数値を確認できます。

このテストは、Go言語のコンパイラが浮動小数点定数の型変換において、IEEE 754規格とGo言語の仕様に準拠した正確な丸め処理を行っていることを検証するために不可欠です。

関連リンク

参考にした情報源リンク

[インデックス 14480] ファイルの概要

コミット

このコミットは、Go言語のテストスイートに、浮動小数点定数の丸めに関する新しいテストケースを追加するものです。具体的には、float32からfloat64への型変換における0.01の丸め挙動が、gccgoコンパイラで正しく扱われていなかった問題に対応するためのテストです。

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/76fa4f430ad1768450dd052f0fefefba0cc022b7

元コミット内容

commit 76fa4f430ad1768450dd052f0fefefba0cc022b7
Author: Ian Lance Taylor <iant@golang.org>
Date:   Mon Nov 26 08:31:15 2012 -0800

    test: add test for floating point rounding of constants
    
    Failed with gccgo.
    
    R=golang-dev, remyoudompheng, rsc
    CC=golang-dev
    https://golang.org/cl/6855053
---
 test/fixedbugs/bug470.go | 26 ++++++++++++++++++++++++++\n 1 file changed, 26 insertions(+)\n\ndiff --git a/test/fixedbugs/bug470.go b/test/fixedbugs/bug470.go
new file mode 100644
index 0000000000..0a359184c6
--- /dev/null
+++ b/test/fixedbugs/bug470.go
@@ -0,0 +1,26 @@
+// run
+\n+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+\n+// Converting constants between types must introduce rounding.
+\n+package main
+\n+import "fmt"\n+\n+const (\n+    F32 = 0.00999999977648258209228515625
+    F64 = 0.01000000000000000020816681711721685132943093776702880859375
+)\n+\n+var F = float64(float32(0.01))\n+\n+func main() {\n+\t// 0.01 rounded to float32 then to float64 is F32.
+\t// 0.01 represented directly in float64 is F64.
+\tif F != F32 {\n+\t\tpanic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))\n+\t}\n+}\n

変更の背景

このコミットの背景には、Go言語のコンパイラの一つであるgccgoにおける浮動小数点数の丸め処理の不正確さがありました。浮動小数点数は、コンピュータ内部で厳密な十進数として表現できない場合が多く、近似値として格納されます。この近似値の計算や型変換の際に、丸め誤差が発生します。

特に問題となったのは、0.01という十進数をfloat32(単精度浮動小数点数)に変換し、さらにそれをfloat64(倍精度浮動小数点数)に変換する際の挙動です。Go言語の仕様では、定数の型変換において適切な丸めが行われることが期待されます。しかし、gccgoではこの丸め処理が期待通りに行われず、結果として異なる値が生成されてしまうバグが存在していました。

このバグは、数値計算の正確性が求められるアプリケーションにおいて、予期せぬ結果や誤動作を引き起こす可能性がありました。そのため、この問題を特定し、将来的に同様のバグが再発しないように、テストケースを追加する必要がありました。このテストは、gccgoだけでなく、Go言語の他のコンパイラ(例: gc)でも同様の挙動が保証されることを確認するためにも重要です。

前提知識の解説

浮動小数点数 (Floating-Point Numbers)

浮動小数点数は、実数をコンピュータで表現するための形式です。IEEE 754規格が広く用いられており、Go言語のfloat32float64もこの規格に準拠しています。

  • float32 (単精度浮動小数点数): 32ビットで表現され、約7桁の十進精度を持ちます。表現できる数値の範囲は広いですが、精度は限定的です。
  • float64 (倍精度浮動小数点数): 64ビットで表現され、約15〜17桁の十進精度を持ちます。float32よりも高い精度と広い範囲を持ちます。

浮動小数点数の表現と丸め誤差

多くの十進数は、二進数では無限小数になります(例: 0.1は二進数では0.00011001100...と無限に続きます)。コンピュータは有限のビット数で数値を表現するため、無限小数を途中で打ち切る必要があり、この際に丸め誤差 (Rounding Error) が発生します。

例えば、0.01という十進数をfloat32で表現しようとすると、最も近いfloat32の値に丸められます。この丸められたfloat32の値をさらにfloat64に変換すると、そのfloat32の正確な値がfloat64で表現されます。これは、元の0.01を直接float64で表現した場合とは異なる値になる可能性があります。

gccgo

gccgoは、GCC (GNU Compiler Collection) のフロントエンドとして実装されたGo言語のコンパイラです。Go言語の公式コンパイラであるgcとは異なる実装であり、Go言語の仕様に準拠しつつも、GCCの最適化やバックエンドを利用します。異なるコンパイラ実装が存在することで、言語仕様の解釈や数値計算の挙動に微妙な差異が生じることがあり、今回の浮動小数点数の丸め問題もその一例でした。

技術的詳細

このコミットが対処している技術的な問題は、Go言語における浮動小数点定数の型変換時の丸め挙動の一貫性です。特に、0.01という十進数のリテラルがfloat32に変換され、その後float64に変換される際の正確な値が、Go言語の仕様に沿っているかどうかが焦点です。

Go言語の定数は、型付けされていない場合、その値が表現できる最も広い精度で扱われます。しかし、明示的に型変換が行われる場合、その型の精度に合わせて値が丸められます。

今回のケースでは、以下の2つの値が比較されています。

  1. float64(float32(0.01)):
    • まず、十進数の0.01float32に変換されます。この際、0.01に最も近いfloat32の値に丸められます。この値は0.00999999977648258209228515625です。
    • 次に、このfloat32の値がfloat64に変換されます。float32で表現された値は、float64の精度であれば正確に表現できるため、値はそのまま0.00999999977648258209228515625となります。
  2. 0.01を直接float64で表現した場合:
    • 十進数の0.01を直接float64で表現すると、0.01000000000000000020816681711721685132943093776702880859375という値になります。

この2つの値は、見た目は似ていますが、浮動小数点数の内部表現においては異なる値です。Go言語の仕様では、定数の型変換は予測可能な方法で丸めを行うべきであり、float64(float32(0.01))の結果は、0.01float32に丸めた結果をfloat64で表現した値と一致する必要があります。

gccgoがこのテストで失敗したということは、gccgoのコンパイラがfloat64(float32(0.01))の計算において、期待される0.00999999977648258209228515625ではなく、0.01000000000000000020816681711721685132943093776702880859375に近い、あるいはそれと等しい値を生成してしまっていたことを示唆しています。これは、gccgoが中間的なfloat32への丸めを正しく行っていなかったか、あるいは最適化の過程で丸め挙動が変化してしまっていた可能性を意味します。

このテストの追加により、Go言語の異なるコンパイラ実装間での浮動小数点定数の丸め挙動の一貫性が保証され、数値計算の信頼性が向上します。

コアとなるコードの変更箇所

このコミットでは、test/fixedbugs/bug470.goという新しいテストファイルが追加されています。

--- /dev/null
+++ b/test/fixedbugs/bug470.go
@@ -0,0 +1,26 @@
+// run
+\n+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+\n+// Converting constants between types must introduce rounding.
+\n+package main
+\n+import "fmt"\n+\n+const (\n+    F32 = 0.00999999977648258209228515625
+    F64 = 0.01000000000000000020816681711721685132943093776702880859375
+)\n+\n+var F = float64(float32(0.01))\n+\n+func main() {\n+\t// 0.01 rounded to float32 then to float64 is F32.
+\t// 0.01 represented directly in float64 is F64.
+\tif F != F32 {\n+\t\tpanic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))\n+\t}\n+}\n

コアとなるコードの解説

test/fixedbugs/bug470.goファイルは、浮動小数点数の丸め挙動を検証するためのシンプルなGoプログラムです。

  1. パッケージとインポート:

    • package main: 実行可能なプログラムであることを示します。
    • import "fmt": フォーマットされたI/O(入出力)を行うためのパッケージをインポートしています。fmt.Sprintf関数がエラーメッセージの整形に使用されます。
  2. 定数の定義:

    const (
        F32 = 0.00999999977648258209228515625
        F64 = 0.01000000000000000020816681711721685132943093776702880859375
    )
    
    • F32: これは、十進数の0.01float32に丸めた後、そのfloat32の値をfloat64で正確に表現したものです。この値は、0.01に最も近いfloat32のバイナリ表現を十進数で表したものです。
    • F64: これは、十進数の0.01を直接float64で表現したものです。0.01は二進数で正確に表現できないため、float64の精度で最も近い値に丸められています。
  3. 変数の定義:

    var F = float64(float32(0.01))
    
    • F: この変数は、テストの対象となる計算結果を保持します。0.01というリテラルをまずfloat32に明示的に型変換し、その結果をさらにfloat64に型変換しています。Go言語の仕様では、このFの値がF32と厳密に一致することが期待されます。
  4. main関数:

    func main() {
    	// 0.01 rounded to float32 then to float64 is F32.
    	// 0.01 represented directly in float64 is F64.
    	if F != F32 {
    		panic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))
    	}
    }
    
    • このmain関数がテストの本体です。
    • if F != F32: Fの値がF32と等しいかどうかを比較しています。もし等しくなければ、期待される丸め挙動が実現されていないことを意味します。
    • panic(fmt.Sprintf(...)): FF32が一致しない場合、プログラムはパニック(異常終了)します。エラーメッセージには、実際に得られたFの値と、期待されるF32の値が、非常に高い精度(小数点以下1000桁)で表示されます。これにより、丸め誤差の具体的な数値を確認できます。

このテストは、Go言語のコンパイラが浮動小数点定数の型変換において、IEEE 754規格とGo言語の仕様に準拠した正確な丸め処理を行っていることを検証するために不可欠です。

関連リンク

参考にした情報源リンク

[インデックス 14480] ファイルの概要

コミット

このコミットは、Go言語のテストスイートに、浮動小数点定数の丸めに関する新しいテストケースを追加するものです。具体的には、float32からfloat64への型変換における0.01の丸め挙動が、gccgoコンパイラで正しく扱われていなかった問題に対応するためのテストです。

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/76fa4f430ad1768450dd052f0fefefba0cc022b7

元コミット内容

commit 76fa4f430ad1768450dd052f0fefefba0cc022b7
Author: Ian Lance Taylor <iant@golang.org>
Date:   Mon Nov 26 08:31:15 2012 -0800

    test: add test for floating point rounding of constants
    
    Failed with gccgo.
    
    R=golang-dev, remyoudompheng, rsc
    CC=golang-dev
    https://golang.org/cl/6855053
---
 test/fixedbugs/bug470.go | 26 ++++++++++++++++++++++++++\n 1 file changed, 26 insertions(+)\n\ndiff --git a/test/fixedbugs/bug470.go b/test/fixedbugs/bug470.go
new file mode 100644
index 0000000000..0a359184c6
--- /dev/null
+++ b/test/fixedbugs/bug470.go
@@ -0,0 +1,26 @@
+// run
+\n+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+\n+// Converting constants between types must introduce rounding.
+\n+package main
+\n+import "fmt"\n+\n+const (\n+    F32 = 0.00999999977648258209228515625
+    F64 = 0.01000000000000000020816681711721685132943093776702880859375
+)\n+\n+var F = float64(float32(0.01))\n+\n+func main() {\n+\t// 0.01 rounded to float32 then to float64 is F32.
+\t// 0.01 represented directly in float64 is F64.
+\tif F != F32 {\n+\t\tpanic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))\n+\t}\n+}\n

変更の背景

このコミットの背景には、Go言語のコンパイラの一つであるgccgoにおける浮動小数点数の丸め処理の不正確さがありました。浮動小数点数は、コンピュータ内部で厳密な十進数として表現できない場合が多く、近似値として格納されます。この近似値の計算や型変換の際に、丸め誤差が発生します。

特に問題となったのは、0.01という十進数をfloat32(単精度浮動小数点数)に変換し、さらにそれをfloat64(倍精度浮動小数点数)に変換する際の挙動です。Go言語の仕様では、定数の型変換において適切な丸めが行われることが期待されます。しかし、gccgoではこの丸め処理が期待通りに行われず、結果として異なる値が生成されてしまうバグが存在していました。

このバグは、数値計算の正確性が求められるアプリケーションにおいて、予期せぬ結果や誤動作を引き起こす可能性がありました。そのため、この問題を特定し、将来的に同様のバグが再発しないように、テストケースを追加する必要がありました。このテストは、gccgoだけでなく、Go言語の他のコンパイラ(例: gc)でも同様の挙動が保証されることを確認するためにも重要です。

前提知識の解説

浮動小数点数 (Floating-Point Numbers)

浮動小数点数は、実数をコンピュータで表現するための形式です。IEEE 754規格が広く用いられており、Go言語のfloat32float64もこの規格に準拠しています。

  • float32 (単精度浮動小数点数): 32ビットで表現され、約7桁の十進精度を持ちます。表現できる数値の範囲は広いですが、精度は限定的です。
  • float64 (倍精度浮動小数点数): 64ビットで表現され、約15〜17桁の十進精度を持ちます。float32よりも高い精度と広い範囲を持ちます。

浮動小数点数の表現と丸め誤差

多くの十進数は、二進数では無限小数になります(例: 0.1は二進数では0.00011001100...と無限に続きます)。コンピュータは有限のビット数で数値を表現するため、無限小数を途中で打ち切る必要があり、この際に丸め誤差 (Rounding Error) が発生します。

例えば、0.01という十進数をfloat32で表現しようとすると、最も近いfloat32の値に丸められます。この丸められたfloat32の値をさらにfloat64に変換すると、そのfloat32の正確な値がfloat64で表現されます。これは、元の0.01を直接float64で表現した場合とは異なる値になる可能性があります。

gccgo

gccgoは、GCC (GNU Compiler Collection) のフロントエンドとして実装されたGo言語のコンパイラです。Go言語の公式コンパイラであるgcとは異なる実装であり、Go言語の仕様に準拠しつつも、GCCの最適化やバックエンドを利用します。異なるコンパイラ実装が存在することで、言語仕様の解釈や数値計算の挙動に微妙な差異が生じることがあり、今回の浮動小数点数の丸め問題もその一例でした。

技術的詳細

このコミットが対処している技術的な問題は、Go言語における浮動小数点定数の型変換時の丸め挙動の一貫性です。特に、0.01という十進数のリテラルがfloat32に変換され、その後float64に変換される際の正確な値が、Go言語の仕様に沿っているかどうかが焦点です。

Go言語の定数は、型付けされていない場合、その値が表現できる最も広い精度で扱われます。しかし、明示的に型変換が行われる場合、その型の精度に合わせて値が丸められます。

今回のケースでは、以下の2つの値が比較されています。

  1. float64(float32(0.01)):
    • まず、十進数の0.01float32に変換されます。この際、0.01に最も近いfloat32の値に丸められます。この値は0.00999999977648258209228515625です。
    • 次に、このfloat32の値がfloat64に変換されます。float32で表現された値は、float64の精度であれば正確に表現できるため、値はそのまま0.00999999977648258209228515625となります。
  2. 0.01を直接float64で表現した場合:
    • 十進数の0.01を直接float64で表現すると、0.01000000000000000020816681711721685132943093776702880859375という値になります。

この2つの値は、見た目は似ていますが、浮動小数点数の内部表現においては異なる値です。Go言語の仕様では、定数の型変換は予測可能な方法で丸めを行うべきであり、float64(float32(0.01))の結果は、0.01float32に丸めた結果をfloat64で表現した値と一致する必要があります。

gccgoがこのテストで失敗したということは、gccgoのコンパイラがfloat64(float32(0.01))の計算において、期待される0.00999999977648258209228515625ではなく、0.01000000000000000020816681711721685132943093776702880859375に近い、あるいはそれと等しい値を生成してしまっていたことを示唆しています。これは、gccgoが中間的なfloat32への丸めを正しく行っていなかったか、あるいは最適化の過程で丸め挙動が変化してしまっていた可能性を意味します。

このテストの追加により、Go言語の異なるコンパイラ実装間での浮動小数点定数の丸め挙動の一貫性が保証され、数値計算の信頼性が向上します。

コアとなるコードの変更箇所

このコミットでは、test/fixedbugs/bug470.goという新しいテストファイルが追加されています。

--- /dev/null
+++ b/test/fixedbugs/bug470.go
@@ -0,0 +1,26 @@
+// run
+\n+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+\n+// Converting constants between types must introduce rounding.
+\n+package main
+\n+import "fmt"\n+\n+const (\n+    F32 = 0.00999999977648258209228515625
+    F64 = 0.01000000000000000020816681711721685132943093776702880859375
+)\n+\n+var F = float64(float32(0.01))\n+\n+func main() {\n+\t// 0.01 rounded to float32 then to float64 is F32.
+\t// 0.01 represented directly in float64 is F64.
+\tif F != F32 {\n+\t\tpanic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))\n+\t}\n+}\n

コアとなるコードの解説

test/fixedbugs/bug470.goファイルは、浮動小数点数の丸め挙動を検証するためのシンプルなGoプログラムです。

  1. パッケージとインポート:

    • package main: 実行可能なプログラムであることを示します。
    • import "fmt": フォーマットされたI/O(入出力)を行うためのパッケージをインポートしています。fmt.Sprintf関数がエラーメッセージの整形に使用されます。
  2. 定数の定義:

    const (
        F32 = 0.00999999977648258209228515625
        F64 = 0.01000000000000000020816681711721685132943093776702880859375
    )
    
    • F32: これは、十進数の0.01float32に丸めた後、そのfloat32の値をfloat64で正確に表現したものです。この値は、0.01に最も近いfloat32のバイナリ表現を十進数で表したものです。
    • F64: これは、十進数の0.01を直接float64で表現したものです。0.01は二進数で正確に表現できないため、float64の精度で最も近い値に丸められています。
  3. 変数の定義:

    var F = float64(float32(0.01))
    
    • F: この変数は、テストの対象となる計算結果を保持します。0.01というリテラルをまずfloat32に明示的に型変換し、その結果をさらにfloat64に型変換しています。Go言語の仕様では、このFの値がF32と厳密に一致することが期待されます。
  4. main関数:

    func main() {
    	// 0.01 rounded to float32 then to float64 is F32.
    	// 0.01 represented directly in float64 is F64.
    	if F != F32 {
    		panic(fmt.Sprintf("F=%.1000g, want %.1000g", F, F32))
    	}
    }
    
    • このmain関数がテストの本体です。
    • if F != F32: Fの値がF32と等しいかどうかを比較しています。もし等しくなければ、期待される丸め挙動が実現されていないことを意味します。
    • panic(fmt.Sprintf(...)): FF32が一致しない場合、プログラムはパニック(異常終了)します。エラーメッセージには、実際に得られたFの値と、期待されるF32の値が、非常に高い精度(小数点以下1000桁)で表示されます。これにより、丸め誤差の具体的な数値を確認できます。

このテストは、Go言語のコンパイラが浮動小数点定数の型変換において、IEEE 754規格とGo言語の仕様に準拠した正確な丸め処理を行っていることを検証するために不可欠です。

関連リンク

参考にした情報源リンク