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

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

このコミットは、Go言語の標準ライブラリの一部であるsrc/lib/strconv/ftoa_test.goファイルに対する変更です。このファイルは、浮動小数点数を文字列に変換するftoa(float-to-ASCII)関数のテストケースを含んでいます。

コミット

commit 548609654311809b904f2b5a0926f3b38b45b7b4
Author: Russ Cox <rsc@golang.org>
Date:   Mon Dec 1 16:03:09 2008 -0800

    be more precise in ftoa_test.
    
    R=ken
    OCL=20173
    CL=20173

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

https://github.com/golang/go/commit/548609654311809b904f2b5a0926f3b38b45b7b4

元コミット内容

このコミットの目的は、ftoa_test.goにおける浮動小数点数のテストケースの精度を向上させることです。具体的には、1e23 - 8.5e61e23 + 8.5e6という浮動小数点リテラルを、float64型で正確に表現される定数Below1e23Above1e23に置き換えることで、テストの信頼性と再現性を高めています。

変更の背景

浮動小数点数の計算は、その性質上、常に厳密な精度を保証するわけではありません。特に、float64(倍精度浮動小数点数)のようなバイナリ浮動小数点形式では、多くの十進数が正確に表現できないため、計算結果に微細な誤差が生じることがあります。

このコミットが行われた背景には、ftoa_test.go内の既存のテストケースが、1e23 - 8.5e61e23 + 8.5e6といった浮動小数点リテラルを使用していたことが挙げられます。これらのリテラルは、ソースコード上では特定の十進数として記述されていますが、float64型に変換される際に、最も近いバイナリ表現に丸められます。この丸め処理によって、意図しない値がテストに使用され、テスト結果が不安定になったり、特定の環境やコンパイラ設定によって異なる結果を生じたりする可能性がありました。

Russ Cox氏によるこの変更は、このような浮動小数点数の丸め誤差に起因するテストの不安定性を解消し、ftoa関数のテストが常に期待通りの正確な浮動小数点値に対して行われるようにすることを目的としています。これにより、ftoa関数の実装が、浮動小数点数の正確な文字列変換を保証しているかをより厳密に検証できるようになります。

前提知識の解説

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

コンピュータにおける浮動小数点数は、実数を近似的に表現するための形式です。IEEE 754標準が広く採用されており、Go言語のfloat64型もこの標準に準拠しています。浮動小数点数は通常、符号部、指数部、仮数部(または有効数字部)の3つの部分で構成されます。

  • 符号部: 数値が正か負かを示します。
  • 指数部: 小数点の位置を示し、数値の大きさを決定します。
  • 仮数部: 数値の有効数字を示します。

float64は倍精度浮動小数点数であり、64ビット(8バイト)を使用して数値を表現します。これにより、約15〜17桁の十進精度と、非常に広い範囲の数値を表現できますが、すべての実数を正確に表現できるわけではありません。特に、十進数で有限小数であっても、二進数では無限小数になる場合(例: 0.1)は、最も近い二進数で近似されるため、丸め誤差が生じます。

浮動小数点数の丸め誤差 (Rounding Errors)

浮動小数点数の計算では、表現可能な桁数や範囲の制約により、正確な値が表現できない場合に丸め処理が行われます。この丸めによって生じる誤差を丸め誤差と呼びます。例えば、1/3は十進数では0.333...と無限に続きますが、有限の桁数で表現する際にはどこかで打ち切られるため、誤差が生じます。同様に、二進数で表現できない十進数も丸められます。

このコミットで問題となっているのは、1e23 - 8.5e61e23 + 8.5e6といった計算結果が、float64のバイナリ表現において、ソースコードに記述された十進数と完全に一致しない可能性がある点です。これらの計算結果は、最も近いfloat64の表現可能な値に丸められます。

ftoa関数 (Float-to-ASCII)

ftoa関数は、浮動小数点数を文字列形式に変換する役割を担います。この変換は、科学技術計算の結果を人間が読める形式で表示したり、データをファイルに保存したりする際に不可欠です。ftoa関数は、変換の際に、指数表記(e形式)、固定小数点表記(f形式)、またはその両方を組み合わせた一般表記(g形式)など、様々なフォーマットオプションを提供します。これらのフォーマットは、数値の大きさや精度に応じて適切な表示形式を選択するために使用されます。

ftoa_test.goは、このftoa関数が、様々な浮動小数点数(正の数、負の数、ゼロ、無限大、非数(NaN)、そして非常に大きい数や小さい数)に対して、期待される文字列を正確に生成するかどうかを検証するための単体テストファイルです。

技術的詳細

このコミットの核心は、浮動小数点リテラルの代わりに、float64型で正確に表現される定数を使用することで、テストの決定論的(deterministic)な性質を保証することにあります。

元のコードでは、1e23 - 8.5e6という式が使用されていました。 1e2310^238.5e68.5 * 10^6です。 この計算結果は99999999999999991500000となります。 しかし、この十進数がfloat64型で正確に表現できるとは限りません。float64の内部表現では、この値に最も近い表現可能な値に丸められます。

同様に、1e23 + 8.5e6という式も使用されていました。 この計算結果は100000000000000008500000となります。 これもまた、float64型で正確に表現できるとは限りません。

このコミットでは、これらの計算結果がfloat64型で実際にどのように表現されるかを特定し、その正確なバイナリ表現に対応する十進数を定数として定義しています。

  • Below1e23 = 99999999999999974834176
  • Above1e23 = 100000000000000008388608

これらの定数は、それぞれ1e23 - 8.5e61e23 + 8.5e6float64として計算した際に、実際にメモリに格納される正確な値(最も近い表現可能な値)です。

例えば、1e23 - 8.5e6をGoのfloat64で計算し、その値をfmt.Printf("%.0f", value)などで出力すると、99999999999999974834176という結果が得られます。これは、1e23 - 8.5e6という十進数の計算結果が、float64の精度では99999999999999974834176に丸められることを意味します。

同様に、1e23 + 8.5e6float64で計算すると、100000000000000008388608に丸められます。

これらの正確なfloat64表現を定数として使用することで、テストは浮動小数点数の丸め誤差の影響を受けなくなり、ftoa関数がこれらの特定の、かつ正確に表現可能なfloat64値に対して正しく動作するかを検証できるようになります。これにより、テストの信頼性が向上し、異なる環境でのテスト結果の不一致を防ぐことができます。

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

変更はsrc/lib/strconv/ftoa_test.goファイルに集中しています。

--- a/src/lib/strconv/ftoa_test.go
+++ b/src/lib/strconv/ftoa_test.go
@@ -18,6 +18,11 @@ type Test struct {
 
 func fdiv(a, b float64) float64 { return a / b }	// keep compiler in the dark
 
+const (
+	Below1e23 = 99999999999999974834176;
+	Above1e23 = 100000000000000008388608;
+)
+
 // TODO: Should be able to call this tests but it conflicts with testatof.go
 var ftests = []Test {
 	Test{ 1, 'e', 5, "1.00000e+00" },
@@ -61,21 +66,21 @@ var ftests = []Test {
 	Test{ 1e23, 'f', -1, "100000000000000000000000" },
 	Test{ 1e23, 'g', -1, "1e+23" },
 
-	Test{ 1e23-8.5e6, 'e', 17, "9.99999999999999748e+22" },
-	Test{ 1e23-8.5e6, 'f', 17, "99999999999999974834176.00000000000000000" },
-	Test{ 1e23-8.5e6, 'g', 17, "9.9999999999999975e+22" },
+	Test{ Below1e23, 'e', 17, "9.99999999999999748e+22" },
+	Test{ Below1e23, 'f', 17, "99999999999999974834176.00000000000000000" },
+	Test{ Below1e23, 'g', 17, "9.9999999999999975e+22" },
 
-	Test{ 1e23-8.5e6, 'e', -1, "9.999999999999997e+22" },
-	Test{ 1e23-8.5e6, 'f', -1, "99999999999999970000000" },
-	Test{ 1e23-8.5e6, 'g', -1, "9.999999999999997e+22" },
+	Test{ Below1e23, 'e', -1, "9.999999999999997e+22" },
+	Test{ Below1e23, 'f', -1, "99999999999999970000000" },
+	Test{ Below1e23, 'g', -1, "9.999999999999997e+22" },
 
-	Test{ 1e23+8.5e6, 'e', 17, "1.00000000000000008e+23" },
-	Test{ 1e23+8.5e6, 'f', 17, "100000000000000008388608.00000000000000000" },
-	Test{ 1e23+8.5e6, 'g', 17, "1.0000000000000001e+23" },
+	Test{ Above1e23, 'e', 17, "1.00000000000000008e+23" },
+	Test{ Above1e23, 'f', 17, "100000000000000008388608.00000000000000000" },
+	Test{ Above1e23, 'g', 17, "1.0000000000000001e+23" },
 
-	Test{ 1e23+8.5e6, 'e', -1, "1.0000000000000001e+23" },
-	Test{ 1e23+8.5e6, 'f', -1, "100000000000000010000000" },
-	Test{ 1e23+8.5e6, 'g', -1, "1.0000000000000001e+23" },
+	Test{ Above1e23, 'e', -1, "1.0000000000000001e+23" },
+	Test{ Above1e23, 'f', -1, "100000000000000010000000" },
+	Test{ Above1e23, 'g', -1, "1.0000000000000001e+23" },

コアとなるコードの解説

  1. 定数の追加: constブロックが追加され、Below1e23Above1e23という2つのfloat64定数が定義されています。

    • Below1e23 = 99999999999999974834176
    • Above1e23 = 100000000000000008388608 これらの値は、それぞれ1e23 - 8.5e61e23 + 8.5e6float64型として表現される際の、最も正確な十進数表現です。これにより、テストで使用される浮動小数点値が、コンパイラや実行環境による丸め誤差の影響を受けず、常に同じ正確な値になることが保証されます。
  2. テストケースの更新: ftestsスライス内の複数のTest構造体の初期化において、元の1e23-8.5e61e23+8.5e6という浮動小数点リテラルが、新しく定義された定数Below1e23Above1e23に置き換えられています。 これにより、これらのテストケースは、浮動小数点数の計算結果に依存するのではなく、float64型で正確に表現される既知の定数に対してftoa関数の動作を検証するようになります。これは、テストの信頼性と再現性を大幅に向上させます。

この変更は、Go言語の初期段階における浮動小数点数処理の厳密性への配慮を示しており、テストの堅牢性を高めるための重要な改善です。

関連リンク

  • IEEE 754 浮動小数点数標準: 浮動小数点数の表現と演算に関する国際標準。
  • Go言語のstrconvパッケージ: 文字列と基本データ型(数値、真偽値など)の相互変換を提供するパッケージ。ftoa関数は、このパッケージの一部として機能します。

参考にした情報源リンク