Why does using Go's big.Float type sometimes results in far-less precision than normal float64's ?? As in the following code:

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

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&#39;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 (
        &quot;fmt&quot; 
        &quot;math/big&quot; 
    )

    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 &lt; 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(&quot;\nPi via Nilakantha Somayaji per float64 types is: %0.22f \n&quot;, 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 &lt; 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(&quot;\nPi via Nilakantha Somayaji per big.Float types is: %0.22f \n&quot;, 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

huangapple
  • 本文由 发表于 2023年6月21日 12:31:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76519952.html
匿名

发表评论

匿名网友

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

确定