开发者

How can I take a fractional number and convert it to a list of its digits in Haskell?

开发者 https://www.devze.com 2023-04-11 19:47 出处:网络
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

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")
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号