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

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

このコミットは、Go言語のfmtパッケージにおける浮動小数点数フォーマット指定子%gの出力形式の変更に関するものです。具体的には、特定の大きな浮動小数点数値に対する%gの出力が、固定小数点形式から指数形式(科学的記数法)に変更されたことを示しています。これは、fmtパッケージの浮動小数点数フォーマットの挙動がより一貫性を持つように、または特定のケースでより適切な表現となるように調整されたことを意味します。

コミット

commit 375b1e2a0ee9e147e4e1cfdd20f87e99c108d905
Author: Rob Pike <r@golang.org>
Date:   Mon Nov 24 11:59:23 2008 -0800

    output of fmt has changed for %g
    
    R=rsc
    DELTA=1  (0 added, 0 deleted, 1 changed)
    OCL=19909
    CL=19909

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

https://github.com/golang/go/commit/375b1e2a0ee9e147e4e1cfdd20f87e99c108d905

元コミット内容

このコミットの元のメッセージは非常に簡潔です。

output of fmt has changed for %g

これは、「fmtパッケージの%gフォーマットの出力が変更された」という事実を直接的に述べています。具体的な変更内容や理由については、このメッセージだけでは詳細が分かりませんが、テストコードの変更からその詳細を読み取ることができます。

変更の背景

Go言語の初期開発段階において、fmtパッケージのフォーマットルール、特に浮動小数点数の扱いは、その後の安定版リリースに向けて継続的に洗練されていました。%gフォーマットは、数値の大きさに応じて固定小数点形式(%f)と指数形式(%e)を自動的に切り替える「汎用」フォーマットとして設計されています。この自動切り替えの閾値や挙動は、数値の可読性、精度、そして一般的な慣習に合致するように調整されることがあります。

このコミットは、おそらく特定の大きな数値(例: 1234.5678e3、つまり 1,234,567.8)に対して、以前は固定小数点形式で出力されていたものが、より適切な指数形式で出力されるように変更されたことを示唆しています。これは、非常に大きな数値や非常に小さな数値を扱う際に、指数形式の方が桁数を抑えつつ精度を保ち、かつ可読性を向上させるための方針転換、またはバグ修正の一環であった可能性があります。

Go言語のfmtパッケージは、C言語のprintfにインスパイアされていますが、Go独自の設計思想に基づいており、その挙動は厳密に定義され、テストによって保証されています。このような変更は、言語の安定性と予測可能性を確保するための継続的な改善プロセスの一部です。

前提知識の解説

Go言語のfmtパッケージ

fmtパッケージは、Go言語におけるフォーマットI/O(入力/出力)を提供する標準ライブラリです。C言語のprintfscanfに似た機能を提供し、様々なデータ型を整形して文字列として出力したり、文字列からデータを解析したりするために使用されます。

主な関数には以下のようなものがあります。

  • fmt.Printf(format string, a ...interface{}) (n int, err error): フォーマット文字列に基づいて標準出力に整形された文字列を出力します。
  • fmt.Sprintf(format string, a ...interface{}) string: フォーマット文字列に基づいて整形された文字列を返します。
  • fmt.Print(a ...interface{}) (n int, err): 引数をデフォルトのフォーマットで標準出力に出力します。
  • fmt.Println(a ...interface{}) (n int, err): 引数をデフォルトのフォーマットで標準出力に出力し、改行を追加します。

フォーマット指定子(Verb)

fmtパッケージでは、フォーマット文字列内で%に続く文字(Verb)を使って、出力する値の型や表示形式を指定します。

浮動小数点数に関連する主なVerbは以下の通りです。

  • %f (float): 小数点以下の桁数を指定して固定小数点形式で表示します。デフォルトでは小数点以下6桁が表示されます。例: 123.456789
  • %e (scientific notation): 指数形式(科学的記数法)で表示します。例: 1.234567e+02
  • %g (general): %f%eのうち、より短く、かつ精度を保てる方を自動的に選択して表示します。これは、数値の大きさに応じて表示形式が切り替わるため、「汎用」と呼ばれます。通常、大きな数値や非常に小さな数値では%eが選ばれ、中程度の数値では%fが選ばれます。この切り替えの閾値は実装によって定義されます。

浮動小数点数と精度

コンピュータにおける浮動小数点数は、IEEE 754規格に基づいて表現されることが一般的です。これは、数値を仮数部と指数部に分けて表現することで、非常に広い範囲の数値を表現できるようにするものです。しかし、すべての実数を正確に表現できるわけではなく、丸め誤差が発生する可能性があります。

%gのような汎用フォーマットは、これらの特性を考慮し、数値の有効桁数を最大限に活かしつつ、人間にとって読みやすい形式を提供しようとします。

技術的詳細

このコミットの技術的詳細は、fmtパッケージの%gフォーマット指定子が、特定の浮動小数点数値に対して、いつ固定小数点形式(%f)から指数形式(%e)に切り替わるかの内部ロジックが変更されたことにあります。

変更前の挙動では、1234.5678e3(つまり 1,234,567.8)という数値が%gでフォーマットされた際に、"1234567.8"という固定小数点形式で出力されていました。これは、%gが内部的に、数値の絶対値が特定の範囲内にある場合に%fを選択し、それ以外の場合に%eを選択するというルールに基づいています。

このコミットによって、1234.5678e3という数値に対しては、%g"1.2345678e+06"という指数形式を選択するように変更されました。これは、%gの内部的な切り替え閾値が調整されたか、または特定の数値の丸め処理や表現方法に関するロジックが変更されたことを意味します。

一般的に、%gは以下のルールに従って%fまたは%eを選択します(これは一般的な挙動であり、Goの特定のバージョンや実装によって微調整される可能性があります):

  • 数値の絶対値が非常に小さい(例: 1e-4未満)場合や、非常に大きい(例: 1e+6以上)場合、%eが選択される傾向があります。
  • それ以外の、中程度の絶対値を持つ数値の場合、%fが選択される傾向があります。

今回の変更は、1,234,567.8という数値が、新しいルールでは「非常に大きい」と判断され、指数形式がより適切であると見なされたことを示しています。指数形式は、大きな数値をよりコンパクトに表現し、有効数字を明確にする利点があります。

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

変更はtest/fmt_test.goというテストファイルにのみ行われています。これは、fmtパッケージ自体の実装ではなく、その挙動を検証するテストの期待値が変更されたことを意味します。

--- a/test/fmt_test.go
+++ b/test/fmt_test.go
@@ -52,7 +52,7 @@ func main() {
 	E(f.s("\tf   ").f64(1234.5678e-8), "\tf   0.000012");
 	E(f.s("\tf   ").f64(-7.0), "\tf   -7.000000");
 	E(f.s("\tf   ").f64(-1e-9), "\tf   -0.000000");
-	E(f.s("\tg   ").g64(1234.5678e3), "\tg   1234567.8");
+	E(f.s("\tg   ").g64(1234.5678e3), "\tg   1.2345678e+06");
 	E(f.s("\tg   ").g64(1234.5678e-8), "\tg   1.2345678e-05");
 	E(f.s("\tg   ").g64(-7.0), "\tg   -7");
 	E(f.s("\tg   ").g64(-1e-9), "\tg   -1e-09");

コアとなるコードの解説

この変更は、test/fmt_test.goファイル内のmain関数の一部です。このテストファイルは、fmtパッケージの様々なフォーマット指定子の挙動を検証するために使用されます。

変更された行は以下の通りです。

-	E(f.s("\tg   ").g64(1234.5678e3), "\tg   1234567.8");
+	E(f.s("\tg   ").g64(1234.5678e3), "\tg   1.2345678e+06");
  • E(...) は、おそらくテストフレームワークの一部であり、第一引数と第二引数が等しいことを検証する関数です。
  • f.s("\tg ") は、フォーマット文字列の一部を構築していると考えられます。ここでは、タブ文字と文字列"g "が追加されています。
  • g64(1234.5678e3) は、1234.5678e3(つまり 1,234,567.8)というfloat64型の数値を%gフォーマットで整形した結果を生成する関数呼び出しです。
  • 変更前の期待値は "\tg 1234567.8" でした。これは、1,234,567.8が固定小数点形式で出力されることを期待していました。
  • 変更後の期待値は "\tg 1.2345678e+06" です。これは、同じ数値が指数形式(科学的記数法)で出力されることを期待しています。

このテストの変更は、fmtパッケージの内部的な%gフォーマットロジックが変更され、1234.5678e3という数値に対しては、もはや固定小数点形式ではなく、指数形式が選択されるようになったことを明確に示しています。これは、fmtパッケージの浮動小数点数フォーマットの挙動が、より大きな数値に対しては指数形式を優先するように調整されたことを意味します。

関連リンク

  • Go言語のfmtパッケージ公式ドキュメント: https://pkg.go.dev/fmt (このコミットが作成された2008年時点のドキュメントは直接参照できませんが、現在のドキュメントで%gの挙動を確認できます。)

参考にした情報源リンク

  • Go言語のfmtパッケージの挙動に関する一般的な知識
  • 浮動小数点数の表現に関する一般的な知識
  • Gitコミットログの解析
  • Go言語のテストコードの読み方