为什么这两个大的 Float 值不相等?
Why are these 2 big Float values not equal?
在过去的两周里,我一直在研究浮点数的行为和功能,特别是 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)
为什么这2个操作的结果不相等?据我了解,这与 precision/accuracy/rounding 模式有关。
谢谢!
value1
和 value3
是指针,所以 value1 == value3
比较的是这些指针,而不是指向的值。有可能 2 个指向的对象相等但它们的地址不相等。
比较big.Float
values (or *big.Float
), use the Float.Cmp()
方法。 returns 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 implements the gob.GobEncoder interface. The Float value and all its attributes (precision, rounding mode, accuracy) are marshaled.
输出不同,因为 big.Float
的内部结构不同(在本例中为准确度)。在这种情况下,即使您可以比较指向的对象,它们也不会相同,但表示的数字是相同的。同样,始终使用提供的方法来比较复杂对象,当然不是地址。
此示例中的差异来自存储的精度字段:
fmt.Println(value1.Acc())
fmt.Println(value3.Acc())
哪些输出(在 Go Playground 上尝试):
Below
Exact
Float.Acc()
返回的准确度是“最近一次操作产生的x的准确度”。由于在 value1
和 value3
上执行的最后一个操作不相同(value1.Sub()
和 value3.Set()
),因此精度字段不一定相同(在本例中它们是相同的)不同)。并且由于精度属性也包含在Gob序列化形式中,这就是为什么它们的序列化形式不同。
在过去的两周里,我一直在研究浮点数的行为和功能,特别是 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)
为什么这2个操作的结果不相等?据我了解,这与 precision/accuracy/rounding 模式有关。
谢谢!
value1
和 value3
是指针,所以 value1 == value3
比较的是这些指针,而不是指向的值。有可能 2 个指向的对象相等但它们的地址不相等。
比较big.Float
values (or *big.Float
), use the Float.Cmp()
方法。 returns 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 implements the gob.GobEncoder interface. The Float value and all its attributes (precision, rounding mode, accuracy) are marshaled.
输出不同,因为 big.Float
的内部结构不同(在本例中为准确度)。在这种情况下,即使您可以比较指向的对象,它们也不会相同,但表示的数字是相同的。同样,始终使用提供的方法来比较复杂对象,当然不是地址。
此示例中的差异来自存储的精度字段:
fmt.Println(value1.Acc())
fmt.Println(value3.Acc())
哪些输出(在 Go Playground 上尝试):
Below
Exact
Float.Acc()
返回的准确度是“最近一次操作产生的x的准确度”。由于在 value1
和 value3
上执行的最后一个操作不相同(value1.Sub()
和 value3.Set()
),因此精度字段不一定相同(在本例中它们是相同的)不同)。并且由于精度属性也包含在Gob序列化形式中,这就是为什么它们的序列化形式不同。