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

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

このコミットは、Go言語の標準ライブラリである math/big パッケージに、Rat 型と Int 型の SetString メソッドおよび Scan メソッドの使用例を追加するものです。具体的には、src/pkg/math/big/example_test.go という新しいテストファイルが作成され、これらのメソッドの具体的な利用方法が示されています。

コミット

commit ddd67f2ecd1c100c48563addf4293bfe6dc7535f
Author: Andrew Gerrand <adg@golang.org>
Date:   Wed Jan 25 10:29:44 2012 +1100

    math/big: add examples for Rat and Int's SetString and Scan methods
    
    R=golang-dev, bradfitz, rsc, r, gri, r
    CC=golang-dev
    https://golang.org/cl/5543047

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

https://github.com/golang/go/commit/ddd67f2ecd1c100c48563addf4293bfe6dc7535f

元コミット内容

math/big: add examples for Rat and Int's SetString and Scan methods

R=golang-dev, bradfitz, rsc, r, gri, r
CC=golang-dev
https://golang.org/cl/5543047

変更の背景

Go言語の math/big パッケージは、任意精度(arbitrary-precision)の整数、有理数、浮動小数点数を扱うための機能を提供します。これらの型は、標準のGoの数値型(int, float64など)では表現できない非常に大きな数値や、精度が要求される計算に用いられます。

SetString メソッドは、文字列形式で表現された数値を対応する big.Intbig.Rat オブジェクトにパースして設定するために使用されます。一方、Scan メソッドは、fmt パッケージの Scanner インターフェースを実装しており、fmt.Scanfmt.Sscan などの関数を通じて、入力ストリームから数値を読み込む際に利用されます。

このコミットが作成された背景には、これらの重要なメソッドの利用方法を開発者により明確に示す必要があったことが考えられます。特に、Scan メソッドは fmt パッケージとの連携において暗黙的に呼び出されることが多いため、その動作を例示することは、ライブラリの使いやすさを向上させる上で非常に有効です。公式の例は、ドキュメントだけでは伝わりにくい具体的なコードの書き方や、エッジケースの扱い方を理解するのに役立ちます。

前提知識の解説

任意精度演算 (Arbitrary-Precision Arithmetic)

通常のプログラミング言語における数値型(例: Goの int64, float64)は、固定されたビット数で数値を表現します。これにより、表現できる数値の範囲や精度には限界があります。例えば、int64 は約9.22 × 10^18 までの整数しか扱えず、float64 は約15桁の精度しか保証しません。

これに対し、任意精度演算は、必要に応じてメモリを動的に割り当てることで、理論上は無限の桁数や精度を持つ数値を扱うことができます。Goの math/big パッケージは、この任意精度演算をGo言語で実現するための機能を提供します。

  • big.Int: 任意精度の整数を扱います。非常に大きな数値を正確に計算する場合に利用されます。
  • big.Rat: 任意精度の有理数(分数)を扱います。numerator/denominator の形式で数値を表現し、浮動小数点数で発生する丸め誤差なしに正確な分数計算を行うことができます。

fmt.Scanner インターフェース

Go言語の fmt パッケージは、フォーマットされた入出力(printf/scanfスタイル)を提供します。fmt.Scan, fmt.Sscan, fmt.Fscan などの関数は、入力から値を読み取るために使用されます。これらの関数は、読み取る型が fmt.Scanner インターフェースを実装している場合、その Scan メソッドを自動的に呼び出します。

fmt.Scanner インターフェースは以下のように定義されています。

type Scanner interface {
    Scan(state fmt.ScanState, verb rune) error
}

Scan メソッドは、入力ストリームからデータを読み取り、それ自身(レシーバ)にその値を設定する責任を持ちます。math/big パッケージの Int および Rat 型がこのインターフェースを実装しているため、fmt パッケージの走査関数を通じてこれらの型の値を直接読み込むことが可能になります。

SetString メソッド

SetString メソッドは、文字列形式で表現された数値をパースし、その値を big.Int または big.Rat オブジェクトに設定するために使用されます。

  • (*Int).SetString(s string, base int):
    • s: 数値を表す文字列。
    • base: 数値の基数(2から62まで)。例えば、10進数の場合は 10、8進数の場合は 8、16進数の場合は 16 を指定します。base0 の場合、文字列のプレフィックス(0x は16進数、0 は8進数)に基づいて基数を自動的に推測します。
  • (*Rat).SetString(s string):
    • s: 有理数を表す文字列。"numerator/denominator" の形式(例: "3/2")または浮動小数点数形式(例: "1.5")で指定できます。

これらのメソッドは、文字列から数値オブジェクトへの変換という、任意精度演算において非常に基本的な操作を提供します。

技術的詳細

このコミットは、Goのテストフレームワークにおける「Example」関数を利用しています。Goの go test コマンドは、Example というプレフィックスを持つ関数を特別に扱います。これらの関数は、通常のテスト関数と同様に実行されますが、その標準出力(fmt.Println など)がキャプチャされ、関数のコメントブロックに記述された期待される出力と比較されます。これにより、コードの動作例が常に最新かつ正確であることを保証し、同時にドキュメントとしても機能します。

example_test.go ファイルは、Goのパッケージのテストファイル命名規則に従っています。_test.go サフィックスを持つファイルは、テストコードを含むことを示し、package big_test のように _test サフィックスを付けることで、テスト対象のパッケージとは別のパッケージとしてテストを実行し、外部から見えるAPIのみをテストすることを保証します。

追加された例は以下の通りです。

  1. ExampleRat_SetString:
    • big.Rat 型のインスタンスを作成し、SetString("355/113") を呼び出して円周率の近似値(355/113)を設定します。
    • FloatString(3) を使用して、結果を小数点以下3桁の浮動小数点数として出力します。これは、有理数を浮動小数点数として表示する際の丸め処理を示しています。
  2. ExampleInt_SetString:
    • big.Int 型のインスタンスを作成し、SetString("644", 8) を呼び出して8進数文字列 "644" を整数に変換します。
    • 結果をそのまま出力し、8進数 "644" が10進数で何になるか(420)を示します。
  3. ExampleRat_Scan:
    • big.Rat 型のインスタンスを作成します。
    • fmt.Sscan("1.5000", r) を使用して、文字列 "1.5000" から有理数を読み込みます。
    • Scan メソッドが fmt.Scanner インターフェースの実装としてどのように機能するかを示します。エラーハンドリングも含まれています。
  4. ExampleInt_Scan:
    • big.Int 型のインスタンスを作成します。
    • fmt.Sscan("18446744073709551617", i) を使用して、非常に大きな整数を文字列から読み込みます。
    • Scan メソッドが fmt.Scanner インターフェースの実装として、大きな整数をどのように処理するかを示します。

これらの例は、math/big パッケージの基本的な使い方を網羅しており、特に文字列との相互変換の重要性を示しています。

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

このコミットで追加されたファイルは src/pkg/math/big/example_test.go のみです。

--- /dev/null
+++ b/src/pkg/math/big/example_test.go
@@ -0,0 +1,51 @@
+// 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.
+
+package big_test
+
+import (
+	"fmt"
+	"log"
+	"math/big"
+)
+
+// 3.142
+func ExampleRat_SetString() {
+	r := new(big.Rat)
+	r.SetString("355/113")
+	fmt.Println(r.FloatString(3))
+}
+
+// 420
+func ExampleInt_SetString() {
+	i := new(big.Int)
+	i.SetString("644", 8) // octal
+	fmt.Println(i)
+}
+
+// 3/2
+func ExampleRat_Scan() {
+	// The Scan function is rarely used directly;
+	// the fmt package recognizes it as an implementation of fmt.Scanner.
+	r := new(big.Rat)
+	_, err := fmt.Sscan("1.5000", r)
+	if err != nil {
+		log.Println("error scanning value:", err)
+	} else {
+		fmt.Println(r)
+	}
+}
+
+// 18446744073709551617
+func ExampleInt_Scan() {
+	// The Scan function is rarely used directly;
+	// the fmt package recognizes it as an implementation of fmt.Scanner.
+	i := new(big.Int)
+	_, err := fmt.Sscan("18446744073709551617", i)
+	if err != nil {
+		log.Println("error scanning value:", err)
+	} else {
+		fmt.Println(i)
+	}
+}

コアとなるコードの解説

追加された example_test.go ファイルは、math/big パッケージの RatInt 型の SetString および Scan メソッドの具体的な使用例を、GoのExampleテスト形式で提供しています。

ExampleRat_SetString()

この関数は big.Rat 型の SetString メソッドの基本的な使い方を示しています。

  1. r := new(big.Rat): 新しい big.Rat オブジェクトを初期化します。new を使うことで、ポインタが返され、メソッド呼び出しでそのオブジェクトの状態を変更できます。
  2. r.SetString("355/113"): 文字列 "355/113" をパースし、r に有理数として設定します。これは円周率の近似値として知られる分数です。
  3. fmt.Println(r.FloatString(3)): Rat 型の値を浮動小数点数として表示します。FloatString(3) は、小数点以下3桁までで文字列を生成します。これにより、3.142 という出力が得られます。

ExampleInt_SetString()

この関数は big.Int 型の SetString メソッドの基本的な使い方を示しています。

  1. i := new(big.Int): 新しい big.Int オブジェクトを初期化します。
  2. i.SetString("644", 8): 文字列 "644" を基数8(8進数)としてパースし、i に整数として設定します。8進数の 644 は10進数で 6*8^2 + 4*8^1 + 4*8^0 = 6*64 + 4*8 + 4*1 = 384 + 32 + 4 = 420 となります。
  3. fmt.Println(i): Int 型の値をそのまま出力します。これにより、420 という出力が得られます。

ExampleRat_Scan()

この関数は big.Rat 型が fmt.Scanner インターフェースをどのように実装しているかを示します。

  1. r := new(big.Rat): 新しい big.Rat オブジェクトを初期化します。
  2. _, err := fmt.Sscan("1.5000", r): fmt.Sscan は文字列から値を読み取る関数です。rfmt.Scanner インターフェースを実装しているため、fmt.Sscan は内部的に r.Scan() メソッドを呼び出し、文字列 "1.5000" をパースして r に設定します。
  3. エラーハンドリング: fmt.Sscan がエラーを返した場合(例: 無効な入力形式)、log.Println でエラーメッセージを出力します。
  4. fmt.Println(r): 正常にスキャンされた Rat の値を出力します。1.50003/2 として表現されます。

ExampleInt_Scan()

この関数は big.Int 型が fmt.Scanner インターフェースをどのように実装しているかを示します。

  1. i := new(big.Int): 新しい big.Int オブジェクトを初期化します。
  2. _, err := fmt.Sscan("18446744073709551617", i): fmt.Sscan を使用して、非常に大きな整数を表す文字列を i に読み込みます。この数値は uint64 の最大値 18446744073709551615 をわずかに超える値であり、標準の int64uint64 では正確に表現できないことを示唆しています。big.Int は任意精度であるため、このような大きな数値も正確に扱えます。
  3. エラーハンドリング: fmt.Sscan がエラーを返した場合、エラーメッセージを出力します。
  4. fmt.Println(i): 正常にスキャンされた Int の値を出力します。

これらの例は、math/big パッケージの SetStringScan メソッドが、文字列と任意精度数値の間でどのように変換を行うか、そして fmt パッケージとの統合がどのように機能するかを明確に示しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント (pkg.go.dev)
  • Go言語のGitHubリポジトリ (github.com/golang/go)
  • Go言語のExampleテストに関する一般的な情報源 (例: Go言語のブログ、技術記事)
  • 任意精度演算に関する一般的な知識