big.Float SetPrec奇怪的行为

时间:2018-02-16 03:21:20

标签: go

在golang中使用big.Float进行一些计算后,我将精度设置为2。

即使这个数字只是一个简单的10,在设定精度后它是8。

package main

import (
    "fmt"
    "math/big"
)

func main() {
    cost := big.NewFloat(10)
    fmt.Println("COST NOW", cost)

    perKWh := big.NewFloat(0)
    cost.Add(cost, perKWh)
    fmt.Println("COST ", cost.String())

    perMinute := big.NewFloat(0)
    cost.Add(cost, perMinute)
    fmt.Println("COST ", cost.String())

    discountAmount := big.NewFloat(0)
    cost.Sub(cost, discountAmount)
    floatCos, _ := cost.Float64()
    fmt.Println(fmt.Sprintf("COST FLOAT %v", floatCos))
    cost.SetPrec(2)

    fmt.Println("COST ", cost.String())
}

点击这里的游乐场示例:https://play.golang.org/p/JmCRXkD5u49

想了解原因

2 个答案:

答案 0 :(得分:3)

来自fine manual

  

键入Float
  [...]
  每个Float值还具有精度,舍入模式和精度。精度是可用于表示该值的最大尾数位数。舍入模式指定如何舍入结果以适合尾数位,精确度描述与精确结果相关的舍入误差。

big.Float在内部表示为:

sign × mantissa × 2**exponent

当您致电SetPrec时,您正在为尾数设置的数量,而不是该数字的十进制表示中的精度位数。

您不能在两位尾数中表示十进制10(1010二进制),因此它舍入到十进制8(1000二进制),可以容纳2位。你需要至少三位才能存储小数10的101部分.8可以放入一个尾数位,所以如果你说cost.SetPrec(1),你会看到相同的8位。

在使用大包时,你需要考虑二进制。

答案 1 :(得分:2)

首先,丢弃所有不相关的代码。接下来,打印有用的诊断信息。

package main

import (
    "fmt"
    "math/big"
)

func main() {
    cost := big.NewFloat(10)
    fmt.Println("Cost ", cost.String())
    fmt.Println("Prec", cost.Prec())
    fmt.Println("MinPrec", cost.MinPrec())
    fmt.Println("Mode", cost.Mode())
    cost.SetPrec(2)
    fmt.Println("Prec", cost.Prec())
    fmt.Println("Accuracy", cost.Acc())
    fmt.Println("Cost ", cost.String())
}

输出:

Cost  10
Prec 53
MinPrec 3
Mode ToNearestEven
Prec 2
Accuracy Below
Cost  8

第10轮到最近的偶数,可用符号,指数和2位尾数表示,得到8。

Rounding ToNearestEven是IEE754舍入。舍入到最近,连接到偶数 - 舍入到最接近的值;如果数字中间下降,则使用偶数(零)最低有效位四舍五入到最接近的值。