もう迷わない!Go言語 big.Int.Bits()の代替メソッドと使い分け
big.Int.Bits()
とは
big.Int.Bits()
メソッドは、*big.Int
型の数値が保持する符号なしワード(big.Word
型)のスライスを返します。このスライスは、数値の絶対値を「最下位ワードから最上位ワード」の順で表現しています。
簡単に言うと、big.Int
型の非常に大きな整数を、コンピュータが扱いやすい固定長の「単語」(big.Word
)の配列として取り出すためのメソッドです。
詳細
- 変更の可能性:
Bits()
が返すスライスは、big.Int
の内部表現への直接の参照である可能性があります。したがって、返されたスライスの要素を変更すると、元のbig.Int
の値も変更される可能性があるため、注意が必要です。通常は、Bits()
で得たスライスを直接変更するのではなく、必要であればコピーして使用することが推奨されます。 - 符号:
Bits()
メソッドは数値の「絶対値」を表現するため、数値の符号(正または負)はスライスには含まれません。符号の情報はbig.Int
オブジェクト自体が持っています。 - スライスの内容:
- 返されるスライスは、
big.Int
の絶対値のバイナリ表現の下位ビットから上位ビットへの並びで構成されます。 - 例えば、10進数の
12345678901234567890
のような大きな数をbig.Int
で表現した場合、Bits()
メソッドは、その数を構成するbig.Word
の列(配列)を返します。
- 返されるスライスは、
big.Word
型:big.Word
はuint
のエイリアスであり、通常はシステムが効率的に扱えるワードサイズ(32ビットまたは64ビット)に相当します。big.Int
型: Go言語のmath/big
パッケージで提供される、任意の精度(任意長)の整数を扱うための型です。通常のint
やint64
では表現できないような非常に大きな整数を扱うことができます。
なぜ Bits()
が必要なのか?
big.Int
は非常に大きな数を扱うため、通常の int
や int64
のように直接ビット操作を行うのは難しい場合があります。Bits()
メソッドは、big.Int
の内部表現にアクセスし、より低レベルなビット操作や、他のシステムとのデータ交換を行う際に役立ちます。
例えば、以下のような場合に利用されます。
- 他のライブラリやシステムとの連携:
big.Int
以外の形式で多倍長整数を扱うライブラリやシステムとデータをやり取りする場合、Bits()
で得られたワードのスライスが利用されることがあります。 - シリアライズ/デシリアライズ:
big.Int
の値をバイト列に変換して保存したり、ネットワーク経由で送信したりする場合。 - 特定のビットパターンにアクセスしたい場合:
big.Int
の内部表現の各ワードのビットを直接調べたり、操作したりする場合。
package main
import (
"fmt"
"math/big"
)
func main() {
// 大きな整数を作成
numStr := "1234567890123456789012345678901234567890"
bigInt := new(big.Int)
bigInt.SetString(numStr, 10) // 10進数で設定
fmt.Printf("元の big.Int: %s\n", bigInt.String())
// Bits() メソッドを呼び出し
bits := bigInt.Bits()
fmt.Printf("Bits() で取得したワードのスライス: %v\n", bits)
fmt.Printf("スライスの型: %T\n", bits)
// スライスの各ワードのサイズと値を確認 (64ビットシステムの場合)
// big.Word は uint64 になることが多い
if len(bits) > 0 {
fmt.Printf("最初のワードの値 (16進数): %x\n", bits[0])
if len(bits) > 1 {
fmt.Printf("2番目のワードの値 (16進数): %x\n", bits[1])
}
}
// 負の数の場合
negBigInt := new(big.Int).Neg(bigInt)
fmt.Printf("\n負の big.Int: %s\n", negBigInt.String())
negBits := negBigInt.Bits()
fmt.Printf("負の数の Bits() (絶対値): %v\n", negBits) // 絶対値が返されることに注目
}
この例では、非常に大きな整数を big.Int
で作成し、Bits()
メソッドを使ってその内部表現である big.Word
のスライスを取得しています。負の数の場合でも、Bits()
はその絶対値を返すことに注意してください。
スライスの内容の誤解(符号の欠如、エンディアン)
- トラブルシューティング:
- 符号:
Bits()
は数値の絶対値のビット表現を返します。元のbig.Int
が負の数であっても、返されるスライスは正の数として扱われます。符号の情報はbig.Int.Sign()
メソッドで取得する必要があります。 - エンディアン: スライスは「最下位ワードから最上位ワード」の順で並んでいます。つまり、スライス内のインデックス0の要素が数値の最も下位のビットを含み、インデックスが増えるにつれて上位のビットを表します。他のシステムやライブラリとの連携でエンディアン(バイトオーダー)を考慮する必要がある場合は、この点を念頭に置いて変換を行う必要があります。Goの
math/big
パッケージは、内部的にリトルエンディアンでワードを扱いますが、バイト列に変換する場合はbig.Int.Bytes()
メソッドの挙動(ビッグエンディアン)も理解しておく必要があります。
- 符号:
- エラー:
Bits()
が返す[]big.Word
スライスが、期待するビットパターンや符号の情報を含んでいないと誤解する。
返されたスライスの直接変更
-
トラブルシューティング:
Bits()
で取得したスライスの内容を変更する必要がある場合は、必ずコピーを作成してから操作を行ってください。例えば、newBits := make([]big.Word, len(bits))
のように新しいスライスを作成し、copy(newBits, bits)
で内容をコピーします。- 変更したワード列を
big.Int
に戻す場合は、big.Int.SetBits()
メソッドを使用します。
package main import ( "fmt" "math/big" ) func main() { x := big.NewInt(10) fmt.Printf("Original x: %s, Bits: %v\n", x.String(), x.Bits()) // Original x: 10, Bits: [10] // Bits() で取得したスライスを直接変更する (BAD PRACTICE!) bits := x.Bits() if len(bits) > 0 { bits[0] = 20 // x の値が意図せず変更される } fmt.Printf("Modified x (BAD): %s, Bits: %v\n", x.String(), x.Bits()) // Modified x (BAD): 20, Bits: [20] // 適切な方法: コピーを作成して変更し、SetBits() で設定し直す y := big.NewInt(30) fmt.Printf("Original y: %s, Bits: %v\n", y.String(), y.Bits()) yBits := make([]big.Word, len(y.Bits())) copy(yBits, y.Bits()) // コピーを作成 if len(yBits) > 0 { yBits[0] = 40 // コピーしたスライスを変更 } y.SetBits(yBits) // 変更したスライスを元の big.Int に設定し直す fmt.Printf("Modified y (GOOD): %s, Bits: %v\n", y.String(), y.Bits()) // Modified y (GOOD): 40, Bits: [40] }
-
エラー:
Bits()
が返すスライスは、big.Int
の内部表現への直接の参照であるため、このスライスを直接変更すると、元のbig.Int
の値が意図せず変更されてしまう可能性がある。
big.Word のサイズとシステムのアーキテクチャ
- トラブルシューティング:
big.Word
の実際のサイズに依存するロジック(例:ビットシフトの量)を書く場合は、unsafe.Sizeof(big.Word(0))
を使用して実行時のサイズを確認するか、uint
のサイズを考慮して汎用的なコードを書く必要があります。- 通常は、
big.Int
のメソッド (SetBit
,Bit
,Lsh
,Rsh
など) を使用する方が、プラットフォームに依存しない安全なコードになります。Bits()
は、より低レベルなデータ変換が必要な場合に限定して使用するのが良いでしょう。
- エラー:
big.Word
が常に特定のビットサイズ(例:64ビット)であると仮定してしまう。big.Word
はuint
のエイリアスであり、システムのアーキテクチャ(32ビットまたは64ビット)によってそのサイズが異なります。
空のスライスまたはゼロ値の big.Int の扱い
-
トラブルシューティング:
Bits()
が返すスライスの長さを常にチェックし、空である可能性を考慮したコードを書きます。
package main import ( "fmt" "math/big" ) func main() { zeroInt := big.NewInt(0) zeroBits := zeroInt.Bits() fmt.Printf("Zero big.Int Bits: %v (Length: %d)\n", zeroBits, len(zeroBits)) // Zero big.Int Bits: [] (Length: 0) // スライスの長さをチェックする if len(zeroBits) == 0 { fmt.Println("The big.Int is zero (or empty).") } }
-
エラー:
big.NewInt(0)
のようにゼロ値のbig.Int
や、まだ値が設定されていないbig.Int
に対してBits()
を呼び出したときに、空のスライスが返されることを考慮していない。
Bits() と Bytes() の違いの混同
- トラブルシューティング:
big.Int.Bits()
:big.Word
のスライスを返します。これは数値の内部表現に近いもので、システム依存のワードサイズに基づきます。big.Int.Bytes()
: 数値の絶対値をビッグエンディアンのバイト列([]byte
)として返します。これはバイトオーダーに依存せず、ネットワーク転送やファイル保存などによく使われます。- 用途に応じて適切なメソッドを選択してください。バイト列が必要な場合は通常
Bytes()
を使用します。
- エラー:
Bits()
とBytes()
の役割を混同し、期待するバイト列が得られない。
big.Int.Bits()
は big.Int
の低レベルな内部表現にアクセスするための手段であり、主に特定の最適化や、big.Int
のデータを他のフォーマットに変換する際に使用されます。一般的な算術演算や、単に big.Int
の値を扱いたいだけであれば、このメソッドを直接使う必要はほとんどありません。
もし Bits()
を使用する際は、以下の点に注意してください。
big.Word
のサイズ:システムのアーキテクチャによって異なります。- エンディアンの理解:ワードの順序(最下位から最上位)を理解してください。
- スライスは内部参照:返されたスライスの変更は元の
big.Int
に影響します。変更するなら必ずコピーを。 - 符号は含まれない:常に絶対値のビット表現が返されます。
big.Int.Bits()
は、big.Int
の内部表現(符号なしワードのスライス)にアクセスするためのメソッドです。これは主に、低レベルなビット操作、シリアライズ/デシリアライズ、または他のシステムとの連携で使われます。
例1: big.Int
の内部ワードを確認する
この例では、big.Int
の数値がどのように big.Word
のスライスとして表現されるかを確認します。
package main
import (
"fmt"
"math/big"
)
func main() {
// 非常に大きな整数を定義 (10進数)
numStr := "18446744073709551615" // これは 2^64 - 1 (uint64 の最大値)
numStr2 := "18446744073709551616" // これは 2^64 (uint64 の最大値 + 1)
// big.Int を作成
x := new(big.Int)
x.SetString(numStr, 10)
y := new(big.Int)
y.SetString(numStr2, 10)
z := big.NewInt(0) // ゼロ
negX := new(big.Int).Neg(x) // 負の数
fmt.Printf("--- big.Int.Bits() の基本 --- \n")
fmt.Printf("x (2^64 - 1): %s\n", x.String())
fmt.Printf(" Bits(): %v\n", x.Bits()) // 64-bit システムでは [18446744073709551615] (単一の uint64 ワード)
fmt.Printf("\ny (2^64): %s\n", y.String())
fmt.Printf(" Bits(): %v\n", y.Bits()) // 64-bit システムでは [0 1] (0x0000000000000000, 0x0000000000000001)
// 最下位ワードが 0、2番目のワードが 1
fmt.Printf("\nz (0): %s\n", z.String())
fmt.Printf(" Bits(): %v (長さ: %d)\n", z.Bits(), len(z.Bits())) // [] (長さ 0)
fmt.Printf("\nnegX (-2^64 + 1): %s\n", negX.String())
fmt.Printf(" Bits(): %v (絶対値のビットを返すことに注意)\n", negX.Bits()) // x と同じ [18446744073709551615]
}
解説:
- 負の数
negX
の場合も、Bits()
はその絶対値のビット表現を返します。符号はスライスには含まれません。 z
(0
) の場合、Bits()
は空のスライスを返します。y
(2^64
) は、64ビットシステムでは2つのbig.Word
で表現されます。スライスは[0 1]
となり、これは「0 * 2^0 + 1 * 2^64
」を意味します。スライスの最初の要素が最下位ワード、2番目の要素が次のワードです。x
(2^64 - 1
) は、64ビットシステムでは1つのbig.Word
(uint64) で表現されます。
例2: Bits()
で取得したスライスをコピーして変更し、SetBits()
で戻す
Bits()
が返すスライスは内部参照であるため、変更する場合はコピーが必要です。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Printf("\n--- Bits() の変更と SetBits() --- \n")
// 元の big.Int
originalInt := big.NewInt(1234567890) // 10進数
fmt.Printf("Original big.Int: %s\n", originalInt.String())
fmt.Printf(" Original Bits: %v\n", originalInt.Bits())
// Bits() で取得したスライスをコピー
// make([]big.Word, len(originalInt.Bits())) で新しいスライスを作成
// copy() で内容をコピー
clonedBits := make([]big.Word, len(originalInt.Bits()))
copy(clonedBits, originalInt.Bits())
// コピーしたスライスを操作 (最下位ワードを倍にする例)
if len(clonedBits) > 0 {
clonedBits[0] *= 2 // 最下位ワードを2倍
}
fmt.Printf(" Modified Cloned Bits: %v\n", clonedBits)
// 新しい big.Int を作成し、変更したワードで設定
modifiedInt := new(big.Int)
modifiedInt.SetBits(clonedBits) // SetBits() でワードスライスから big.Int を構築
fmt.Printf("Modified big.Int (using SetBits): %s\n", modifiedInt.String())
// 元の big.Int は変更されていないことを確認
fmt.Printf("Original big.Int (unchanged): %s\n", originalInt.String())
}
解説:
originalInt
のBits()
を取得し、それをclonedBits
という新しいスライスにコピーします。clonedBits
の内容(ここでは最下位ワード)を変更します。modifiedInt := new(big.Int)
で新しいbig.Int
を作成し、modifiedInt.SetBits(clonedBits)
を使って、変更したワードスライスからこのbig.Int
の値を設定します。originalInt
は変更されていないことを確認できます。
Bits()
と Bytes()
の違いを理解することは重要です。
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Printf("\n--- Bits() と Bytes() の比較 --- \n")
num := big.NewInt(0x1234567890ABCDEF) // 16進数で大きな数を定義
fmt.Printf("Original big.Int: %s (0x%x)\n", num.String(), num.Uint64())
// Bits() で取得
bits := num.Bits()
fmt.Printf(" Bits() (big.Wordスライス): %v\n", bits) // 64-bitシステムなら [13117684674637903215] (0x1234567890ABCDEF)
// Bytes() で取得 (ビッグエンディアンのバイトスライス)
bytes := num.Bytes()
fmt.Printf(" Bytes() ([]byte): %x\n", bytes) // 例: [12 34 56 78 90 ab cd ef] (ビッグエンディアン)
// Bits() の各ワードをバイト列に変換する例 (手動でエンディアンを考慮する必要がある)
fmt.Printf(" Bits() をバイトに変換 (手動): ")
for _, word := range bits {
// big.Word のサイズは uint のサイズに依存 (通常は 4 または 8 バイト)
// バイナリエンコーディングはシステムのエンディアンに依存する
// ここでは簡略化のために、直接バイトにキャスト
// 実際の変換には encoding/binary がより適切
for i := 0; i < big.Word(0).BitLen()/8; i++ { // big.Word が何ビットかによってループ回数を調整
// 各ワードをリトルエンディアンでバイトに変換する (仮定)
// 注意: これはプラットフォームのエンディアンと big.Word のサイズに依存します
fmt.Printf("%02x", byte(word>>(8*i)))
}
}
fmt.Println()
// Bytes() から big.Int を再構築
reconstructedInt := new(big.Int).SetBytes(bytes)
fmt.Printf(" Bytes() から再構築: %s (0x%x)\n", reconstructedInt.String(), reconstructedInt.Uint64())
}
解説:
Bits()
からバイト列を生成する場合は、big.Word
のサイズとシステムのエンディアンを意識して、encoding/binary
パッケージなどを使って慎重に変換する必要があります。Bytes()
は[]byte
スライスを返し、これはバイトオーダー(ビッグエンディアン)が保証されます。通常、データの永続化やネットワーク転送にはBytes()
が適しています。Bits()
はbig.Word
のスライスを返しますが、これはシステムのワードサイズに依存します。
big.Int.Bits()
は、big.Int
の内部表現に深く踏み込むためのメソッドであり、主に以下のような高度な用途で利用されます。
- 相互運用性: 他の言語やシステムで、特定の多倍長整数の内部表現とGoの
big.Int
の間で変換が必要な場合。 - 特定のビットパターンの直接操作: 特定のワードやビットフラグを直接読み書きする場合(ただし、通常は
big.Int
のビット操作メソッドを使う方が安全)。 - カスタムシリアライズ/デシリアライズ:
big.Int
を特定の形式のバイト列に変換する場合。
big.Int.Bits()
の主な用途と代替方法
big.Int.Bits()
は主に以下の目的で使用されます。
- 数値の内部ワード表現へのアクセス: 個々の
big.Word
を調べたり操作したりするため。 - シリアライズ/デシリアライズ:
big.Int
をバイト列に変換して保存したり、ネットワーク経由で送信したりするため。 - 特定のビット操作: 特定のビットの値を直接読み書きするため。
これらの用途に対する代替方法を見ていきましょう。
代替方法1: バイト列への変換 (big.Int.Bytes()
および big.Int.SetBytes()
)
目的: big.Int
の値をバイト列に変換して永続化したり、ネットワークで送信したり、あるいはバイト列から big.Int
を再構築したりする場合。
Bits()
を使う場合の注意点:
- バイト列への変換には、手動でのエンディアン変換やパディングの処理が必要になる場合があります。
- 符号情報は含まれません。
- スライスの要素の順序は最下位ワードから最上位ワードです(リトルエンディアン的)。
Bits()
は[]big.Word
を返し、big.Word
のサイズはシステムに依存します(32ビットまたは64ビット)。
代替方法:
big.Int.SetBytes(buf []byte)
: ビッグエンディアンのバイト列からbig.Int
の値を設定します。big.Int.Bytes()
:big.Int
の絶対値をビッグエンディアンのバイト列 ([]byte
) として返します。これはネットワークバイトオーダーとしても知られており、異なるシステム間でのデータ交換に非常に適しています。
利点:
- 効率性: Goの内部で最適化された実装が使用されます。
- 使いやすさ:
Bits()
に比べて、より高レベルな抽象化がされており、内部ワードのサイズやエンディアンを意識する必要がありません。 - エンディアンの統一: 常にビッグエンディアンであるため、異なるシステム間でのデータのやり取りが容易です。
- プラットフォーム非依存:
Bytes()
が返すバイト列は、システム(32ビット/64ビット)に依存しません。
例:
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("--- バイト列変換の代替方法 (Bytes() / SetBytes()) ---")
// 大きな整数
num := new(big.Int)
num.SetString("123456789012345678901234567890", 10)
fmt.Printf("元の big.Int: %s\n", num.String())
// big.Int をバイト列に変換 (Bytes() を使用)
data := num.Bytes()
fmt.Printf("Bytes() で変換したバイト列 (16進数): %x\n", data)
// バイト列から big.Int を再構築 (SetBytes() を使用)
reconstructedNum := new(big.Int)
reconstructedNum.SetBytes(data)
fmt.Printf("SetBytes() で再構築した big.Int: %s\n", reconstructedNum.String())
// 負の数も同様 (Bytes() は絶対値を返す)
negNum := new(big.Int).Neg(num)
fmt.Printf("\n負の big.Int: %s\n", negNum.String())
negData := negNum.Bytes()
fmt.Printf("負の数の Bytes() (絶対値): %x\n", negData) // num のバイト列と同じ
}
代替方法2: ビット操作 (big.Int.Bit()
, big.Int.SetBit()
, big.Int.Lsh()
, big.Int.Rsh()
)
目的: big.Int
の特定のビットの値を取得したり設定したり、ビットシフトを行ったりする場合。
Bits()
を使う場合の注意点:
- 手動でのビットシフトやマスク操作は複雑になりがちです。
big.Word
のサイズに依存する計算が必要になります。- 特定のビットにアクセスするには、どの
big.Word
のどの位置に目的のビットがあるかを計算する必要があります。
代替方法:
big.Int.Rsh(x *big.Int, n uint)
:x
をn
ビット右シフトした新しいbig.Int
を返します。big.Int.Lsh(x *big.Int, n uint)
:x
をn
ビット左シフトした新しいbig.Int
を返します。big.Int.SetBit(x *big.Int, i int, b uint)
:x
のi
番目のビットをb
(0または1)に設定した新しいbig.Int
を返します。big.Int.Bit(i uint)
: 指定されたインデックスi
のビット(0または1)を返します。
利点:
- パフォーマンス: ライブラリの内部で効率的に実装されています。
- 安全性:
big.Word
のサイズや内部構造を意識する必要がありません。 - シンプルさ: 特定のビットの操作やシフトが直感的に行えます。
例:
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("\n--- ビット操作の代替方法 (Bit(), SetBit(), Lsh(), Rsh()) ---")
val := big.NewInt(100) // 10進数 100 (バイナリ: 01100100)
fmt.Printf("元の big.Int: %s (バイナリ: %b)\n", val.String(), val)
// Bit() を使用して特定のビットをチェック
fmt.Printf(" ビット 2: %d\n", val.Bit(2)) // 01100100 -> 0 (2番目のビットは0)
fmt.Printf(" ビット 5: %d\n", val.Bit(5)) // 01100100 -> 1 (5番目のビットは1)
// SetBit() を使用して特定のビットを設定
// val の 0番目のビットを 1 に設定 (奇数にする)
valWithBitSet := new(big.Int).SetBit(val, 0, 1)
fmt.Printf(" 0番目のビットを1に設定: %s (バイナリ: %b)\n", valWithBitSet.String(), valWithBitSet)
// Lsh() (左シフト) を使用
shiftedLeft := new(big.Int).Lsh(val, 2) // 2ビット左シフト (x4)
fmt.Printf(" 2ビット左シフト: %s (バイナリ: %b)\n", shiftedLeft.String(), shiftedLeft)
// Rsh() (右シフト) を使用
shiftedRight := new(big.Int).Rsh(val, 3) // 3ビット右シフト (x1/8)
fmt.Printf(" 3ビット右シフト: %s (バイナリ: %b)\n", shiftedRight.String(), shiftedRight)
}
代替方法3: 文字列変換 (big.Int.String()
, big.Int.SetString()
)
目的: big.Int
の値を人間が読める形式(10進数、16進数など)で表示したり、文字列から big.Int
を作成したりする場合。
Bits()
を使う場合の注意点:
Bits()
は内部のワードのスライスを返すため、それを人間が読める文字列に変換するには、自分でロジックを実装する必要があります。これは非常に複雑になります。
代替方法:
big.Int.SetString(s string, base int)
: 指定された基数の文字列からbig.Int
の値を設定します。big.Int.Text(base int)
: 指定された基数(2〜62)の文字列として値を返します。big.Int.String()
: 10進数文字列として値を返します。
利点:
- 使いやすさ: 最もシンプルで直感的な方法です。
- 可読性: ほとんどのデバッグや表示のシナリオで最適です。
例:
package main
import (
"fmt"
"math/big"
)
func main() {
fmt.Println("\n--- 文字列変換の代替方法 (String(), Text(), SetString()) ---")
// big.Int を作成
myInt := new(big.Int)
myInt.SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) // 16進数で大きな数を設定
// String() で10進数文字列に変換
fmt.Printf("10進数文字列: %s\n", myInt.String())
// Text() で異なる基数の文字列に変換
fmt.Printf("16進数文字列: %s\n", myInt.Text(16))
fmt.Printf("2進数文字列: %s\n", myInt.Text(2))
// 文字列から big.Int を再構築
strVal := "98765432109876543210"
reconstructedFromStr := new(big.Int)
reconstructedFromStr.SetString(strVal, 10)
fmt.Printf("文字列から再構築: %s\n", reconstructedFromStr.String())
}
ほとんどのケースで上記の代替方法が推奨されますが、big.Int.Bits()
が依然として最適な、または唯一の選択肢となるシナリオも存在します。
- デバッグ/内部構造の調査:
big.Int
の内部がどのように動作しているかを深く理解するために、一時的にBits()
を使用する場合があります。 - 非常に低レベルなパフォーマンス最適化: 極めて特殊なケースで、
Bytes()
や他のメソッドよりも、big.Word
レベルでの直接操作がパフォーマンス上優位になる場合。ただし、これは稀であり、プロファイリングで確認する必要があります。 - 特定の外部ライブラリとの連携: 他のシステムやライブラリが、Goの
big.Int
の内部big.Word
表現と完全に一致する独自の多倍長整数フォーマットを使用している場合。この場合、手動でbig.Word
のスライスを変換する必要があるかもしれません。