Go言語 big.Float.SetMantExp()徹底解説:任意精度浮動小数点の操作
このメソッドは、以下のような形式で big.Float
の値を設定します。
z=mant×2exp
exp int
: 数値の「指数部」となる整数です。これは、mant
に掛けられる2のべき乗(2exp)を示します。mant *Float
: 数値の「仮数部」となるbig.Float
のポインタです。このmant
は、通常 0.5≤∣mant∣<1.0 の範囲に正規化されます。z
: メソッドのレシーバー(SetMantExp
を呼び出す*big.Float
オブジェクト)で、設定された結果が格納されます。
具体的な動作
z
の値は、mant
の値に 2exp を乗算した結果として設定されます。z
の精度 (precision) と丸めモード (rounding mode) は、z
自身に設定されているものが使用されます。mant
の精度や丸めモードは、z
の設定には影響しません。mant
はゼロであっても構いません。その場合、z
もゼロになります(exp
の値に関わらず)。mant
が無限大 (Infinity) や非数 (NaN) を表す場合、Goのmath/big
パッケージのbig.Float
はIEEE 754のNaNを直接サポートせず、代わりにpanic
を発生させます。
使用例
例えば、0.75×210 という値を big.Float
で表現したい場合:
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Float
// 仮数部を0.75として設定
mant := big.NewFloat(0.75)
// 指数部を10として設定
exp := 10
// f を mant * 2^exp で設定
f.SetMantExp(mant, exp)
fmt.Printf("f = %.10g (仮数部: %s, 指数部: %d)\n", &f, mant.Text('g', -1), exp)
// 出力例: f = 768 (仮数部: 0.75, 指数部: 10)
// 0.75 * 2^10 = 0.75 * 1024 = 768
}
なぜこのメソッドが必要なのか?
big.Float
は任意精度を扱うため、浮動小数点数を内部的に仮数と指数で表現しています。SetMantExp()
は、この内部表現を直接操作することで、特定の仮数と指数を持つ数値を効率的に構築するために使われます。例えば、特定のビットシフト操作を行いたい場合などに便利です。
big.Float.MantExp()
メソッドは、既存の big.Float
の値から仮数部と指数部を抽出するために使用されます。SetMantExp()
はその逆の操作にあたります。
ポインタの取り扱いに関するエラー
SetMantExp
の mant
引数は *big.Float
型、つまり big.Float
のポインタを期待します。
よくある間違い
mant
引数に直接 big.Float
の値を渡してしまう。
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Float
var mant big.Float // ポインタではない
mant.SetFloat64(0.75)
// エラー: SetMantExp expects *big.Float, not big.Float
// f.SetMantExp(mant, 10)
fmt.Println("This code will not compile as written.")
}
トラブルシューティング
mant
には必ずポインタを渡すようにしてください。big.NewFloat()
を使うか、既存の big.Float
変数のアドレス演算子 &
を使います。
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Float
// 方法1: big.NewFloat() を使う
mant1 := big.NewFloat(0.75)
f.SetMantExp(mant1, 10)
fmt.Printf("f (NewFloat) = %s\n", f.String()) // 768
// 方法2: 既存の変数のアドレスを使う
var mant2 big.Float
mant2.SetFloat64(0.75)
f.SetMantExp(&mant2, 10) // & を使う
fmt.Printf("f (address) = %s\n", f.String()) // 768
}
仮数部の正規化に関する誤解
SetMantExp(mant, exp)
は、結果的に mant * 2^exp
となりますが、mant
自体が正規化されているかどうかにかかわらず、この計算を実行します。しかし、big.Float
の多くの内部演算や、big.Float.MantExp()
で仮数部と指数部を取り出す際には、仮数部は通常 0.5≤∣mant∣<1.0 の範囲に正規化されます。この正規化は SetMantExp()
に直接は影響しませんが、その後の処理で混乱を招く可能性があります。
よくある誤解
SetMantExp
に渡す mant
が自動的に正規化されると思い込んでいる。
トラブルシューティング
SetMantExp
は、あくまで指定された mant
と exp
を使って単純な積を計算します。もし、特定の正規化された仮数部と指数部で値を構成したい場合は、まず適切な mant
を手動で計算するか、big.Float.SetFloat64()
などで目的の値を作成し、後で big.Float.MantExp()
で抽出する方法を検討してください。
例: big.NewFloat(1.5).SetMantExp(big.NewFloat(0.75), 1)
と big.NewFloat(0.75).SetMantExp(big.NewFloat(1.5), 0)
は同じ値 (1.5) を生成しますが、mant
引数が異なります。
package main
import (
"fmt"
"math/big"
)
func main() {
var f1, f2 big.Float
// f1 は 0.75 * 2^1 = 1.5
f1.SetMantExp(big.NewFloat(0.75), 1)
fmt.Printf("f1 = %s\n", f1.String())
// f2 は 1.5 * 2^0 = 1.5
f2.SetMantExp(big.NewFloat(1.5), 0)
fmt.Printf("f2 = %s\n", f2.String())
}
精度の取り扱い
SetMantExp()
で設定される big.Float
の精度は、レシーバー (SetMantExp
を呼び出す *big.Float
) に既に設定されている精度に依存します。mant
引数の精度は結果に影響しません。
よくある間違い
mant
の精度が結果に引き継がれると思い込んでいる。
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Float
f.SetPrec(64) // f の精度を64ビットに設定
mant := new(big.Float).SetPrec(128).SetFloat64(0.1234567890123456789) // mant は128ビット精度
f.SetMantExp(mant, 0) // mant * 2^0 = mant となる
// f の精度は64ビットなので、mantの128ビット精度は失われる可能性がある
fmt.Printf("f (precision %d) = %.20f\n", f.Prec(), &f)
fmt.Printf("mant (precision %d) = %.20f\n", mant.Prec(), mant)
// 出力例:
// f (precision 64) = 0.12345678901234568
// mant (precision 128) = 0.1234567890123456789
// f はmantの精度を保持していないことがわかる
}
トラブルシューティング
結果の big.Float
に必要な精度を設定してから SetMantExp
を呼び出してください。
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Float
f.SetPrec(128) // f の精度を128ビットに設定
mant := new(big.Float).SetPrec(64).SetFloat64(0.1234567890123456789) // mant は64ビット精度でも良い
f.SetMantExp(mant, 0)
fmt.Printf("f (precision %d) = %.20f\n", f.Prec(), &f)
fmt.Printf("mant (precision %d) = %.20f\n", mant.Prec(), mant)
// 出力例:
// f (precision 128) = 0.12345678901234567890
// mant (precision 64) = 0.12345678901234568
// f がmantより高い精度を持つ場合、mantが提供する桁数まで正確に設定される
}
ゼロ値の取り扱い
mant
がゼロ (0
) の場合、SetMantExp()
は z
をゼロに設定します。この挙動は通常期待通りですが、意図せず mant
がゼロになってしまうケースには注意が必要です。
よくある間違い
計算の結果 mant
がゼロになってしまい、意図しないゼロ値が設定される。
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Float
mant := big.NewFloat(0.0) // 意図せず0になってしまった
exp := 5
f.SetMantExp(mant, exp)
fmt.Printf("f = %s\n", f.String()) // 出力: 0 (0 * 2^5 = 0)
}
トラブルシューティング
mant
の値が期待通りであるか、計算の途中でゼロになっていないかを確認してください。デバッグ出力やユニットテストが有効です。
パニックの可能性(非数・無限大)
math/big.Float
はIEEE 754の非数(NaN)や無限大(Infinity)を直接サポートしていません。SetMantExp
に渡される mant
が、これらの特殊な値を表す場合にはパニックが発生する可能性があります。
よくある間違い
mant
が無限大やNaNを保持している可能性があるが、考慮していない。
package main
import (
"fmt"
"math/big"
)
func main() {
var f big.Float
// 無限大を生成しようとする(DivideByZeroなどで)
inf := new(big.Float).Quo(big.NewFloat(1.0), big.NewFloat(0.0))
fmt.Printf("inf = %s\n", inf.String()) // +Inf
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
// inf を SetMantExp に渡すとパニック
f.SetMantExp(inf, 10)
fmt.Println("This line will not be reached if panic occurs.")
}
トラブルシューティング
SetMantExp
を呼び出す前に、mant
の値が通常の数値であることを確認してください。IsInf()
や IsNaN()
のようなメソッドは math/big
には直接ありませんが、big.Float
が特殊な値を保持することはあまりありません。通常、big.Float
で計算を行った結果、無限大になるような状況では、SetMantExp
に渡す前にすでに無限大の挙動を示すため、このメソッドが直接の原因となることは稀です。
big.Float.SetMantExp()
は、big.Float
のポインタ、精度、そして仮数部と指数部の関係を理解していれば、強力で効率的なツールとなります。上記のエラーとトラブルシューティングのポイントを念頭に置くことで、より堅牢なコードを書くことができるでしょう。
Go言語の big.Float.SetMantExp()
メソッドは、任意精度浮動小数点数を扱う上で非常に強力ですが、その特性を理解していないと予期せぬ挙動やエラーに遭遇することがあります。ここでは、よくあるエラーとそれに対するトラブルシューティングについて解説します。
よくあるエラーと問題点
-
- 問題
SetMantExp()
メソッド自体は、レシーバー (*big.Float
オブジェクト) の既存の精度と丸めモードを使用します。mant
引数として渡すbig.Float
の精度は、結果の精度に影響しません。big.Float
のデフォルトの精度はfloat64
と同じ53ビットであり、このデフォルト精度を意識せずにSetMantExp
を使うと、期待する精度が得られないことがあります。 - 例
この場合、package main import ( "fmt" "math/big" ) func main() { var f big.Float // デフォルト精度 (53ビット) mant := big.NewFloat(0.1) // 0.1 はバイナリで正確に表現できない exp := 0 f.SetMantExp(mant, exp) // f の精度は53ビット fmt.Printf("f (default prec) = %.20g\n", &f) // 精度を明示的に設定 f2 := new(big.Float).SetPrec(100) // 100ビットの精度を設定 f2.SetMantExp(mant, exp) fmt.Printf("f2 (100-bit prec) = %.20g\n", &f2) }
f
とf2
で表示される0.1
の精度が異なる可能性があります。
- 問題
-
丸め誤差 (Rounding Errors)
- 問題
big.Float
は任意精度ですが、それでも浮動小数点数である以上、丸め誤差は発生します。特に、10進数の小数をバイナリで正確に表現できない場合、SetMantExp()
を介して値を設定しても、内部的には最も近いバイナリ表現に丸められます。この丸めは、レシーバーの精度と丸めモードに従って行われます。 - トラブルシューティング
- 高い精度を設定する
計算結果の精度が重要であれば、SetPrec()
メソッドを使用して必要な精度を設定します。 - SetString() を検討する
文字列として正確な10進数を指定したい場合、SetString()
メソッドを使用すると、その文字列を内部的に正確なバイナリ表現に変換しようとします(ただし、これにより高い精度が必要になる場合があります)。 - 丸めモードの確認
SetMode()
で丸めモードを確認または変更します。デフォルトはToNearestEven
(最も近い偶数への丸め) です。
- 高い精度を設定する
- 問題
-
無限大 (Infinity) や非数 (NaN) の扱い
- 問題
Goのmath/big.Float
はIEEE 754のNaN(非数)を直接サポートしていません。mant
引数がInf
(無限大) またはNaN
を表すbig.Float
の場合、SetMantExp()
はパニック (ErrNaN
) を発生させます。 - トラブルシューティング
SetMantExp()
を呼び出す前に、mant
が有限な値であることを確認します。mant.IsInf()
を使用してチェックできます。- 無限大を表現したい場合は、
SetInf(signbit bool)
メソッドを使用します。
- 問題
-
ゼロの扱い
- 問題
mant
がゼロの場合、SetMantExp
は常にゼロを返します。exp
の値は無視されます。これは期待通りの動作ですが、意図しないゼロになる可能性がある場合は注意が必要です。 - トラブルシューティング
mant
がゼロであることを認識している場合、SetMantExp
の結果がゼロになることを前提とします。
- 問題
-
パフォーマンスの問題 (特に大きな数値の表示)
- 問題
big.Float
は任意精度であるため、非常に大きな数値や非常に小さな数値を扱うことができます。これらの数値をfmt.Printf
やString()
メソッドで文字列に変換する際に、計算に時間がかかったり、出力が非常に長くなったりすることがあります。SetMantExp
自体は高速ですが、その結果の表示が問題となることがあります。 - トラブルシューティング
- Text() メソッドの使用
big.Float.Text()
メソッドを使用すると、出力形式(指数表記g
、固定小数点f
など)と有効桁数を指定できます。これにより、不要な精度で文字列化されるのを避けることができます。 - 必要な桁数のみ表示
fmt.Printf
のフォーマット指定子 (%.Ns
など) で、表示する小数点以下の桁数や有効桁数を制限します。
- Text() メソッドの使用
- 問題
基本的な使用例:z=mant×2exp
最も基本的な使い方です。特定の仮数と2のべき乗で数値を構成します。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("--- 基本的な使用例: z = mant * 2^exp ---")
var f big.Float
// 仮数部を 0.75 (big.NewFloat(0.75)) に、指数部を 10 に設定
// 結果は 0.75 * 2^10 = 0.75 * 1024 = 768
mant := big.NewFloat(0.75)
exp := 10
f.SetMantExp(mant, exp)
fmt.Printf("f = %s (仮数: %s, 指数: %d)\n", f.Text('g', -1), mant.Text('g', -1), exp)
// 出力: f = 768 (仮数: 0.75, 指数: 10)
// 別の例: 0.5 * 2^3 = 0.5 * 8 = 4
mant2 := big.NewFloat(0.5)
exp2 := 3
f.SetMantExp(mant2, exp2)
fmt.Printf("f = %s (仮数: %s, 指数: %d)\n", f.Text('g', -1), mant2.Text('g', -1), exp2)
// 出力: f = 4 (仮数: 0.5, 指数: 3)
// 仮数部が負の場合: -0.25 * 2^2 = -0.25 * 4 = -1
mant3 := big.NewFloat(-0.25)
exp3 := 2
f.SetMantExp(mant3, exp3)
fmt.Printf("f = %s (仮数: %s, 指数: %d)\n", f.Text('g', -1), mant3.Text('g', -1), exp3)
// 出力: f = -1 (仮数: -0.25, 指数: 2)
// 指数部が負の場合: 1.0 * 2^-1 = 1.0 * 0.5 = 0.5
mant4 := big.NewFloat(1.0)
exp4 := -1
f.SetMantExp(mant4, exp4)
fmt.Printf("f = %s (仮数: %s, 指数: %d)\n", f.Text('g', -1), mant4.Text('g', -1), exp4)
// 出力: f = 0.5 (仮数: 1, 指数: -1)
}
精度を設定した使用例
SetMantExp
はレシーバーの精度を使用します。高い精度が必要な場合は、事前に SetPrec()
で精度を設定する必要があります。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("\n--- 精度を設定した使用例 ---")
// デフォルト精度 (float64相当の53ビット)
var fDefault big.Float
mant := big.NewFloat(0.1) // 0.1は2進数で正確に表現できない
exp := 0
fDefault.SetMantExp(mant, exp)
fmt.Printf("デフォルト精度 (53ビット): %.20g\n", &fDefault)
// 100ビットの精度を設定
fHighPrec := new(big.Float).SetPrec(100) // 100ビットの精度を持つ新しいbig.Floatを生成
fHighPrec.SetMantExp(mant, exp)
fmt.Printf("高精度 (100ビット): %.20g\n", fHighPrec)
// 0.1のより正確な表現を確認するために、精度をさらに上げてみる
fVeryHighPrec := new(big.Float).SetPrec(200)
fVeryHighPrec.SetMantExp(mant, exp) // mantはデフォルト精度なので、0.1の初期変換はデフォルト精度で行われている
fmt.Printf("非常に高い精度 (200ビット): %.20g\n", fVeryHighPrec)
// ↑ ここで重要なのは、`mant` が既に丸められている可能性があるため、
// `SetMantExp` に渡す前に `mant` 自体も適切な精度で初期化する必要がある点。
// 例えば、0.1を文字列から初期化して精度を上げると、より正確な結果が得られる。
// 正しいやり方: 仮数部も高い精度で初期化する
mantHighPrec := new(big.Float).SetPrec(100)
mantHighPrec.SetString("0.1") // 文字列から初期化すると、より正確な値が設定される
fHighPrecCorrect := new(big.Float).SetPrec(100)
fHighPrecCorrect.SetMantExp(mantHighPrec, exp)
fmt.Printf("高精度 (100ビット、仮数部も高精度): %.20g\n", fHighPrecCorrect)
}
仮数部がゼロの場合
仮数部がゼロの場合、指数部が何であっても結果はゼロになります。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("\n--- 仮数部がゼロの場合 ---")
var f big.Float
mant := big.NewFloat(0)
exp := 1000 // 大きな指数部
f.SetMantExp(mant, exp)
fmt.Printf("f = %s (仮数: %s, 指数: %d)\n", f.Text('g', -1), mant.Text('g', -1), exp)
// 出力: f = 0 (仮数: 0, 指数: 1000)
}
MantExp()
と組み合わせる例
SetMantExp()
は MantExp()
の逆の操作です。既存の big.Float
の値を仮数部と指数部に分解し、それらを操作してから再構成するような場合に便利です。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("\n--- MantExp() との組み合わせ例 ---")
original := big.NewFloat(1234.5678)
fmt.Printf("元の値: %s\n", original.Text('g', -1))
// MantExp() を使って仮数部と指数部を抽出
var mantExtracted big.Float
expExtracted := original.MantExp(&mantExtracted)
fmt.Printf("抽出された仮数: %s\n", mantExtracted.Text('g', -1))
fmt.Printf("抽出された指数: %d\n", expExtracted)
// 抽出された仮数と指数を使って、元の値を再構成
var reconstructed big.Float
reconstructed.SetMantExp(&mantExtracted, expExtracted)
fmt.Printf("再構成された値: %s\n", reconstructed.Text('g', -1))
// 指数を変更して値をシフトする例:
// 元の値の指数を2つ増やす (original * 2^2)
var shifted big.Float
shifted.SetMantExp(&mantExtracted, expExtracted+2)
fmt.Printf("指数を2増やした値 (%s * 2^2): %s\n", original.Text('g', -1), shifted.Text('g', -1))
// 1234.5678 * 4 = 4938.2712
}
SetMantExp
は、仮数部が無限大や非数である場合、パニックを発生させます。これは、big.Float
がIEEE 754のNaNを直接サポートしていないためです。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("\n--- 無限大/非数での注意点 ---")
var f big.Float
// 無限大のbig.Floatを生成
infMant := new(big.Float).SetInf(false) // +Inf
fmt.Printf("無限大の仮数: %s\n", infMant.Text('g', -1))
defer func() {
if r := recover(); r != nil {
fmt.Printf("パニックが発生しました: %v\n", r)
}
}()
// 無限大の仮数でSetMantExpを呼び出すとパニックが発生
// このコードを実行すると、上記のdefer関数がパニックを捕捉します。
f.SetMantExp(infMant, 0)
fmt.Println("この行は表示されないはずです。")
}
SetString() または Set() と乗算 (Mul()) を組み合わせる
これは最も一般的で柔軟な代替方法です。特に、表現したい数値が10進数で与えられる場合や、2^exp
の部分が明確な定数である場合に有効です。
という計算を、SetString()
で mant
を初期化し、その後 Mul()
で 2^exp
を乗算することで実現します。
例
0.75×210 を計算する場合
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("--- SetString() + Mul() による代替 ---")
var f big.Float
// 1. 仮数部を文字列から設定 (またはSetFloat64など)
// SetStringを使うと、文字列で与えられた値を精度よく初期化できる
f.SetString("0.75")
// 2. 2^exp の値を計算し、別のbig.Floatとして用意
pow2 := new(big.Float).SetInt64(1 << 10) // 1 << 10 は 2^10 = 1024
// 3. 乗算
f.Mul(&f, pow2) // f = f * pow2
fmt.Printf("f = %s\n", f.Text('g', -1))
// 出力: f = 768
// 小数点以下の指数部の例: 1.0 * 2^-1 = 0.5
var f2 big.Float
f2.SetString("1.0")
// 2^-1 は 0.5
pow2_neg := new(big.Float).SetFloat64(0.5) // または big.NewFloat(0.5)
f2.Mul(&f2, pow2_neg)
fmt.Printf("f2 = %s\n", f2.Text('g', -1))
// 出力: f2 = 0.5
}
利点
- 一般的な操作
Mul()
は頻繁に使用されるため、慣れているプログラマが多い。 - 柔軟性
仮数部をfloat64
、int64
、または文字列など、さまざまな形式から初期化できる。 - 直感的
通常の算術演算の順序に従うため、理解しやすい。
欠点
SetMantExp()
ほど直接的ではない。特に、数学的な M×2E 形式で値を扱いたい場合に、2^E
を別途計算する必要がある。
SetInt() / SetUint() を使用して整数値を設定し、その後乗算/除算
整数値や、特に N×2E の形式で N が整数である場合に有効です。
例
768=3×28 (ここで mant=3, exp=8)
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("--- SetInt() + Mul() / Quo() による代替 ---")
var f big.Float
// 仮数部を整数として設定
mantInt := big.NewInt(3)
f.SetInt(mantInt) // f = 3
// 2^exp の値を計算し、big.Floatとして用意
pow2 := new(big.Float).SetInt64(1 << 8) // 2^8 = 256
// 乗算
f.Mul(&f, pow2) // f = 3 * 256 = 768
fmt.Printf("f = %s\n", f.Text('g', -1))
// 出力: f = 768
// 指数部が負の場合: 3 * 2^-1 = 1.5
var f2 big.Float
f2.SetInt(big.NewInt(3))
// 2^-1 は 0.5 (除算でも表現可能)
pow2_neg := new(big.Float).SetFloat64(0.5)
f2.Mul(&f2, pow2_neg) // f2 = 3 * 0.5 = 1.5
fmt.Printf("f2 = %s\n", f2.Text('g', -1))
// 出力: f2 = 1.5
// あるいは Quo (除算) を使う
var f3 big.Float
f3.SetInt(big.NewInt(3))
divisor := new(big.Float).SetInt64(1 << 1) // 2^1 = 2
f3.Quo(&f3, divisor) // f3 = 3 / 2 = 1.5
fmt.Printf("f3 = %s\n", f3.Text('g', -1))
// 出力: f3 = 1.5
}
利点
- 整数のシフト操作(
1 << exp
)と組み合わせやすい。 - 仮数部が整数である場合に、
big.Int
から直接big.Float
を構築できる。
欠点
- 仮数部が小数である場合には、
SetString()
やSetFloat64()
を使う必要がある。
Set() を使って既存の big.Float の値をコピーする
これは直接的な代替とは少し異なりますが、SetMantExp()
が特定の仮数と指数を持つ新しい値を生成する代わりに、既存の big.Float
の値をコピーしたい場合に役立ちます。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("--- Set() によるコピー ---")
original := big.NewFloat(123.45)
var copyOfF big.Float
// original の値を copyOfF にコピー
copyOfF.Set(original)
fmt.Printf("Original: %s\n", original.Text('g', -1))
fmt.Printf("Copy: %s\n", copyOfF.Text('g', -1))
}
SetMantExp()
は、以下のような状況で特に役立ちます。
- 数学的な表記 M×2E がコードに直接反映されることを重視する場合。
- パフォーマンスが非常に重要な場合
SetMantExp()
は仮数と指数から直接値を構築するため、Mul()
のように複数の操作を必要とする代替手段よりもわずかに高速である可能性があります(ただし、ほとんどのアプリケーションではパフォーマンスの差は無視できるレベルです)。 - MantExp() で抽出した値を再構成する場合
MantExp()
で分解した値を、指数だけ変えて再構築するような操作に最適です。 - 浮動小数点数の内部表現を直接操作したい場合
例えば、バイナリ浮動小数点数の特定のビット列を構成したり、正規化された仮数と指数を使って値を生成したい場合。