在过去的两周里,我一直在研究浮点数的行为和功能,特别是GO中的大浮点数。我遇到了无数的行为,我自己找到了答案。但是,有一个答案是我自己找不到的。
https://play.golang.org/p/-y0oeb2Jisv
value1 := big.NewFloat(137216723432.8234782347)
value2 := big.NewFloat(71371.92602458)
for i := 0; i < 300; i++ {
value1.Sub(value1, value2)
}
value3 := big.NewFloat(137216723432.8234782347)
value4 := big.NewFloat(71371.92602458)
for i := 0; i < 300; i++ {
result := big.NewFloat(0).Sub(value3,value4)
value3.Set(result)
}
encodedValue1, _ := value1.GobEncode()
encodedValue3, _ := value3.GobEncode()
if value1 == value3 {
fmt.Println("values are equal" , value1 , value3)
} else {
fmt.Println("values are not equal", value1 ,value3)
}
fmt.Println("difference is here:n", encodedValue1,"n", encodedValue3)
为什么这两个操作的结果不相等?根据我的理解,这与精度/精度/舍入模式有关。
谢谢!
value1
和value3
是指针,因此value1 == value3
比较的是这些指针,而不是指向的值。有可能两个有指向的对象是相等的,但它们的地址不相等。
要比较big.Float
值(或*big.Float
),请使用Float.Cmp()
方法。如果两个值(它们所代表的数字)相等,则返回0
。
if value1.Cmp(value3) == 0 {
fmt.Println("values are equal", value1, value3)
} else {
fmt.Println("values are not equal", value1, value3)
}
修改后的输出将是(在Go Playground上试试):
values are equal 1.3719531185501585e+11 1.3719531185501585e+11
difference is here:
[1 2 0 0 0 53 0 0 0 37 255 139 210 151 120 32 120 0]
[1 10 0 0 0 53 0 0 0 37 255 139 210 151 120 32 120 0]
表示的数字是相等的。
Float.GobEncode()
返回的序列化二进制形式不相同,但这并不意味着表示的数字不相等。如其文档所述:
GobEncode实现了gob。GobEncoder接口。Float值及其所有属性(精度、舍入模式、精度)将被封送。
输出是不同的,因为big.Float
的内部是不一样的(在这个例子中是Accuracy)。在这种情况下,即使您可以比较有指向的对象,它们也不会相同,但表示的数字是相同的。同样,总是使用提供的方法来比较复杂的对象,而不是地址。
这个例子中的区别来自于存储的精度字段:
fmt.Println(value1.Acc())
fmt.Println(value3.Acc())
哪个输出(在Go Playground上试试):
Below
Exact
Float.Acc()
返回的精度是最近一次操作产生的x的精度。由于对value1
和value3
执行的最后一次操作不相同(value1.Sub()
和value3.Set()
),因此精度字段不一定相同(在本例中它们确实不同)。由于精度属性也包含在Gob序列化形式中,这就是为什么它们的序列化形式是不同的。