2011-08-14 29 views
8

我一直参与a programming contestone of the problems'输入数据包含一个十进制格式的小数:0.75就是一个例子。如何在Haskell中将小数部分解析为Rational?

解析成Double是微不足道的(我可以使用read),但精度的损失是痛苦的。需要对Double比较(我不是)非常小心,这似乎是多余的,因为在Haskell中有一个Rational数据类型。

当试图使用它时,我发现read a Rational必须提供以下格式的字符串:numerator % denominator,这显然没有。

所以,问题是:

什么是解析分数的十进制表示到Rational最简单的方法?

也应该考虑外部依赖的数量,因为我无法在网上裁判中安装额外的库。

回答

15

你想要的功能是Numeric.readFloat

Numeric Data.Ratio> fst . head $ readFloat "0.75" :: Rational 
3 % 4 
+0

谢谢!这工作。 – Rotsor

+6

如果您想要读取负数:'fst,您可能需要添加'readSigned'。 head $ readSigned readFloat“-3.14”:: Rational' – newacct

3

如何以下(GHCI会话):

> :m + Data.Ratio 
> approxRational (read "0.1" :: Double) 0.01 
1 % 10 

当然,你必须适当地选择你的-5次方。

+0

这是个好主意!我认为这应该在大多数情况下用来代替'toRational'! – Rotsor

+0

不幸的是,epsilon的选择在这里并不明显。例如,'approxRational 0.999 0.0001'是'909%910',这不是我想要的。在这种情况下使用的正确的epsilon是“0.000001”(精度平方?) – Rotsor

1

也许你会得到加分的较量中为自己实现它:

import Data.Ratio ((%)) 

readRational :: String -> Rational 
readRational input = read intPart % 1 + read fracPart % (10^length fracPart) 
    where (intPart, fromDot) = span (/='.') input 
     fracPart   = if null fromDot then "0" else tail fromDot 
+0

我不这么认为。在这样的比赛中,只有提交时间和正确性很重要。好的解决方案仍然足够短,可以在紧急情况下编码。 – Rotsor

相关问题