四舍五入到Haskell中的特定位数 [英] Rounding to specific number of digits in Haskell

查看:144
本文介绍了四舍五入到Haskell中的特定位数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使一个浮点数四舍五入为定义的数字长度的函数.到目前为止,我想出的是:

I am trying to make a function to round a floating point number to a defined length of digits. What I have come up with so far is this:

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)

I am using the digs function to determine the number of digits before the comma to optimize the input value (i.e. move everything past the comma, so 1.234 becomes 0.1234 * 10^1)

roundTo函数似乎适用于大多数输入,但是对于某些输入,我得到了奇怪的结果,例如roundTo 1.0014 4生成1.0010000000000001而不是1.001.

The roundTo function seems to work for most input, however for some inputs I get strange results, e.g. roundTo 1.0014 4 produces 1.0010000000000001 instead of 1.001.

此示例中的问题是由计算1001 * 1.0e-3(返回1.0010000000000001)引起的

The problem in this example is caused by calculating 1001 * 1.0e-3 (which returns 1.0010000000000001)

这是我必须使用的Haskell的数字表示形式中的简单问题吗?还是有更好的方法将浮点数四舍五入为特定长度的数字?

Is this simply a problem in the number representation of Haskell I have to live with or is there a better way to round a floating point number to a specific length of digits?

推荐答案

与浮点问题一样,这不是haskell问题.由于每个浮点数都是在有限的位数中实现的,因此存在无法完全准确表示的数字.您还可以通过计算0.1 + 0.2来查看此内容,该方法笨拙地返回0.30000000000000004而不是0.3.这与如何为您的语言和硬件体系结构实现浮点数有关.

This isn't a haskell problem as much as a floating point problem. Since each floating point number is implemented in a finite number of bits, there exist numbers that can't be represented completely accurately. You can also see this by calculating 0.1 + 0.2, which awkwardly returns 0.30000000000000004 instead of 0.3. This has to do with how floating point numbers are implemented for your language and hardware architecture.

解决方案是继续使用roundTo函数进行计算(与没有特殊库时一样准确),但是如果要将其打印到屏幕上,则应使用字符串格式,例如Text.Printf.printf功能.您可以指定当转换为类似

The solution is to continue using your roundTo function for doing computation (it's as accurate as you'll get without special libraries), but if you want to print it to the screen then you should use string formatting such as the Text.Printf.printf function. You can specify the number of digits to round to when converting to a string with something like

import Text.Printf

roundToStr :: (PrintfArg a, Floating a) => Int -> a -> String
roundToStr n f = printf ("%0." ++ show n ++ "f") f

但是正如我提到的,这将返回一个字符串而不是一个数字.

But as I mentioned, this will return a string rather than a number.

一种更好的方法可能是

roundToStr :: (PrintfArg a, Floating a) => Int -> a -> String
roundToStr n f = printf (printf "%%0.%df" n) f

,但是我还没有进行基准测试,以了解哪个实际上更快.两者将完全一样地工作.

but I haven't benchmarked to see which is actually faster. Both will work exactly the same though.

正如@augustss所指出的那样,您只需使用

As @augustss has pointed out, you can do it even easier with just

roundToStr :: (PrintfArg a, Floating a) => Int -> a -> String
roundToStr = printf "%0.*f"

使用了我以前不知道的格式化规则.

which uses a formatting rule that I was previously unaware of.

这篇关于四舍五入到Haskell中的特定位数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆