英文:
Why does using Go's big.Float type sometimes results in far-less precision than normal float64's ?? As in the following code:
问题
main函数中的两个函数的逻辑是相同的。那么,为什么会有不同且非常令人费解的结果呢?
这两个函数唯一的区别在于第二个函数在整个过程中使用了更精确的类型。所以,人们会认为它应该产生更精确的结果,不是吗?
这段代码的行为是错误的。有什么解释吗?
//The following code's behavior is just wrong. What could explain this?
// π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) ...
package main
import (
"fmt"
"math/big"
)
func main(){
with_float64_types()
with_big_Float_types()
}
// logic using float64 types:
func with_float64_types() {
// float64 constants:
var four64 float64
four64 = 4
var three64 float64
three64 = 3
// float64 variables:
var digitone64 float64
digitone64 = 2
var digittwo64 float64
digittwo64 = 3
var digitthree64 float64
digitthree64 = 4
var sum64 float64
sum64 = three64 + (four64 / (digitone64*digittwo64*digitthree64))
var nextterm64 float64
// float64 proc:
iters_fl64 := 1
for iters_fl64 < 100000 { // 100,000
iters_fl64++
digitone64 = digitone64 + 2
digittwo64 = digittwo64 + 2
digitthree64 = digitthree64 + 2
nextterm64 = four64/(digitone64*digittwo64*digitthree64)
if iters_fl64 % 2 == 0 { // % is modulus operator
sum64 = sum64 - nextterm64
} else {
sum64 = sum64 + nextterm64
}
}
fmt.Printf("\nPi via Nilakantha Somayaji per float64 types is: %0.22f \n", sum64)
// prints 3.1415926535897864546598 which is ok
}
// logic using big.Float types:
func with_big_Float_types() {
// big.Float constants:
twoBig := big.NewFloat(2)
threeBig := big.NewFloat(3)
fourBig := big.NewFloat(4)
// big.Float variables:
digitoneBig := new(big.Float)
digitoneBig = twoBig
digittwoBig := new(big.Float)
digittwoBig = threeBig
digitthreeBig := new(big.Float)
digitthreeBig = fourBig
sumBig := new(big.Float)
nexttermBig := new(big.Float)
precision := 512
sumBig.SetPrec(uint(precision))
twoBig.SetPrec(uint(precision))
threeBig.SetPrec(uint(precision))
fourBig.SetPrec(uint(precision))
digitoneBig.SetPrec(uint(precision))
digittwoBig.SetPrec(uint(precision))
digitthreeBig.SetPrec(uint(precision))
nexttermBig.SetPrec(uint(precision))
sumBig.Add(threeBig, (new(big.Float).Quo(fourBig, new(big.Float).Mul(digitoneBig, new(big.Float).Mul(digittwoBig, digitthreeBig)))))
// big.Float proc:
iterBig := 1
for iterBig < 100000 { // 100,000
iterBig++
digitoneBig.Add(digitoneBig, twoBig)
digittwoBig.Add(digittwoBig, twoBig)
digitthreeBig.Add(digitthreeBig, twoBig)
nexttermBig.Quo(fourBig, new(big.Float).Mul(digitoneBig, new(big.Float).Mul(digittwoBig, digitthreeBig)))
if iterBig % 2 == 0 { // % is modulus operator
sumBig.Sub(sumBig, nexttermBig)
} else {
sumBig.Add(sumBig, nexttermBig)
}
}
fmt.Printf("\nPi via Nilakantha Somayaji per big.Float types is: %0.22f \n", sumBig)
// prints 3.1376671059697782 695252 which is very-much not ok, but why? The logic is identical. Is it not?
}
英文:
The logic of the two funcs in main are identical. So, why the different and very unintuitive results?
The two functions differ only in that the second uses a more precise type throughout. So, it is the one
that ought to yield the more precise result, one would think?
//The following code's behavior is just wrong. What could explain this?
// π = 3 + 4/(2*3*4) - 4/(4*5*6) + 4/(6*7*8) - 4/(8*9*10) + 4/(10*11*12) ...
package main
import (
"fmt"
"math/big"
)
func main(){
with_float64_types()
with_big_Float_types()
}
// logic using float64 types:
func with_float64_types() {
// float64 constants:
var four64 float64
four64 = 4
var three64 float64
three64 = 3
// float64 variables:
var digitone64 float64
digitone64 = 2
var digittwo64 float64
digittwo64 = 3
var digitthree64 float64
digitthree64 = 4
var sum64 float64
sum64 = three64 + (four64 / (digitone64*digittwo64*digitthree64))
var nextterm64 float64
// float64 proc:
iters_fl64 := 1
for iters_fl64 < 100000 { // 100,000
iters_fl64++
digitone64 = digitone64 + 2
digittwo64 = digittwo64 + 2
digitthree64 = digitthree64 + 2
nextterm64 = four64/(digitone64*digittwo64*digitthree64)
if iters_fl64 % 2 == 0 { // % is modulus operator
sum64 = sum64 - nextterm64
} else {
sum64 = sum64 + nextterm64
}
}
fmt.Printf("\nPi via Nilakantha Somayaji per float64 types is: %0.22f \n", sum64)
// prints 3.1415926535897864546598 which is ok
}
// logic using big.Float types:
func with_big_Float_types() {
// big.Float constants:
twoBig := big.NewFloat(2)
threeBig := big.NewFloat(3)
fourBig := big.NewFloat(4)
// big.Float variables:
digitoneBig := new(big.Float)
digitoneBig = twoBig
digittwoBig := new(big.Float)
digittwoBig = threeBig
digitthreeBig := new(big.Float)
digitthreeBig = fourBig
sumBig := new(big.Float)
nexttermBig := new(big.Float)
precision := 512
sumBig.SetPrec(uint(precision))
twoBig.SetPrec(uint(precision))
threeBig.SetPrec(uint(precision))
fourBig.SetPrec(uint(precision))
digitoneBig.SetPrec(uint(precision))
digittwoBig.SetPrec(uint(precision))
digitthreeBig.SetPrec(uint(precision))
nexttermBig.SetPrec(uint(precision))
sumBig.Add(threeBig, (new(big.Float).Quo(fourBig, new(big.Float).Mul(digitoneBig, new(big.Float).Mul(digittwoBig, digitthreeBig)))))
// big.Float proc:
iterBig := 1
for iterBig < 100000 { // 100,000
iterBig++
digitoneBig.Add(digitoneBig, twoBig)
digittwoBig.Add(digittwoBig, twoBig)
digitthreeBig.Add(digitthreeBig, twoBig)
nexttermBig.Quo(fourBig, new(big.Float).Mul(digitoneBig, new(big.Float).Mul(digittwoBig, digitthreeBig)))
if iterBig % 2 == 0 { // % is modulus operator
sumBig.Sub(sumBig, nexttermBig)
} else {
sumBig.Add(sumBig, nexttermBig)
}
}
fmt.Printf("\nPi via Nilakantha Somayaji per big.Float types is: %0.22f \n", sumBig)
// prints 3.1376671059697782 695252 which is very-much not ok, but why? The logic is identical. Is it not?
}
答案1
得分: 1
实际上,我在语法中发现了一个错误。我没有在变量上使用星号运算符。
原来的代码应该是这样的:
// big.Float 变量:
digitoneBig := new(big.Float)
digitoneBig = twoBig
digittwoBig := new(big.Float)
digittwoBig = threeBig
digitthreeBig := new(big.Float)
digitthreeBig = fourBig
应该修改为:
// big.Float 变量:
digitoneBig := new(big.Float)
*digitoneBig = *twoBig
digittwoBig := new(big.Float)
*digittwoBig = *threeBig
digitthreeBig := new(big.Float)
*digitthreeBig = *fourBig
英文:
Actually, I located an error in my syntax. I was failing to use the asterisk operator on my variables.
the following:
// big.Float variables:
digitoneBig := new(big.Float)
digitoneBig = twoBig
digittwoBig := new(big.Float)
digittwoBig = threeBig
digitthreeBig := new(big.Float)
digitthreeBig = fourBig
should have been:
// big.Float variables:
digitoneBig := new(big.Float)
*digitoneBig = *twoBig
digittwoBig := new(big.Float)
*digittwoBig = *threeBig
digitthreeBig := new(big.Float)
*digitthreeBig = *fourBig
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论