9.4 精密計算和 big 包
我們知道有些時候通過編程的方式去進行計算是不精確的。如果你使用 Go 語言中的 float64 類型進行浮點運算,返回結果將精確到 15 位,足以滿足大多數的任務。當對超出 int64 或者 uint64 類型這樣的大數進行計算時,如果對精度沒有要求,float32 或者 float64 可以勝任,但如果對精度有嚴格要求的時候,我們不能使用浮點數,在內存中它們只能被近似的表示。
對於整數的高精度計算 Go 語言中提供了 big 包。其中包含了 math 包:有用來表示大整數的 big.Int
和表示大有理數的 big.Rat
類型(可以表示爲 2/5 或 3.1416 這樣的分數,而不是無理數或 π)。這些類型可以實現任意位類型的數字,只要內存足夠大。缺點是更大的內存和處理開銷使它們使用起來要比內置的數字類型慢很多。
大的整型數字是通過 big.NewInt(n)
來構造的,其中 n 爲 int64 類型整數。而大有理數是用過 big.NewRat(N,D)
方法構造。N(分子)和 D(分母)都是 int64 型整數。因爲 Go 語言不支持運算符重載,所以所有大數字類型都有像是 Add()
和 Mul()
這樣的方法。它們作用於作爲 receiver 的整數和有理數,大多數情況下它們修改 receiver 並以 receiver 作爲返回結果。因爲沒有必要創建 big.Int
類型的臨時變量來存放中間結果,所以這樣的運算可通過內存鏈式存儲。
示例 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
*/
輸出結果:
Big Int: 43492122561469640008497075573153004
Big Rat: -37/112