为什么2.9000000000000004而不是2.9?
这个问题在这里已经有了答案:
我如何告诉ghci不要这样做,并像其他编程语言(和计算器)一样,每两年15岁就会显示双倍操作的结果?
由于这些结果是GHCI(和标准计算器*)计算的实际结果,因此您无法更改结果的内部表示形式(请参阅TNI的答案)。 既然你只想显示一个固定的小数位数,那么它更像是一个演示文稿(与printf("%f.2",...)
)。
这个解决方案可以在https://stackoverflow.com/a/2327801/1139697找到。 它可以像这样应用:
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",...]
请注意,如果您想继续计算,这将不可行。 如果你想要精确的算术,你最好还是使用Rationals
。 不要忘记,在这种情况下,你的投入应该是理性的。
*是的,即使你的标准计算器也做同样的事情,你没有看到它的唯一原因是固定的演示文稿,它不能显示超过固定的小数位数。
为什么会发生?
因为某些浮点数不能用没有舍入的有限位数表示。 浮点数字的位数是有限的,它们不能准确地表示所有的实数:当位数多于格式允许的数字时,剩余的数字被省略 - 数字被舍入。
你应该阅读每个计算机科学家应该知道的关于浮点算术和这个答案。
这是浮点数的本质,它们不能准确表示真实(或合理)的数字。 Haskell默认转换为字符串可确保在读取数字时获得完全相同的表示形式。 如果你想以不同的方式打印数字,你可以使自己的类型显示不同的数字。
像(未经测试)的东西:
newtype MyDouble = MyDouble {getMyDouble :: Double}
deriving (Eq, Ord, Num, Real, RealFrac, Fractional, Floating)
instance Show MyDouble where show = printf "%g" . getMyDouble
default (MyDouble)
这将创建一个Double
类型的副本,但使用不同的Show
实例,只打印几位小数。 default
声明使得编译器在存在歧义时选择此类型。 哦,为了使这项工作,你需要一些语言扩展。
您也可以尝试numbers
包中的CReal
类型。