将浮点数舍入到特定的小数位数

时间:2019-10-04 15:26:11

标签: haskell floating-point rounding

我试图显示一个浮点数,但将其四舍五入,

f = 5.545

显示为:5.55

f = 5.544 

显示为:5.54

我见过只显示两个小数点的方法,但是我想将其四舍五入。

谢谢!

2 个答案:

答案 0 :(得分:0)

之所以发生这种情况,是因为浮点数在计算机中的表示方式是:它们实际上以2为底,而不是以10为底(有点过分简化,但足够好)。因此,当您键入0.545时,计算机实际上将其记录为0.5499999999...-非常接近0.545,但略小。而且由于它小于0.545,因此也难怪它会四舍五入为0.54

如果您确实必须有精确的以10为底的数字,您应该使用Decimal而不是FloatDouble。该软件包特别注意以10为基数表示浮点数,而不会丢失。

x :: Decimal
x = 0.545

show x
> "0.545"

需要注意的是printf不支持Decimal,因此您必须通过roundTo进行四舍五入并通过show转换为字符串来显示它。 roundTo进行“银行取整”的另一个注意事项-如果最后一位为5,则将其舍入为最接近的偶数数字,因此,作为特殊情况,我们需要予以抵消(我找不到可以通过算术规则四舍五入的现成函数):

displayDecimal :: Decimal -> String
displayDecimal x = show (rounded + compensate)
    where rounded = roundTo 2 x
          compensate = if (x - rounded) == 0.005 then 0.01 else 0

displayDecimal 0.545
> "0.55"

displayDecimal 0.5450000000001
> "0.55"

displayDecimal 0.544
> "0.54"

displayDecimal 0.5449999999999
> "0.54"

但是,如果您只希望将其用于具有小数点后三位的数字,则可以避免在四舍五入之前仅添加一个很小的值,例如0.00001。此值足够小,不会混淆您的实际数字,但又足够大,可以补偿以2为基数与以10为基数的差异:

displayRounded :: Double -> String            
displayRounded x = printf "%.2f" (x + 0.00001)

displayRounded 0.544
> "0.54"

displayRounded 0.545
> "0.55"

答案 1 :(得分:0)

所以我还没有找到一个真正的解决方案,但是我意识到了:

Printf已经完成了工作,但不完全是我想要的。 假设我要舍入1.445,它将显示1.44。但是,如果数字为1.446,则显示为1.45。

并不是我想要的,但是足够接近。