丑陋的双打 - 为什么2.9000000000000004而不是2.9?

Den*_*der 7 haskell

当我在ghci做5.2 - 2.3时,我会得到2.9000000000000004而不是2.9.当使用Double或Float时,这样的丑陋(以及人类的错误)结果也显示在其他地方.

为什么会这样?(这只是为了好奇,而不是我真正的问题)

我真正的问题是:我如何告诉ghci不这样做,并像任何其他编程语言(和计算器)一样显示双打操作的结果,就像每个15岁的人一样写它们?

当我使用ghci作为一个不错的计算器并处理我执行此类操作的列表时,这真烦人.

map ((-)2.3) [4.0, 3.8, 5.2, 6.4, 1.3, 8.3, 13.7, 9.0, 7.5, 2.4]
[-1.7000000000000002,-1.5,-2.9000000000000004,-4.1000000000000005,0.9999999999999998,-6.000000000000001,-11.399999999999999,-6.7,-5.2,-0.10000000000000009]
Run Code Online (Sandbox Code Playgroud)

这在后来使用纸张上的数字时无效

提前致谢 :)

NIN*_*OOP 18

为什么会这样?

因为某些浮点数不能用有限数量的位表示而不能舍入. 浮点数具有有限的位数,它们不能准确地表示所有实数:当数字多于格式允许时,剩余的数字被省略 - 数字被舍入.

您应该阅读每个计算机科学家应该知道的关于浮点算术的内容这个答案.

  • 事实上,他们甚至无法代表我们在这里看到的所有理性 (2认同)

Zet*_*eta 8

我如何告诉ghci不这样做,并像任何其他编程语言(和计算器)一样显示双打操作的结果,就像每个15岁的人都会写它们一样?

由于这些结果是实际结果GHCI(和您的标准计算器*)计算您无法更改结果的内部表示(请参阅TNI的答案).由于您只想显示固定数量的小数,因此更多的是演示问题(与printf("%f.2",...)C相比).

可以在/sf/answers/162946101/中找到解决方案.它可以像这样应用:

import Numeric
fixedN :: (RealFloat b) => Int -> b -> String
fixedN a b = showFFloat (Just a) b ""

map (fixedN 2 . (-)2.3) [4.0, 3.8, 5.2, 6.4, 1.3, 8.3, 13.7, 9.0, 7.5, 2.4]
-- result: ["-1.70","-1.50","-2.90","-4.10","1.00","-6.00",...]
Run Code Online (Sandbox Code Playgroud)

请注意,如果要继续计算,这将不可行.如果你想要精确算术,那么Rationals无论如何你都会更好.在这种情况下,不要忘记你的输入应该是合理的.

*是的,即使您的标准计算器也做同样的事情,唯一的原因是您没有看到它是固定的表示,它不能显示超过固定的小数位数.