知っておきたい!Go言語 big.Float.Int()のよくあるエラーと解決策

2025-06-01

「big.Float.Int()」はGo言語のmath/bigパッケージに属するFloat型のメソッドです。このメソッドは、Float型の浮動小数点数を整数部のみに変換した*big.Int型の値を返します。

具体的な動作としては、以下のようになります。

  1. 小数点以下の切り捨て(Truncation): Int()メソッドは、小数点以下を単純に切り捨てます。つまり、正の数であれば小数点以下を切り捨て、負の数であれば小数点以下を切り上げます(例:3.14は3になり、-3.14は-3になります)。

  2. *big.Int型の返却: 結果は*big.Int型(big.Int型へのポインタ)で返されます。これは、非常に大きな整数を扱うことができるmath/bigパッケージの標準的な形式です。

なぜこれが必要なのか?

Go言語の組み込みのfloat64float32型は、小数点以下の精度が限られています。また、int型も表現できる整数の範囲が限られています。 math/bigパッケージのFloat型は、任意の精度で浮動小数点数を表現できます。Int()メソッドを使うことで、この高精度な浮動小数点数から、オーバーフローを気にすることなく(十分に大きな整数を表現できる)整数部分だけを取り出すことができるようになります。

使用例

package main

import (
	"fmt"
	"math/big"
)

func main() {
	// 正の浮動小数点数
	f1 := new(big.Float).SetString("123.456")
	i1 := f1.Int(nil) // nilを渡すと新しいbig.Intが作成されます
	fmt.Printf("f1: %s, i1: %s (Type: %T)\n", f1.String(), i1.String(), i1) // 出力: f1: 123.456, i1: 123 (Type: *big.Int)

	// 負の浮動小数点数
	f2 := new(big.Float).SetString("-789.123")
	i2 := f2.Int(nil)
	fmt.Printf("f2: %s, i2: %s (Type: %T)\n", f2.String(), i2.String(), i2) // 出力: f2: -789.123, i2: -789 (Type: *big.Int)

	// 非常に大きな浮動小数点数
	f3 := new(big.Float).SetString("98765432109876543210.12345")
	i3 := f3.Int(nil)
	fmt.Printf("f3: %s, i3: %s (Type: %T)\n", f3.String(), i3.String(), i3) // 出力: f3: 98765432109876543210.12345, i3: 98765432109876543210 (Type: *big.Int)

	// 結果を既存のbig.Intに格納する場合
	f4 := new(big.Float).SetString("5.67")
	var existingInt big.Int
	i4 := f4.Int(&existingInt) // 既存のbig.Intへのポインタを渡す
	fmt.Printf("f4: %s, i4: %s (Type: %T)\n", f4.String(), i4.String(), i4) // 出力: f4: 5.67, i4: 5 (Type: *big.Int)
	fmt.Printf("existingInt: %s (Type: %T)\n", existingInt.String(), &existingInt) // 出力: existingInt: 5 (Type: *big.Int)
}


精度に関する問題 (Precision Issues)

big.Floatは任意精度浮動小数点数ですが、Int()メソッドは小数点以下を切り捨てるため、元のbig.Floatが持つ精度が失われます。

よくある間違い
元のbig.Floatの精度が低い、または意図しない丸めモードで計算された結果をInt()に渡してしまうこと。


package main

import (
	"fmt"
	"math/big"
)

func main() {
	// デフォルト精度(通常53ビット)でFloatを作成
	f := new(big.Float).SetFloat64(3.9999999999999996) // float64の表現では4.0に非常に近いが、内部的には4未満
	i := f.Int(nil)
	fmt.Printf("f: %s, i: %s\n", f.String(), i.String()) // 多くの環境で f: 4, i: 4 となる可能性がある (float64の丸めによる)

	// 高精度を設定した場合
	fHighPrec := new(big.Float).SetPrec(100).SetString("3.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999")
	iHighPrec := fHighPrec.Int(nil)
	fmt.Printf("fHighPrec: %s, iHighPrec: %s\n", fHighPrec.String(), iHighPrec.String()) // 出力: fHighPrec: 3.99..., iHighPrec: 3
}

トラブルシューティング

  • 期待する丸め動作が必要な場合は、Int()ではなく、big.Floatの他のメソッド(例: Float().SetInt(intVal).SetMode(big.ToNearestEven)など)や、適切な丸めモードを設定してから整数に変換する方法を検討してください。Int()は常に0への切り捨て(truncation)です。
  • SetString()を使って文字列から初期化することで、浮動小数点数の表現による誤差を避けることができます。
  • big.Floatを初期化する際、または計算を行う際に、十分なSetPrec()を使って精度を設定しているか確認してください。特にfloat64から変換する場合は、float64が持つ精度(通常53ビット)以上の精度をbig.Floatに設定しても、元のfloat64の精度以上の情報は得られません。

無限大 (Infinity) や非数 (NaN) の扱い

big.Floatは無限大や非数(NaN)を表現できますが、これらをInt()に変換しようとすると特別な挙動を示します。

よくある間違い
IsInf()IsNaN()でチェックせずにInt()を呼び出し、予期しない結果(nilが返ってくる)になる。


package main

import (
	"fmt"
	"math/big"
)

func main() {
	// 無限大
	inf := new(big.Float).SetInf(false) // 負の無限大
	iInf, accInf := inf.Int(nil)
	fmt.Printf("Inf: %s, Int: %v, Accuracy: %v\n", inf.String(), iInf, accInf) // 出力: Inf: -Inf, Int: <nil>, Accuracy: Below

	// 非数 (NaN)
	nan := new(big.Float)
	nan.SetString("NaN") // SetStringはNaNをサポートしている
	iNaN, accNaN := nan.Int(nil)
	fmt.Printf("NaN: %s, Int: %v, Accuracy: %v\n", nan.String(), iNaN, accNaN) // 出力: NaN: NaN, Int: <nil>, Accuracy: Exact
}

トラブルシューティング

  • Int()を呼び出す前に、IsInf()IsNaN()を使って入力が無限大や非数でないことを確認することが重要です。
  • 無限大や非数をInt()に変換しようとすると、*big.Intの戻り値はnilになります。
  • Int()メソッドは2つの戻り値を返します。2番目の戻り値はbig.Accuracy型で、変換がExact(正確)、Below(元の値より小さい)、Above(元の値より大きい)のいずれであったかを示します。

メモリ管理とパフォーマンス

big.Intbig.Floatは任意精度であるため、扱う数値が大きくなるとそれに応じてメモリ使用量も増え、計算に時間がかかる場合があります。

よくある間違い
不必要に新しい*big.Intインスタンスを生成し続けること。


package main

import (
	"fmt"
	"math/big"
)

func main() {
	f := new(big.Float).SetString("12345678901234567890.123")

	// 毎回新しいbig.Intを生成する (非効率的)
	for i := 0; i < 3; i++ {
		result := f.Int(nil) // 新しいbig.Intが作成される
		fmt.Printf("Result %d: %s\n", i, result.String())
	}

	fmt.Println("---")

	// 既存のbig.Intを再利用する (効率的)
	var reusableInt big.Int
	for i := 0; i < 3; i++ {
		result := f.Int(&reusableInt) // 既存のbig.Intに結果が格納される
		fmt.Printf("Result %d: %s\n", i, result.String())
	}
}

トラブルシューティング

  • Int(z *big.Int)メソッドの引数znilを渡すと新しい*big.Intが割り当てられますが、既存の*big.Intへのポインタを渡すことで、その*big.Intが再利用され、不要なメモリ割り当てを避けることができます。特にループ内でInt()を頻繁に呼び出す場合は、このテクニックがパフォーマンス向上に寄与します。

big.Floatが0の場合、Int()は0を返します。これは期待通りの動作です。

よくある間違い(というより確認事項)
正のゼロと負のゼロの区別。big.Floatは負のゼロ(-0.0)を表現できますが、Int()は符号を考慮せずに0を返します。


package main

import (
	"fmt"
	"math/big"
)

func main() {
	fPosZero := new(big.Float).SetFloat64(0.0)
	iPosZero := fPosZero.Int(nil)
	fmt.Printf("Pos Zero: %s, Int: %s\n", fPosZero.String(), iPosZero.String())

	fNegZero := new(big.Float).SetString("-0.0")
	iNegZero := fNegZero.Int(nil)
	fmt.Printf("Neg Zero: %s, Int: %s\n", fNegZero.String(), iNegZero.String()) // Intは"0"を返す
}

トラブルシューティング

  • ほとんどの場合、正のゼロと負のゼロの区別は整数の世界では意味を持たないため、これは問題になりません。もしこの区別が重要であるならば、Int()の前にbig.FloatSign()メソッドなどで符号を確認する必要があります。

big.Float.Int()を使用する際の一般的なエラーとトラブルシューティングのポイントは以下の通りです。

  • パフォーマンス: ループなどで繰り返しInt()を呼び出す場合は、既存の*big.Intインスタンスを引数として渡すことで、不要なメモリ割り当てを避ける。
  • 特殊な値: 無限大やNaNを扱う場合は、Int()の戻り値がnilになること、およびAccuracyの戻り値を確認し、事前にIsInf()IsNaN()でチェックする。
  • 精度: big.Floatの適切な精度設定を確認し、必要に応じてSetPrec()SetString()を使用する。


big.Float.Int()とは?

big.Float.Int()は、math/bigパッケージのbig.Float型(任意精度浮動小数点数)のメソッドです。このメソッドは、big.Float整数部分を抽出し、それを*big.Int型(任意精度整数)として返します。小数点以下は常に切り捨てられます(0方向への丸め)。

メソッドのシグネチャは以下のようになります。

func (f *Float) Int(z *Int) (*Int, Accuracy)
  • 戻り値2 (Accuracy): 変換の精度を示す値(big.Exact, big.Below, big.Above)。無限大やNaNの場合には異なる意味を持ちます。
  • 戻り値1 (*Int): 抽出された整数部分を表す*big.Intzが渡された場合はそれと同じポインタ、nilが渡された場合は新しく作成されたポインタ。
  • z: 結果を格納する*big.Intへのポインタ。nilを渡すと新しい*big.Intが作成されます。
  • f: メソッドを呼び出す*big.Floatインスタンス。

例1: 基本的な使い方と小数点以下の切り捨て

この例では、正の数と負の数でInt()がどのように動作し、小数点以下が切り捨てられるかを示します。

package main

import (
	"fmt"
	"math/big"
)

func main() {
	fmt.Println("--- 例1: 基本的な使い方と小数点以下の切り捨て ---")

	// 1. 正の浮動小数点数
	f1 := new(big.Float).SetString("123.456")
	// Int()メソッドを呼び出す。nilを渡すと新しいbig.Intが作成される。
	i1, acc1 := f1.Int(nil)
	fmt.Printf("元の値: %s, 整数部分: %s, 精度: %v\n", f1.String(), i1.String(), acc1)
	// 出力: 元の値: 123.456, 整数部分: 123, 精度: Exact

	// 2. 負の浮動小数点数
	f2 := new(big.Float).SetString("-789.123")
	// 負の数の場合も小数点以下が切り捨てられる(-3.14 -> -3)
	i2, acc2 := f2.Int(nil)
	fmt.Printf("元の値: %s, 整数部分: %s, 精度: %v\n", f2.String(), i2.String(), acc2)
	// 出力: 元の値: -789.123, 整数部分: -789, 精度: Exact

	// 3. ぴったり整数値の浮動小数点数
	f3 := new(big.Float).SetString("500.00")
	i3, acc3 := f3.Int(nil)
	fmt.Printf("元の値: %s, 整数部分: %s, 精度: %v\n", f3.String(), i3.String(), acc3)
	// 出力: 元の値: 500, 整数部分: 500, 精度: Exact
}

解説

  • Accuracyの戻り値はExactとなっています。これは、浮動小数点数から整数部分を抽出する操作は「正確」に行われたことを意味します。小数点以下が切り捨てられても、この文脈では「正確」です。
  • f1.Int(nil)のようにnilを渡すと、Int()メソッドは新しく*big.Int型のインスタンスを作成し、そのポインタを返します。
  • new(big.Float).SetString("...")を使って、高精度な浮動小数点数を文字列から初期化しています。これはfloat64からの変換で発生する可能性のある丸め誤差を避けるためによく使われます。

例2: 既存の*big.Intを再利用するパフォーマンス最適化

ループなどでInt()メソッドを繰り返し呼び出す場合、毎回新しい*big.Intを割り当てるのは非効率です。この例では、既存の*big.Intインスタンスを再利用する方法を示します。

package main

import (
	"fmt"
	"math/big"
)

func main() {
	fmt.Println("\n--- 例2: 既存の*big.Intを再利用するパフォーマンス最適化 ---")

	numbers := []string{
		"10.1", "20.5", "30.9", "40.0", "-5.2",
	}

	// 新しいbig.Intを毎回生成する (非効率的)
	fmt.Println("毎回新しいbig.Intを生成:")
	for _, s := range numbers {
		f := new(big.Float).SetString(s)
		i, _ := f.Int(nil) // ここで新しいbig.Intが割り当てられる
		fmt.Printf("Float: %s, Int: %s\n", f.String(), i.String())
	}

	fmt.Println("\n既存のbig.Intを再利用:")
	// 既存のbig.Intを宣言し、それを再利用する
	var reusableInt big.Int
	for _, s := range numbers {
		f := new(big.Float).SetString(s)
		// reusableIntへのポインタを渡すことで、割り当てを再利用する
		i, _ := f.Int(&reusableInt)
		// iはreusableIntと同じポインタを指している
		fmt.Printf("Float: %s, Int: %s (ポインタアドレス: %p)\n", f.String(), i.String(), i)
	}

	// 最後にreusableIntの値を表示して、最後に格納された値を確認
	fmt.Printf("最終的なreusableIntの値: %s\n", reusableInt.String())
}

解説

  • 最後のreusableInt.String()は、最後に処理された値(この場合は"-5")がreusableIntに格納されていることを示します。
  • fmt.Printfでポインタアドレスを表示している部分を見ると、iが常に同じアドレスを指していることが確認できます。これは、同じメモリ領域が再利用されていることを意味します。
  • 2番目のループでは、ループの前にvar reusableInt big.Intと宣言したbig.Int変数のアドレスをf.Int(&reusableInt)として渡しています。これにより、Int()メソッドは結果をこの既存のreusableIntに格納し、新しいメモリ割り当ては発生しません。
  • 最初のループでは、f.Int(nil)を呼び出すたびに新しいbig.Intオブジェクトがメモリに割り当てられます。

big.Floatは無限大やNaNを表現できます。これらをInt()に変換しようとすると、特別な挙動を示します。

package main

import (
	"fmt"
	"math/big"
)

func main() {
	fmt.Println("\n--- 例3: 無限大 (Infinity) や非数 (NaN) の扱い ---")

	// 1. 正の無限大
	infPos := new(big.Float).SetInf(true) // trueで正の無限大
	iInfPos, accInfPos := infPos.Int(nil)
	// 無限大を整数に変換すると、*big.Intはnilになる
	fmt.Printf("元の値: %s, 整数部分: %v, 精度: %v (IsInf: %t)\n",
		infPos.String(), iInfPos, accInfPos, infPos.IsInf())
	// 出力: 元の値: +Inf, 整数部分: <nil>, 精度: Above (IsInf: true)

	// 2. 負の無限大
	infNeg := new(big.Float).SetInf(false) // falseで負の無限大
	iInfNeg, accInfNeg := infNeg.Int(nil)
	fmt.Printf("元の値: %s, 整数部分: %v, 精度: %v (IsInf: %t)\n",
		infNeg.String(), iInfNeg, accInfNeg, infNeg.IsInf())
	// 出力: 元の値: -Inf, 整数部分: <nil>, 精度: Below (IsInf: true)

	// 3. 非数 (NaN)
	nan := new(big.Float)
	nan.SetString("NaN") // NaNを文字列から設定
	iNaN, accNaN := nan.Int(nil)
	// NaNを整数に変換すると、*big.Intはnilになる
	fmt.Printf("元の値: %s, 整数部分: %v, 精度: %v (IsNaN: %t)\n",
		nan.String(), iNaN, accNaN, nan.IsNaN())
	// 出力: 元の値: NaN, 整数部分: <nil>, 精度: Exact (IsNaN: true)

	// 重要な注意点: Int()を呼び出す前にIsInf()やIsNaN()でチェックする
	value := new(big.Float).SetString("100.5")
	if value.IsInf() || value.IsNaN() {
		fmt.Println("値は無限大またはNaNです。整数に変換できません。")
	} else {
		intValue, _ := value.Int(nil)
		fmt.Printf("安全に変換できる値: %s, 整数部分: %s\n", value.String(), intValue.String())
	}
}
  • 最後のブロックでは、Int()を呼び出す前にIsInf()IsNaN()を使って、値が有効な数値であることを確認するベストプラクティスを示しています。これにより、nilポインタのデアファレンス(nilを指すポインタの値を参照しようとすること)によるパニックを防ぐことができます。
  • Accuracyの戻り値は、無限大の場合はBelowまたはAbove、NaNの場合はExactとなりますが、*big.Intnilであることから、これらのAccuracyは変換が成功しなかったことを示唆しています。
  • 無限大やNaNに対してInt()を呼び出すと、*big.Intの戻り値は常にnilになります。これはエラーではありませんが、呼び出し側でnilチェックを行う必要があります。
  • SetString("NaN")で非数(NaN)を作成します。
  • SetInf(true)で正の無限大、SetInf(false)で負の無限大を作成します。


big.Float.Int()は**0への切り捨て(truncation)**を行います。もし、他の丸めモード(四捨五入、切り上げ、切り捨てなど)が必要な場合や、特定の条件下での整数化が必要な場合は、以下の方法を検討します。

big.Float.ToNearestInt(): 最も近い整数への丸め

このメソッドは、big.Float値を最も近い整数に丸めます。0.5の場合は偶数丸め(half to even)を行います。これは、統計処理や金融計算などで一般的に使用される丸めルールです。

特徴

  • 結果は*big.Floatで返されるため、さらにInt()で変換する必要がある(またはSetInt()で直接*big.Intに変換)。
  • 四捨五入に似ているが、0.5の端数処理が偶数丸め。

使用例

package main

import (
	"fmt"
	"math/big"
)

func main() {
	fmt.Println("--- big.Float.ToNearestInt() の例 ---")

	// 1. 通常の四捨五入に近い例
	f1 := new(big.Float).SetString("3.7")
	rounded1 := new(big.Float)
	f1.ToNearestInt(rounded1) // rounded1 に結果が格納される
	i1, _ := rounded1.Int(nil)
	fmt.Printf("元の値: %s, 最も近い整数 (Float): %s, 整数部分 (Int): %s\n", f1.String(), rounded1.String(), i1.String())
	// 出力: 元の値: 3.7, 最も近い整数 (Float): 4, 整数部分 (Int): 4

	// 2. 0.5 の偶数丸め
	f2 := new(big.Float).SetString("3.5")
	rounded2 := new(big.Float)
	f2.ToNearestInt(rounded2)
	i2, _ := rounded2.Int(nil) // 3.5 -> 4 (偶数)
	fmt.Printf("元の値: %s, 最も近い整数 (Float): %s, 整数部分 (Int): %s\n", f2.String(), rounded2.String(), i2.String())
	// 出力: 元の値: 3.5, 最も近い整数 (Float): 4, 整数部分 (Int): 4

	f3 := new(big.Float).SetString("2.5")
	rounded3 := new(big.Float)
	f3.ToNearestInt(rounded3)
	i3, _ := rounded3.Int(nil) // 2.5 -> 2 (偶数)
	fmt.Printf("元の値: %s, 最も近い整数 (Float): %s, 整数部分 (Int): %s\n", f3.String(), rounded3.String(), i3.String())
	// 出力: 元の値: 2.5, 最も近い整数 (Float): 2, 整数部分 (Int): 2
}

big.Floatとbig.Intの間の変換メソッド(SetInt, SetUint64, SetFloat64など)

big.Floatには、big.IntやGoの組み込み整数型との間で変換を行うためのメソッドがいくつかあります。これらはbig.Float.Int()とは逆の操作を行いますが、big.Intや他の整数型からbig.Floatを作成し、その後必要に応じて別の丸め処理を適用するという文脈で代替手段となりえます。

特徴

  • 浮動小数点数から整数への変換(ただし、Int()と同じく切り捨て)。
  • 整数から浮動小数点数への変換。

使用例 (FloatからIntへの直接変換は Int() のみ)

big.Floatからbig.Intへ直接、明示的な丸めモードを指定して変換するメソッドは現状ありません。Int()が唯一の直接的な方法です。 しかし、big.Intからbig.Floatへの変換は可能です。

package main

import (
	"fmt"
	"math/big"
)

func main() {
	fmt.Println("\n--- big.Int と big.Float の相互変換の例 ---")

	// big.Int から big.Float を作成
	i := new(big.Int).SetString("12345")
	f := new(big.Float).SetInt(i)
	fmt.Printf("big.Int: %s, big.Float: %s\n", i.String(), f.String())
	// 出力: big.Int: 12345, big.Float: 12345

	// float64 から big.Float を作成
	f64 := 3.14159
	fBig := new(big.Float).SetFloat64(f64)
	fmt.Printf("float64: %f, big.Float: %s\n", f64, fBig.String())
	// 出力: float64: 3.141590, big.Float: 3.14159
}

手動での丸め処理とbig.Float.Cmp()

もし、big.Float.ToNearestInt()が提供する偶数丸め以外の特定の丸めルール(例: 常に切り上げ、常に切り下げ、通常の四捨五入など)が必要な場合、手動で処理を実装することが考えられます。これには、big.Float.Cmp()メソッド(比較)やbig.Float.Add(), big.Float.Sub()などの演算メソッドを組み合わせます。

特徴

  • コードが複雑になりがち。
  • 任意の丸めルールを実装できる。

使用例: 通常の四捨五入(0.5は切り上げ)を実装

package main

import (
	"fmt"
	"math/big"
)

// roundHalfUp は、0.5を切り上げる四捨五入を行う関数
func roundHalfUp(f *big.Float) *big.Int {
	// 値の符号を確認
	sign := f.Sign()
	if sign == 0 {
		return new(big.Int).SetInt64(0)
	}

	// 整数部分を取得 (切り捨て)
	truncatedInt, _ := f.Int(nil)

	// 小数部分を取得 (元の値 - 整数部分)
	// 例: 3.7 - 3 = 0.7
	// 例: -3.7 - (-3) = -0.7
	frac := new(big.Float).Sub(f, new(big.Float).SetInt(truncatedInt))

	// 0.5 と比較するための基準となる値
	half := new(big.Float).SetFloat64(0.5)

	// 負の数の場合は、0.5の判断基準も負にする
	if sign < 0 {
		half.Neg(half) // half を -0.5 にする
	}

	// 小数部分が0.5以上(絶対値で)なら切り上げ
	// f >= 0 の場合: frac.Cmp(half) >= 0 (例: 0.7 >= 0.5)
	// f < 0 の場合: frac.Cmp(half) <= 0 (例: -0.7 <= -0.5)
	if (sign >= 0 && frac.Cmp(half) >= 0) || (sign < 0 && frac.Cmp(half) <= 0) {
		// 整数部分に1を足す(または引く)
		if sign >= 0 {
			truncatedInt.Add(truncatedInt, big.NewInt(1))
		} else {
			truncatedInt.Sub(truncatedInt, big.NewInt(1))
		}
	}
	return truncatedInt
}

func main() {
	fmt.Println("\n--- 手動での通常の四捨五入 (roundHalfUp) の例 ---")

	testValues := []string{"3.7", "3.5", "2.5", "-3.7", "-3.5", "-2.5", "0.0"}

	for _, s := range testValues {
		f := new(big.Float).SetString(s)
		resultInt := roundHalfUp(f)
		fmt.Printf("元の値: %s, 四捨五入後 (Int): %s\n", f.String(), resultInt.String())
	}
	/*
		出力例:
		元の値: 3.7, 四捨五入後 (Int): 4
		元の値: 3.5, 四捨五入後 (Int): 4
		元の値: 2.5, 四捨五入後 (Int): 3
		元の値: -3.7, 四捨五入後 (Int): -4
		元の値: -3.5, 四捨五入後 (Int): -4
		元の値: -2.5, 四捨五入後 (Int): -3
		元の値: 0, 四捨五入後 (Int): 0
	*/
}

解説
このroundHalfUp関数は、以下のステップで通常の四捨五入(0.5は切り上げ)を実装しています。

  1. f.Int(nil)で元の値の整数部分(切り捨て)を取得します。
  2. f.Sub(f, new(big.Float).SetInt(truncatedInt))で小数点部分を計算します。
  3. 小数部分が0.5以上(負の数の場合は-0.5以下)であれば、整数部分を増減させます。

big.Float.SetMode(): 丸めモードの設定 (演算時の丸め)

big.Floatには、演算(加算、減算、乗算、除算など)の際に使用する丸めモードを設定するSetMode()メソッドがあります。これはInt()のような変換とは直接関係ありませんが、特定の丸めモードで計算された結果を最終的にInt()で切り捨てる場合など、間接的に影響を与える可能性があります。

丸めモードの例

  • big.ToNegativeInf: 負の無限大への丸め(切り捨て)。
  • big.ToPositiveInf: 正の無限大への丸め(切り上げ)。
  • big.AwayFromZero: 0から遠ざかる方向への丸め(絶対値の切り上げ)。
  • big.ToZero: 0への切り捨て(Int()がこれに相当)。
  • big.ToNearestEven: 最も近い整数に丸め、0.5は偶数に丸める(デフォルト)。

使用例

package main

import (
	"fmt"
	"math/big"
)

func main() {
	fmt.Println("\n--- big.Float.SetMode() の例 (演算時の丸め) ---")

	// 新しいFloatを作成し、丸めモードを設定
	f := new(big.Float).SetPrec(53) // デフォルト精度 (float64相当)

	// ToPositiveInf (切り上げ)
	f.SetMode(big.ToPositiveInf)
	f.SetString("3.1")
	result1 := new(big.Float)
	result1.Add(f, new(big.Float).SetInt64(0)) // 演算で丸めが適用される
	i1, _ := result1.Int(nil)
	fmt.Printf("3.1 (ToPositiveInf): Float=%s, Int=%s\n", result1.String(), i1.String())
	// 出力: 3.1 (ToPositiveInf): Float=4, Int=4

	f.SetString("3.9")
	result2 := new(big.Float)
	result2.Add(f, new(big.Float).SetInt64(0))
	i2, _ := result2.Int(nil)
	fmt.Printf("3.9 (ToPositiveInf): Float=%s, Int=%s\n", result2.String(), i2.String())
	// 出力: 3.9 (ToPositiveInf): Float=4, Int=4

	// ToNegativeInf (切り捨て)
	f.SetMode(big.ToNegativeInf)
	f.SetString("3.9")
	result3 := new(big.Float)
	result3.Add(f, new(big.Float).SetInt64(0))
	i3, _ := result3.Int(nil)
	fmt.Printf("3.9 (ToNegativeInf): Float=%s, Int=%s\n", result3.String(), i3.String())
	// 出力: 3.9 (ToNegativeInf): Float=3, Int=3

	f.SetString("-3.1")
	result4 := new(big.Float)
	result4.Add(f, new(big.Float).SetInt64(0))
	i4, _ := result4.Int(nil)
	fmt.Printf("-3.1 (ToNegativeInf): Float=%s, Int=%s\n", result4.String(), i4.String())
	// 出力: -3.1 (ToNegativeInf): Float=-4, Int=-4 (負の方向への切り捨て)
}

解説
SetMode()は、big.Floatの演算が行われるときに適用される丸めルールを設定します。上記の例では、Add()(0を加算するだけの操作)で丸めが適用され、その結果のbig.Floatに対してInt()を呼び出すことで、期待する整数値を得ています。 これはbig.Float.Int()の直接の代替ではありませんが、整数化の前に特定の丸めルールで値を調整したい場合に有効なアプローチです。

代替方法主な用途丸めルール注意点
big.Float.Int()デフォルト: 0への切り捨て0への切り捨て無限大/NaNはnilを返す。
big.Float.ToNearestInt()最も近い整数への丸め(偶数丸め)偶数丸め結果は*big.Floatで返されるため、さらにInt()が必要。
手動での丸め処理任意のカスタム丸めルール(例: 通常の四捨五入)カスタムコードが複雑になり、正確な実装が必要。
big.Float.SetMode()演算時の丸めモードの設定ToPositiveInf, ToNegativeInf など演算に適用されるもので、直接的な整数化メソッドではない。