为什么这两个大浮点数值不相等?

huangapple go评论94阅读模式
英文:

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

value1value3是指针,所以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的准确性”。由于对value1value3执行的最后一个操作不同(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.

huangapple
  • 本文由 发表于 2021年9月1日 21:41:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/69014916.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定