0

在过去的两周里,我一直在研究浮点的行为和功能,特别是 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)

为什么这两个操作的结果不相等?据我了解,这与精度/准确度/舍入模式有关。

谢谢!

4

1 回答 1

0

value1andvalue3是指针,所以value1 == value3比较那些指针,而不是指向的值。有可能 2 个指向对象相等但它们的地址不相等。

要比较big.Float值(或*big.Float),请使用该Float.Cmp()方法。0如果 2 个值(它们代表的数字)相等,则返回。

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(在本例中为准确性)。在这种情况下,即使您可以比较指向的对象,它们也不会相同,但表示的数字是相同的。同样,始终使用提供的方法来比较复杂的对象,当然不是地址。

此示例中的差异来自存储的准确度字段:

fmt.Println(value1.Acc())
fmt.Println(value3.Acc())

哪些输出(在Go Playground上尝试):

Below
Exact

返回的准确度Float.Acc()是“最近一次操作产生的 x 的准确度”。value1由于对和执行的最后一个操作value3不相同(value1.Sub()value3.Set()),因此准确度字段不一定相同(在此示例中它们确实不同)。而且由于准确度属性也包含在 Gob 序列化形式中,这就是它们的序列化形式不同的原因。

于 2021-09-01T14:11:58.767 回答