How can I take a fractional number and convert it to a list of its digits in Haskell?
I want to take something like 1/7 (0.142857142857...)开发者_如何学运维 and convert it to "0.142857142857" or "142857142857" [1,4,2,8,5,7,1,4,2,8,5,7]. Using
map ((+) (-48) . ord) . show
works when the denominator is small, but with larger denominators, Haskell begins to use scientific notation. How can I consistently convert a fractional into a list of its digits?
This is not a complete solution, but it will get you started. This gets the list of digits for a number between zero and one. Wrap it with an appropriate method to get the output in the format you need.
digits :: (RealFrac a) => a -> [Int]
digits 0 = []
digits x = d : digits (10*x - fromIntegral d)
where
d = floor (10*x)
Playing around with it:
ghci> digits (1/4)
[2,5]
ghci> digits (1/3)
[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,7,2,7,3,8,6,0,0,9,
9,9,5,8,2,5,5,8,8,7,0,3,1,5,5,5,1,7,5,7,8,1,2,5]
-- rounding error got us, let's use an exact rational
ghci> import Data.Ratio
ghci> digits (1%3)
[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
...
Naturally, you can take from the infinite list of digits to get a prefix.
For example, this will show 1/7 to 12 decimal places. It will never use scientific notation.
Numeric.showFFloat (Just 12) (1/7) ""
The straightforward way, I suppose.
showDigits :: Int -> Double -> String
showDigits n x = show (floor x) ++ "." ++ showRest n x
showRest :: Int -> Double -> String
showRest n x | n <= 0 = ""
| otherwise = digitToInt dig : showRest (pred n) x'
where dig = (floor x') `mod` 10
x' = x * 10
This can only be as precise as the Double
representation is, though. Also, it never rounds the final digit up; it just shows it (rounds down). Testing:
ghci> showDigits 5 (1/7)
"0.14285"
I guess you need Text.Printf.printf:
import Data.Char
import Text.Printf
getDigits :: Double -> [Int]
getDigits=map ((subtract 48).Data.Char.ord) . (Text.Printf.printf "%f")
精彩评论