Go言語 big.Rat 型とは?SetInt() を中心とした入門ガイド

2025-06-01

big.Rat.SetInt() は、Go の math/big パッケージで提供されている、有理数 (分数) を扱うための型である big.Rat のメソッドの一つです。このメソッドは、与えられた整数値を big.Rat 型の変数に設定するために使用されます。

具体的には、以下のような処理を行います。

  1. 引数として big.Int 型の値を受け取ります。 これは、設定したい整数値を表す big.Int 型のポインタです。
  2. レシーバ (big.Rat 型の変数) の値を、受け取った big.Int 型の値を持つ有理数として設定します。 このとき、分母は暗黙的に 1 となります。つまり、整数は分母が 1 の分数として表現されるわけです。

コード例で見てみましょう。

package main

import (
	"fmt"
	"math/big"
)

func main() {
	// big.Rat 型の変数を宣言します。
	r := new(big.Rat)

	// 設定したい整数値を big.Int 型で作成します。
	integerValue := big.NewInt(123)

	// SetInt() メソッドを使って、r に integerValue を設定します。
	r.SetInt(integerValue)

	// 設定された r の値を出力します。
	fmt.Println(r.String()) // Output: 123/1

	// 別の整数値を設定してみましょう。
	anotherIntegerValue := big.NewInt(-45)
	r.SetInt(anotherIntegerValue)
	fmt.Println(r.String()) // Output: -45/1
}

この例では、以下の処理が行われています。

  1. r := new(big.Rat) で、新しい big.Rat 型の変数 r を作成しています。
  2. integerValue := big.NewInt(123) で、値が 123 の big.Int 型の変数 integerValue を作成しています。
  3. r.SetInt(integerValue) で、r の値を integerValue (123) を分子、1 を分母とする有理数として設定しています。r.String() は、big.Rat の値を "分子/分母" の形式の文字列で返します。
  4. 同様に、-45 という整数値を持つ big.Int 型の変数を SetInt()r に設定し、その結果を出力しています。
  • 有理数の計算を行う際に、初期値として整数を設定したい場合。
  • big.Int 型の整数値を big.Rat 型の変数に簡単に変換したい場合。


  1. 引数の型の間違い

    • big.Rat.SetInt() の引数は *big.Int 型である必要があります。もし、通常の int 型の変数や、他の型(例えば string)を直接渡すと、コンパイルエラーが発生します。
    • エラー例
      package main
      
      import (
          "fmt"
          "math/big"
      )
      
      func main() {
          r := new(big.Rat)
          intValue := 123 // int 型の変数
          // r.SetInt(intValue) // コンパイルエラー: cannot use intValue (variable of type int) as *big.Int value in argument to r.SetInt
          bigIntValue := big.NewInt(intValue)
          r.SetInt(bigIntValue) // 正しい使い方
          fmt.Println(r.String())
      }
      
    • トラブルシューティング
      引数が *big.Int 型であることを確認し、必要であれば big.NewInt() 関数を使って int 型の値を *big.Int 型に変換してください。
  2. big.Rat 型の変数の初期化忘れ

    • big.Rat 型の変数は、new(big.Rat) でポインタとして初期化するか、または big.Rat{} のようにゼロ値で初期化する必要があります。初期化せずに使用しようとすると、予期せぬ動作やパニックを引き起こす可能性があります。
    • 注意点
      SetInt() はレシーバ (r in r.SetInt()) の値を変更するメソッドです。nil ポインタに対してこのメソッドを呼び出すと、ランタイムエラーが発生します。
    • エラー例
      package main
      
      import (
          "fmt"
          "math/big"
      )
      
      func main() {
          var r *big.Rat // 初期化していないポインタ
          integerValue := big.NewInt(123)
          // r.SetInt(integerValue) // ランタイムエラー: panic: runtime error: invalid memory address or nil pointer dereference
          r = new(big.Rat) // 正しい初期化
          r.SetInt(integerValue)
          fmt.Println(r.String())
      }
      
    • トラブルシューティング
      big.Rat 型の変数を使用する前に、必ず new(big.Rat) で初期化するか、ゼロ値で宣言していることを確認してください。
  3. 意図しない値の設定

    • SetInt() は与えられた big.Int の値をそのまま設定します。もし、何らかの計算結果を big.Rat に設定したい場合は、SetInt() ではなく、他の big.Rat のメソッド(例えば SetFrac() など)を検討する必要があります。
    • トラブルシューティング
      設定したい値が本当に整数値であるか、それとも分数であるべきかを再確認し、適切なメソッドを使用してください。
  4. big.Int 型の変数の変更による影響

    • SetInt() に渡した big.Int 型の変数を後で変更しても、big.Rat 型の変数の値は自動的に更新されません。big.RatSetInt() が呼び出された時点での big.Int の値をコピーして保持します。

    • package main
      
      import (
          "fmt"
          "math/big"
      )
      
      func main() {
          integerValue := big.NewInt(10)
          r := new(big.Rat)
          r.SetInt(integerValue)
          fmt.Println("初期値:", r.String()) // Output: 初期値: 10/1
      
          integerValue.SetInt64(20) // integerValue の値を変更
          fmt.Println("integerValue変更後:", r.String()) // Output: integerValue変更後: 10/1 (r の値は変わらない)
      }
      
    • トラブルシューティング
      big.Int の値を変更した後に big.Rat の値を更新したい場合は、再度 SetInt() を呼び出す必要があります。


例1: 整数の基本的な設定

package main

import (
	"fmt"
	"math/big"
)

func main() {
	// 新しい big.Rat 型の変数を生成します。
	r := new(big.Rat)

	// 設定したい整数値を big.Int 型で作成します。
	integerValue := big.NewInt(150)

	// SetInt() メソッドを使って、r に integerValue を設定します。
	r.SetInt(integerValue)

	// 設定された r の値を文字列として出力します (分子/分母の形式)。
	fmt.Println("r の値:", r.String()) // Output: r の値: 150/1
}

この例では、整数値 150big.Int 型で作成し、SetInt() メソッドを使って big.Rat 型の変数 r に設定しています。出力結果からわかるように、整数は分母が 1 の分数として表現されます。

例2: 複数の整数の設定と表示

複数の big.Rat 変数に異なる整数値を設定し、それらの値を表示する例です。

package main

import (
	"fmt"
	"math/big"
)

func main() {
	r1 := new(big.Rat)
	int1 := big.NewInt(100)
	r1.SetInt(int1)
	fmt.Println("r1 の値:", r1.String()) // Output: r1 の値: 100/1

	r2 := new(big.Rat)
	int2 := big.NewInt(-50)
	r2.SetInt(int2)
	fmt.Println("r2 の値:", r2.String()) // Output: r2 の値: -50/1

	r3 := new(big.Rat)
	int3 := big.NewInt(0)
	r3.SetInt(int3)
	fmt.Println("r3 の値:", r3.String()) // Output: r3 の値: 0/1
}

この例では、正の整数、負の整数、そしてゼロをそれぞれ big.Int 型で作成し、異なる big.Rat 変数に設定しています。

例3: 関数内で SetInt() を使用する

関数内で big.Rat 変数を作成し、SetInt() を使って値を設定して返す例です。

package main

import (
	"fmt"
	"math/big"
)

// 整数値を受け取り、その値を設定した big.Rat を返す関数
func createBigRatFromInt(val int64) *big.Rat {
	r := new(big.Rat)
	intValue := big.NewInt(val)
	r.SetInt(intValue)
	return r
}

func main() {
	rat1 := createBigRatFromInt(25)
	fmt.Println("rat1 の値:", rat1.String()) // Output: rat1 の値: 25/1

	rat2 := createBigRatFromInt(-75)
	fmt.Println("rat2 の値:", rat2.String()) // Output: rat2 の値: -75/1
}

この例では、createBigRatFromInt 関数が int64 型の引数を受け取り、その値を big.Int に変換した後、SetInt() を使って big.Rat に設定して返します。

例4: 構造体の中で big.Rat を使用し、SetInt() で初期化する

構造体のフィールドとして big.Rat を持ち、そのフィールドを SetInt() で初期化する例です。

package main

import (
	"fmt"
	"math/big"
)

// データ構造体
type MyData struct {
	Value *big.Rat
	Name  string
}

func main() {
	data := MyData{
		Value: new(big.Rat),
		Name:  "データ1",
	}

	intValue := big.NewInt(200)
	data.Value.SetInt(intValue)

	fmt.Printf("%s の値: %s\n", data.Name, data.Value.String()) // Output: データ1 の値: 200/1
}

この例では、MyData 構造体が *big.Rat 型の Value フィールドを持っています。main 関数内で MyData のインスタンスを作成し、その Value フィールドに対して SetInt() を使って整数値を設定しています。



代替メソッド

    • big.NewRat() 関数は、与えられた分子 (a) と分母 (b) を持つ新しい big.Rat を生成します。整数値を big.Rat に設定する場合、分母を常に 1 にすることで SetInt() と同じ結果を得られます。
    • コード例
      package main
      
      import (
          "fmt"
          "math/big"
      )
      
      func main() {
          intValue := int64(123)
          r := big.NewRat(intValue, 1) // 分子に整数、分母に 1 を指定
          fmt.Println(r.String())      // Output: 123/1
      
          negativeIntValue := int64(-45)
          r2 := big.NewRat(negativeIntValue, 1)
          fmt.Println(r2.String())     // Output: -45/1
      }
      
    • 利点
      big.Int 型の変数を明示的に作成する必要がないため、コードが少し簡潔になる場合があります。特に、直接的な整数リテラルから big.Rat を作成したい場合に便利です。
    • 注意点
      引数は int64 型です。もし int 型の変数を使用する場合は、明示的な型変換が必要です。
  1. big.Rat.SetFloat64(f float64) を使用する (精度に注意)

    • big.Rat は有理数を正確に表現できますが、float64 は浮動小数点数であり、内部的には近似値で表現されます。SetFloat64() を使用すると、float64 の近似値を可能な限り正確な有理数として big.Rat に設定します。
    • コード例
      package main
      
      import (
          "fmt"
          "math/big"
      )
      
      func main() {
          floatValue := 150.0
          r := new(big.Rat)
          err := r.SetFloat64(floatValue)
          if err != nil {
              fmt.Println("SetFloat64 エラー:", err)
              return
          }
          fmt.Println(r.String()) // Output: 150/1
      
          anotherFloatValue := -25.0
          r2 := new(big.Rat)
          err = r2.SetFloat64(anotherFloatValue)
          if err != nil {
              fmt.Println("SetFloat64 エラー:", err)
              return
          }
          fmt.Println(r2.String()) // Output: -25/1
      }
      
    • 利点
      float64 型の変数から直接 big.Rat を作成できます。
    • 注意点
      浮動小数点数の性質上、完全に正確な有理数表現が得られない場合があります。特に、循環小数などを float64 で表現しようとすると、近似値が設定されることになります。整数値を設定する場合でも、内部的には浮動小数点数を経由するため、わずかな誤差が生じる可能性は否定できません。エラーハンドリングも必要です。
  2. big.Rat.SetString(s string) を使用する

    • SetString() メソッドは、文字列を解析して big.Rat の値を設定します。整数を表す文字列(例: "123", "-45", "0")を渡すことで、SetInt() と同様の結果を得られます。
    • コード例
      package main
      
      import (
          "fmt"
          "math/big"
      )
      
      func main() {
          stringValue := "200"
          r := new(big.Rat)
          _, ok := r.SetString(stringValue)
          if !ok {
              fmt.Println("SetString エラー:", stringValue)
              return
          }
          fmt.Println(r.String()) // Output: 200/1
      
          negativeStringValue := "-75"
          r2 := new(big.Rat)
          _, ok = r2.SetString(negativeStringValue)
          if !ok {
              fmt.Println("SetString エラー:", negativeStringValue)
              return
          }
          fmt.Println(r2.String()) // Output: -75/1
      }
      
    • 利点
      文字列形式で整数値が与えられている場合に便利です。また、分数形式の文字列(例: "3/4")も解析できます。
    • 注意点
      文字列が有効な数値形式でない場合、エラーが発生する可能性があります。戻り値の ok を確認してエラーハンドリングを行う必要があります。

どの方法を選ぶべきか

  • 整数値が文字列として与えられている場合
    big.Rat.SetString() が適しています。
  • float64 型の変数から変換する場合
    big.Rat.SetFloat64() を使用できますが、精度に関する注意が必要です。
  • 整数リテラルから直接 big.Rat を作成したい場合
    big.NewRat(intValue, 1) が簡潔に記述できます。
  • big.Int 型の変数がすでに存在する場合
    big.Rat.SetInt() が最も直接的で効率的な方法です。