How to parse a decimal fraction into Rational in Haskell?
I've been participating in a programming contest and one of the problems' input data included a fractional number in a decimal format: 0.75
is one example.
Parsing that into Double
is trivial (I can use read
for that), but the loss of precision is painful. One needs to be very careful with Double
comparisons (I开发者_如何学C wasn't), which seems redundant since one has Rational
data type in Haskell.
When trying to use that, I've discovered that to read
a Rational
one has to provide a string in the following format: numerator % denominator
, which I, obviously, do not have.
So, the question is:
What is the easiest way to parse a decimal representation of a fraction into Rational
?
The number of external dependencies should be taken into consideration too, since I can't install additional libraries into the online judge.
The function you want is Numeric.readFloat
:
Numeric Data.Ratio> fst . head $ readFloat "0.75" :: Rational
3 % 4
How about the following (GHCi session):
> :m + Data.Ratio
> approxRational (read "0.1" :: Double) 0.01
1 % 10
Of course you have to pick your epsilon appropriately.
Perhaps you'd get extra points in the contest for implementing it yourself:
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
精彩评论