Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 小数点后1位和2位之间的舍入差_Go - Fatal编程技术网

Go 小数点后1位和2位之间的舍入差

Go 小数点后1位和2位之间的舍入差,go,Go,[埃德:改写-很抱歉让人困惑的最初措辞。也感谢所有建议使用整数的人,但出于几个原因,我必须使用float64] 我有一个浮点值,如果大于100,我想四舍五入到1位小数,如果大于1000,就不要小数,否则四舍五入到2位小数。这项工作: func r(f float64) float64 { if f >= 999.5 { return math.Round(f) } if f >= 99.95 { return math.Roun

[埃德:改写-很抱歉让人困惑的最初措辞。也感谢所有建议使用整数的人,但出于几个原因,我必须使用
float64
]

我有一个浮点值,如果大于100,我想四舍五入到1位小数,如果大于1000,就不要小数,否则四舍五入到2位小数。这项工作:

func r(f float64) float64 {
    if f >= 999.5 {
        return math.Round(f)
    }
    if f >= 99.95 {
        return math.Round(f*10) / 10
    }
    return math.Round(f*100) / 100
}
但我想知道这是否会更好:

func r(f float64) float64 {
    if f >= 999.5 {
        return math.Round(f)
    }
    if f*10 >= 999.5 {  // **** only changed line ****
        return math.Round(f*10) / 10
    }
    return math.Round(f*100) / 100
}
这更安全,因为99.95不是使用带二进制指数的浮点来精确表示的。(我相信Go语言需要使用IEEE fp格式,该格式具有二进制指数。)999.5完全可以表示为fp值

但是,我的测试(使用
math.NextAfter()
)表明,第一个解决方案对于99.94999999到99.95000001之间的所有值都非常有效。第一个问题:我担心过度


第二种解决方案的问题是,我担心
f*10
可能会被计算两次。第二个问题:是否有任何保证,优化器将确保只执行一次。

如果您关心额外的乘法,而不是依赖优化器,您可以通过以下方式将其拉出:

func r(f float64) float64 {
    if f >= 999.5 {
        return math.Round(f)
    }
    
    f *= 10
    if f >= 999.5 {
        return math.Round(f) / 10
    }
    
    f *= 10
    return math.Round(f) / 100
}

这两种方法都不太安全,因为不应该对十进制值(如货币)使用浮点运算。一种简单的方法是将货币存储为
int
美分,这避免了浮点的不精确性,并将小数点的位置完全留给渲染关注点(事实上是这样的).使用最小货币单位是一种常见的方法,正如波希米亚人所说,请记住,不同的货币在最小货币单位上有不同的分数(或者根本没有像日元那样的分数)。另请参见。使用二进制浮点无法解决您试图解决的问题。感谢@JimB回复:>两者都不是真正安全的。。。事实上,我知道第二个是完全安全的,因为它使用与
Round
相同的舍入。此外,999.5没有舍入问题。问题是关于优化器的——即我是否可以确保f*10在运行时不会被计算两次。我完全理解fp舍入问题,一般来说,它不应该用于货币。但是,这个值是由一个我无法控制的包提供给我的。此外,999.5以fp表示(无论是使用二进制还是十进制指数)。感谢@Rob Napier,这是一个非常好的观点。(我一定是大脑出了问题。)@AJR:还要注意的是,除法通常是更昂贵的一个数量级,因此虽然这是更好的代码组织,但对第二个倍数的担心可能是错误的。@JimB您是对的,进一步的改进是使用*0.1而不是/10。我想我最感兴趣的是关于Go中优化的保证。@AJR:该语言对编译器优化没有任何保证。