我正在尝试创建一个函数,将浮点数字舍入到定义的数字长度。到目前为止,我想出的是:
import Numeric;
digs :: Integral x => x -> [x] <br>
digs 0 = [] <br>
digs x = digs (x `div` 10) ++ [x `mod` 10]
roundTo x t = let d = length $ digs $ round x <br>
roundToMachine x t = (fromInteger $ round $ x * 10^^t) * 10^^(-t)
in roundToMachine x (t - d)我使用digs函数来确定逗号之前的数字数,以优化输入值(即将所有内容移过逗号,使1.234变为0.1234 * 10^1)。
roundTo函数似乎适用于大多数输入,但是对于某些输入,我得到了奇怪的结果,例如roundTo 1.0014 4生成1.0010000000000001而不是1.001。
此示例中的问题是由计算1001 * 1.0e-3 (返回1.0010000000000001)引起的。
这仅仅是我必须接受的Haskell数字表示中的一个问题,还是有更好的方法将浮点数字舍入到特定长度的数字?
发布于 2013-09-10 16:00:38
这不是haskell问题,也不是浮点问题。由于每个浮点数都是在有限的位数中实现的,因此存在不能完全精确表示的数字。您还可以通过计算0.1 + 0.2来看到这一点,它笨拙地返回0.30000000000000004而不是0.3。这与如何为语言和硬件体系结构实现浮点数有关。
解决方案是继续使用roundTo函数进行计算(它与没有特殊库的精度一样高),但是如果要将其打印到屏幕上,则应该使用字符串格式(如Text.Printf.printf函数)。在转换为字符串时,可以指定要舍入的数字数,如下所示
import Text.Printf
roundToStr :: (PrintfArg a, Floating a) => Int -> a -> String
roundToStr n f = printf ("%0." ++ show n ++ "f") f但正如我所提到的,这将返回一个字符串,而不是一个数字。
编辑:
更好的办法可能是
roundToStr :: (PrintfArg a, Floating a) => Int -> a -> String
roundToStr n f = printf (printf "%%0.%df" n) f但我还没有设定基准来看看哪一个更快。不过,两者的工作原理完全一样。
编辑2:
正如@augustss所指出的,您可以更轻松地使用
roundToStr :: (PrintfArg a, Floating a) => Int -> a -> String
roundToStr = printf "%0.*f"它使用了我以前不知道的格式规则。
发布于 2015-08-11 22:20:31
我意识到这个问题是在两年前发布的,但我想我可以尝试一个不需要字符串转换的答案。
-- x : number you want rounded, n : number of decimal places you want...
truncate' :: Double -> Int -> Double
truncate' x n = (fromIntegral (floor (x * t))) / t
where t = 10^n
-- How to answer your problem...
λ truncate' 1.0014 3
1.001
-- 2 digits of a recurring decimal please...
λ truncate' (1/3) 2
0.33
-- How about 6 digits of pi?
λ truncate' pi 6
3.141592我还没有对它进行彻底的测试,所以如果你发现这个数字不适用,请告诉我!
https://stackoverflow.com/questions/18723381
复制相似问题