我們知道有些時候通過編程的方式去進行計算是不精確的。如果你使用 Go 語言中的 float64 類型進行浮點運算,返回結(jié)果將精確到 15 位,足以滿足大多數(shù)的任務。當對超出 int64 或者 uint64 類型這樣的大數(shù)進行計算時,如果對精度沒有要求,float32 或者 float64 可以勝任,但如果對精度有嚴格要求的時候,我們不能使用浮點數(shù),在內(nèi)存中它們只能被近似的表示。
對于整數(shù)的高精度計算 Go 語言中提供了 big 包。其中包含了 math 包:有用來表示大整數(shù)的 big.Int
和表示大有理數(shù)的 big.Rat
類型(可以表示為 2/5 或 3.1416 這樣的分數(shù),而不是無理數(shù)或 π)。這些類型可以實現(xiàn)任意位類型的數(shù)字,只要內(nèi)存足夠大。缺點是更大的內(nèi)存和處理開銷使它們使用起來要比內(nèi)置的數(shù)字類型慢很多。
大的整型數(shù)字是通過 big.NewInt(n)
來構(gòu)造的,其中 n 為 int64 類型整數(shù)。而大有理數(shù)是用過 big.NewRat(N,D)
方法構(gòu)造。N(分子)和 D(分母)都是 int64 型整數(shù)。因為 Go 語言不支持運算符重載,所以所有大數(shù)字類型都有像是 Add()
和 Mul()
這樣的方法。它們作用于作為 receiver 的整數(shù)和有理數(shù),大多數(shù)情況下它們修改 receiver 并以 receiver 作為返回結(jié)果。因為沒有必要創(chuàng)建 big.Int
類型的臨時變量來存放中間結(jié)果,所以這樣的運算可通過內(nèi)存鏈式存儲。
示例 9.2 big.go:
// big.go
package main
import (
"fmt"
"math"
"math/big"
)
func main() {
// Here are some calculations with bigInts:
im := big.NewInt(math.MaxInt64)
in := im
io := big.NewInt(1956)
ip := big.NewInt(1)
ip.Mul(im, in).Add(ip, im).Div(ip, io)
fmt.Printf("Big Int: %v\n", ip)
// Here are some calculations with bigInts:
rm := big.NewRat(math.MaxInt64, 1956)
rn := big.NewRat(-1956, math.MaxInt64)
ro := big.NewRat(19, 56)
rp := big.NewRat(1111, 2222)
rq := big.NewRat(1, 1)
rq.Mul(rm, rn).Add(rq, ro).Mul(rq, rp)
fmt.Printf("Big Rat: %v\n", rq)
}
/* Output:
Big Int: 43492122561469640008497075573153004
Big Rat: -37/112
*/
輸出結(jié)果:
Big Int: 43492122561469640008497075573153004
Big Rat: -37/112