Как я могу взять дробное число и преобразовать его в список его цифр в Haskell?

#haskell

#haskell

Вопрос:

Я хочу взять что-то вроде 1/7 (0,142857142857 …) и преобразовать его в «0.142857142857» или «142857142857» [1,4,2,8,5,7,1,4,2,8,5,7]. Используя

 map (( ) (-48) . ord) . show
  

работает, когда знаменатель маленький, но с большими знаменателями Haskell начинает использовать научную нотацию. Как я могу последовательно преобразовать дробное число в список его цифр?

Комментарии:

1. Кстати, проверьте Data.Char.digitToInt .

2. Другим способом ( ) (-48) можно записать subtract 48 .

Ответ №1:

Это не полное решение, но оно поможет вам начать. Это возвращает список цифр для числа от нуля до единицы. Оберните его соответствующим методом, чтобы получить вывод в нужном вам формате.

 digits :: (RealFrac a) => a -> [Int]
digits 0 = []
digits x = d : digits (10*x - fromIntegral d)
    where
    d = floor (10*x)
  

Играем с этим:

 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,
...
  

Естественно, вы можете взять из бесконечного списка цифр, чтобы получить префикс.

Комментарии:

1. Эта функция немного забавна, если вы передаете ей цифры больше 1 . digits (4%3) = [13, 3, 3, 3, ...] . =)

Ответ №2:

Например, это покажет от 1/7 до 12 знаков после запятой. Он никогда не будет использовать научную нотацию.

 Numeric.showFFloat (Just 12) (1/7) ""
  

Комментарии:

1. Что это Numeric за модуль?

Ответ №3:

Я полагаю, это простой способ.

 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
  

Однако это может быть настолько точным, насколько Double соответствует представление. Кроме того, он никогда не округляет последнюю цифру в большую сторону; он просто показывает ее (округляет в меньшую сторону). Тестирование:

 ghci> showDigits 5 (1/7)
"0.14285"
  

Ответ №4:

Я думаю, вам нужен Text.Printf.printf:

 import Data.Char
import Text.Printf

getDigits :: Double -> [Int]
getDigits=map ((subtract 48).Data.Char.ord) . (Text.Printf.printf "%f")