提问人:pseuyi 提问时间:7/20/2023 更新时间:7/20/2023 访问量:94
如何在 Haskell 中准确缩放浮点数?
How do you scale floating point numbers accurately in Haskell?
问:
我想将一些小数点后四位的数字缩放为整数。在缩放这些数字时使用(或)会导致某些数字不准确吗?round
ceiling
在 ghci 中: 期待 1009
ghci> let x = 1.009 * 1000
ghci> x
1008.9999999999999
ghci> round x
1009
ghci> floor x
1008
ghci> ceiling x
1009
预期 100900000
ghci> let y = 1.009 * 100000000
ghci> y
1.0089999999999999e8
ghci> round y
100900000
ghci> floor y
100899999
ghci> ceiling y
100900000
答:
对于序列 0.000、0.001、0.002、0.003 ...9.999、功能:
scale x = round (1000*x)
将生成“正确”的四位数结果。这是因为表达式引入的任何浮点误差都是很小的一部分,大约为 1e-13,因此,如果“正确”结果是 -- 比如 -- 1009,那么你可以得到的最小可能答案将是这样的:1000*x
1000*x
1008.9999999999999
你能得到的最大可能的答案是这样的:
1009.0000000000001
这两个整数至少比任何其他整数更接近 10,000,000,009 倍,并且由于四舍五入到最接近的整数,因此它将始终四舍五入到正确答案。round
请注意,和是完全不同的。它们不会四舍五入到最接近的整数,而是四舍五入到特定方向上最接近的整数,因此它们可以清楚地给出错误的答案。具体来说,他们可以提供:floor
ceiling
floor 1008.9999999999999 == 1008 -- wrong!
ceiling 1009.0000000000001 == 1010 -- wrong!
缩放使用也适用于更大的缩放,在一定程度上 - 具体来说,缩放到1e16左右的点。如果缩放比例为“仅”1e15,则转换仍然有效(对于上述序列中的所有人):round
x
scale x = round (1000000000000000*x)
但是,当缩放比例为 1e16 时:
scale x = round (10000000000000000*x)
你开始得到错误的答案:
ghci> scale 0.5005
5004999999999999
如果要获得所有缩放的正确答案,请分两部分进行缩放:
scale :: RealFrac n => n -> Integer
scale x = 10000000000000000000000000000000000 * round (10000*x)
在这里,表达式可靠地将序列 0.000, 0.001, ..., 9.999 中的任意数字缩放到序列 0, 1, ..., 9999 中的相应整数,而不会出现浮点错误,如上所述。从那里开始,任意精度乘以任何整数,无论多大,都将没有错误。round (10000*x)
Integer
评论
round
floor
ceiling
1008.9999999999999
1.009
Double
Double
1.009
1.008999999999999896971303314785473048686981201171875
1008.9999...
1009