英文:
Why are these 2 big Float values not equal?
问题
在过去的两周里,我一直在研究浮点数的行为和功能,特别是在Go语言中的大浮点数。我遇到了许多行为,并通过自己找到了答案。但是,还有一个答案我找不到。
为什么这两个操作的结果不相等?根据我的理解,这与精度/准确性/舍入模式有关。
谢谢!
英文:
During the past 2 weeks I have been studying the behaviour and functionalities of floating points and specifically big Floats in GO . I encountered numerous behaviours and found answers by myself. But still, there is one answer I couldn't find myself.
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)
Why is the result of these 2 operations not equal? From my understanding it is something that has to do with precision/accuracy/rounding mode.
Thank you!
答案1
得分: 0
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
的内部不同(在这个例子中是准确性)。在这种情况下,即使你可以比较指向的对象,它们也不会相同,但表示的数字是相等的。再次强调,始终使用提供的方法来比较复杂对象,而不是地址。
这个例子中的差异来自存储的准确性字段:
fmt.Println(value1.Acc())
fmt.Println(value3.Acc())
输出结果为(在Go Playground上尝试):
Below
Exact
Float.Acc()
返回的准确性是“最近操作产生的x的准确性”。由于对value1
和value3
执行的最后一个操作不同(value1.Sub()
和value3.Set()
),准确性字段不一定相同(在这个例子中它们是不同的)。由于准确性属性也包含在Gob序列化形式中,这就是它们的序列化形式不同的原因。
英文:
value1
and value3
are pointers, so value1 == value3
compares those pointers, not the pointed values. It may be possible 2 pointed objects are equal yet their addresses are not.
To compare big.Float
values (or *big.Float
), use the Float.Cmp()
method. It returns 0
if the 2 values (the numbers they represent) are equal.
if value1.Cmp(value3) == 0 {
fmt.Println("values are equal", value1, value3)
} else {
fmt.Println("values are not equal", value1, value3)
}
With this change output will be (try it on the 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]
So the represented numbers are equal.
The serialized binary form returned by Float.GobEncode()
is not the same, but that doesn't mean the represented numbers are not equal. As its documentation states:
> GobEncode implements the gob.GobEncoder interface. The Float value and all its attributes (precision, rounding mode, accuracy) are marshaled.
The output is different because internals of big.Float
are not the same (in this case the Accuracy). In this case even if you could compare the pointed objects, those would not be the same, but the represented numbers are. Again, always use the provided methods to compare complex objects, and certainly not the addresses.
The difference in this example comes from the stored accuracy field:
fmt.Println(value1.Acc())
fmt.Println(value3.Acc())
Which outputs (try it on the Go Playground):
Below
Exact
The accuracy returned by Float.Acc()
is the "accuracy of x produced by the most recent operation". Since the last operation performed on value1
and value3
are not the same (value1.Sub()
and value3.Set()
), the accuracy field is not necessarily the same (and in this example they do differ). And since the accuracy property is also included in the Gob serialized form, that's why their serialized forms are different.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论