[インデックス 17599] ファイルの概要
このコミットは、Go言語の標準ライブラリであるfmt
パッケージにおいて、complex64
およびcomplex128
型の値に対する%b
フォーマット動詞のサポートを追加するものです。これにより、複素数型の実部と虚部をIEEE 754のバイナリ表現(指数部と仮数部)で出力できるようになります。
コミット
commit 89dacb9cca0a27da1efe0578cd0881b80b13ed45
Author: Rob Pike <r@golang.org>
Date: Sun Sep 15 10:45:36 2013 +1000
fmt: %b for complex64 and complex128
Just an oversight they were missing.
Fixes #6387
R=golang-dev, dominik.honnef, rsc
CC=golang-dev
https://golang.org/cl/13715043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/89dacb9cca0a27da1efe0578cd0881b80b13ed45
元コミット内容
fmt: %b for complex64 and complex128
Just an oversight they were missing.
Fixes #6387
このコミットは、fmt
パッケージにおいて、complex64
型とcomplex128
型の値に対して%b
フォーマット動詞が欠落していたのを修正するものです。これは単なる見落としであったと説明されています。関連するIssueは#6387
です。
変更の背景
Go言語のfmt
パッケージは、様々なデータ型を整形して出力するための機能を提供します。Printf
関数などで使用されるフォーマット動詞は、数値、文字列、ブール値など、多様な型に対応しています。浮動小数点数型(float32
, float64
)に対しては、以前から%b
フォーマット動詞がサポートされており、これは数値をIEEE 754標準に基づくバイナリ表現(指数部と仮数部)で出力する機能を提供していました。
しかし、複素数型(complex64
, complex128
)については、その実部と虚部がそれぞれ浮動小数点数であるにもかかわらず、%b
フォーマット動詞がサポートされていませんでした。これは、一貫性の観点からも、またデバッグや低レベルな数値表現の確認が必要な場面においても不便でした。このコミットは、この機能の欠落が単なる「見落とし (oversight)」であったと認識され、その修正が行われたものです。Issue #6387
がこの問題の報告と修正のきっかけとなりました。
前提知識の解説
Go言語のfmt
パッケージ
fmt
パッケージは、Go言語におけるフォーマットI/Oを実装するためのパッケージです。C言語のprintf
やscanf
に似た機能を提供し、様々なデータ型を文字列に変換したり、文字列からデータを解析したりするのに使われます。
Printf
関数: 指定されたフォーマット文字列に従って値を整形し、標準出力に出力します。- フォーマット動詞: フォーマット文字列内で使用される特殊な記号で、値の型や表示形式を指定します。例えば、
%d
は整数、%s
は文字列、%f
は浮動小数点数を表します。
%b
フォーマット動詞
%b
フォーマット動詞は、浮動小数点数を「指数表記のバイナリ表現」で出力するために使用されます。具体的には、IEEE 754浮動小数点数標準における仮数部と指数部を基にした形式で表示されます。
例:
1.0
(float64) は4503599627370496p-52
と表示されます。4503599627370496
は仮数部(mantissa)を整数として表現したものです。p-52
は2の指数部(exponent)を表し、2^-52
を意味します。- これは
4503599627370496 * 2^-52
が1.0
に等しいことを示しています。
IEEE 754浮動小数点数標準
IEEE 754は、浮動小数点数のコンピュータ上での表現方法に関する国際標準です。この標準は、単精度(32ビット、float32
に相当)と倍精度(64ビット、float64
に相当)の形式を定義しており、それぞれ符号ビット、指数部、仮数部から構成されます。
- 符号ビット (Sign bit): 数の正負を表します(0が正、1が負)。
- 指数部 (Exponent): 2のべき乗の指数を表します。バイアス形式で格納されます。
- 仮数部 (Mantissa/Significand): 有効数字を表します。通常、正規化された形式では先頭の1ビットは省略されます(隠しビット)。
%b
フォーマットは、このIEEE 754の内部表現を人間が読める形式で出力する際に非常に有用です。
Go言語の複素数型
Go言語には、複素数を扱うための組み込み型があります。
complex64
:float32
の実部と虚部を持つ複素数型です。complex128
:float64
の実部と虚部を持つ複素数型です。
複素数は real + imag * i
の形式で表され、real
とimag
はそれぞれ浮動小数点数です。
技術的詳細
このコミットの技術的な核心は、fmt
パッケージが複素数型をどのように処理し、%b
フォーマット動詞をどのように適用するかという点にあります。
fmt
パッケージの内部では、pp
(printer) 構造体がフォーマット処理を担当し、fmt
構造体が具体的なフォーマットロジックをカプセル化しています。複素数型をフォーマットする際には、その実部と虚部を個別に浮動小数点数として抽出し、それぞれの部分に対して適切なフォーマット処理を適用する必要があります。
変更前は、complex64
とcomplex128
のフォーマット処理において、%e
, %E
, %f
, %F
, %g
, %G
といった一般的な浮動小数点数フォーマット動詞のみがサポートされていました。%b
はリストに含まれていませんでした。
このコミットでは、以下の変更が行われました。
fmt_c64
およびfmt_c128
メソッドの更新: これらのメソッドは、それぞれcomplex64
とcomplex128
のフォーマット処理を担当します。内部で実部と虚部を抽出し、それぞれの部分に対して指定されたフォーマット動詞を適用します。今回の変更では、switch verb
文に'b'
ケースが追加され、実部と虚部をfmt_fb32
(float32
用)またはfmt_fb64
(float64
用)でフォーマットするように指示しています。fmtComplex64
およびfmtComplex128
関数の更新: これらの関数は、pp
構造体から呼び出され、特定のフォーマット動詞が複素数型に適用可能かどうかを判断します。変更前は%b
が許可されていませんでしたが、今回の変更で'b'
が許可されるフォーマット動詞のリストに追加されました。
これにより、fmt.Printf("%b", complex(1, 2))
のような呼び出しがあった場合、fmt
パッケージは複素数の実部(1)と虚部(2)をそれぞれ浮動小数点数として抽出し、それらを個別に%b
フォーマットで処理し、最終的に(実部の%b表現 + 虚部の%b表現i)
のような形式で出力するようになります。
コアとなるコードの変更箇所
このコミットでは、主に以下の3つのファイルが変更されています。
src/pkg/fmt/fmt_test.go
: 新しい機能のテストケースが追加されています。src/pkg/fmt/format.go
: 複素数型のフォーマットロジックが変更されています。src/pkg/fmt/print.go
: 複素数型に対する%b
フォーマット動詞の許可が追加されています。
src/pkg/fmt/fmt_test.go
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -227,6 +227,8 @@ var fmtTests = []struct {
{"%+.3g", -1.0, "-1"},
{"% .3g", -1.0, "-1"},
{"% .3g", 1.0, " 1"},
+ {"%b", float32(1.0), "8388608p-23"},
+ {"%b", 1.0, "4503599627370496p-52"},
// complex values
{"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"},
@@ -247,6 +249,8 @@ var fmtTests = []struct {
{"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"},
{"%+.3g", complex64(1 + 2i), "(+1+2i)"},
{"%+.3g", complex128(1 + 2i), "(+1+2i)"},
+ {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"},
+ {"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"},
// erroneous formats
{"", 2, "%!(EXTRA int=2)"},
src/pkg/fmt/format.go
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -429,6 +429,8 @@ func (f *fmt) fmt_c64(v complex64, verb rune) {
oldPlus := f.plus
for i := 0; ; i++ {
switch verb {
+ case 'b':
+ f.fmt_fb32(r)
case 'e':
f.fmt_e32(r)
case 'E':
@@ -457,6 +459,8 @@ func (f *fmt) fmt_c128(v complex128, verb rune) {
oldPlus := f.plus
for i := 0; ; i++ {
switch verb {
+ case 'b':
+ f.fmt_fb64(r)
case 'e':
f.fmt_e64(r)
case 'E':
src/pkg/fmt/print.go
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -511,7 +511,7 @@ func (p *pp) fmtFloat64(v float64, verb rune) {
func (p *pp) fmtComplex64(v complex64, verb rune) {
switch verb {
- case 'e', 'E', 'f', 'F', 'g', 'G':
+ case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c64(v, verb)
case 'v':
p.fmt.fmt_c64(v, 'g')
@@ -522,7 +522,7 @@ func (p *pp) fmtComplex64(v complex64, verb rune) {
func (p *pp) fmtComplex128(v complex128, verb rune) {
switch verb {
- case 'e', 'E', 'f', 'F', 'g', 'G':
+ case 'b', 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c128(v, verb)
case 'v':
p.fmt.fmt_c128(v, 'g')
コアとなるコードの解説
src/pkg/fmt/fmt_test.go
このファイルでは、fmtTests
というテストケースのスライスに新しいエントリが追加されています。
{"%b", float32(1.0), "8388608p-23"}
:float32
の1.0
が%b
で正しくフォーマットされることを確認します。{"%b", 1.0, "4503599627370496p-52"}
:float64
の1.0
が%b
で正しくフォーマットされることを確認します。{"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"}
:complex64
の1+2i
が%b
で正しくフォーマットされることを確認します。実部と虚部がそれぞれfloat32
として%b
フォーマットされます。{"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}
:complex128
の1+2i
が%b
で正しくフォーマットされることを確認します。実部と虚部がそれぞれfloat64
として%b
フォーマットされます。
これらのテストケースは、変更が期待通りに動作し、既存の%b
フォーマットの動作も維持されていることを保証します。
src/pkg/fmt/format.go
このファイルには、fmt
構造体のfmt_c64
とfmt_c128
メソッドが含まれています。これらは、それぞれcomplex64
とcomplex128
の具体的なフォーマットロジックを処理します。
func (f *fmt) fmt_c64(v complex64, verb rune)
:switch verb
文にcase 'b':
が追加されました。- このケースでは、
f.fmt_fb32(r)
が呼び出されます。r
はcomplex64
の実部または虚部(float32
型)です。fmt_fb32
はfloat32
を%b
形式でフォーマットするための内部関数です。
func (f *fmt) fmt_c128(v complex128, verb rune)
:- 同様に、
switch verb
文にcase 'b':
が追加されました。 - このケースでは、
f.fmt_fb64(r)
が呼び出されます。r
はcomplex128
の実部または虚部(float64
型)です。fmt_fb64
はfloat64
を%b
形式でフォーマットするための内部関数です。
- 同様に、
これらの変更により、fmt
パッケージは複素数の実部と虚部を個別に抽出し、それぞれを対応する浮動小数点数型の%b
フォーマットロジックに渡すことができるようになりました。
src/pkg/fmt/print.go
このファイルには、pp
構造体のfmtComplex64
とfmtComplex128
関数が含まれています。これらは、Printf
のような高レベルの関数から呼び出され、与えられた複素数型とフォーマット動詞に基づいて、適切なフォーマット処理をディスパッチします。
func (p *pp) fmtComplex64(v complex64, verb rune)
:switch verb
文のcase
リストに'b'
が追加されました。- これにより、
complex64
型に対して%b
フォーマット動詞が指定された場合、p.fmt.fmt_c64(v, verb)
が呼び出されるようになります。
func (p *pp) fmtComplex128(v complex128, verb rune)
:- 同様に、
switch verb
文のcase
リストに'b'
が追加されました。 - これにより、
complex128
型に対して%b
フォーマット動詞が指定された場合、p.fmt.fmt_c128(v, verb)
が呼び出されるようになります。
- 同様に、
これらの変更は、%b
フォーマット動詞が複素数型に対して「有効な」動詞として認識されるようにするためのものです。これにより、fmt
パッケージは複素数型と%b
動詞の組み合わせを正しく処理できるようになります。
関連リンク
- Go言語の
fmt
パッケージのドキュメント: https://pkg.go.dev/fmt - Go言語のIssue #6387: https://github.com/golang/go/issues/6387
- IEEE 754浮動小数点数標準 (Wikipedia): https://ja.wikipedia.org/wiki/IEEE_754
参考にした情報源リンク
- Go言語の公式ドキュメント
- GitHubのgolang/goリポジトリのコミット履歴とIssueトラッカー
- IEEE 754に関する一般的な情報源(Wikipediaなど)