Help us understand the problem. What is going on with this article?

すごい乱暴な方法で Haskell の小数を正確数にする

More than 5 years have passed since last update.

そもそも Haskell の Prelude で toRational :: Real a => a -> Rational が宣言されているので,これを使えば小数を有理数として扱えはするけれど,以下のように望ましくない動きをする

import Data.Ratio ((%))
11 % 10  -- Haskell での 11/10 (= 1.1) の有理数表現
fromRational $ 11 % 10 -- 1.1 これは期待通り
fromRational $ toRational 1.1 -- 1.1 これも期待通り
(toRational 1.1) == (toRational 1.1) -- True これも期待通り
toRational 1.1 -- 2476979795053773 % 2251799813685248 えっ
(toRational 1.1) == (11 % 10) -- False そんな…

fromRationaltoRational を連続して適用する場合は割と望ましい結果が得られるが,toRational のみを利用して,他の有理数との算術演算をしたりするとどうもおかしい事になりがち.
なので多少乱暴な方法で正確数を Real a ( 実数型クラスのインスタンス ) から得る関数を書く

import Numeric ( floatToDigit, fromRat )
import Data.Ratio ( (%), denominator )

-- | exact ratio number from Real `a`
-- example
-- > exact 1.1 -- 11 % 10
-- > (exact 1.1) == (11 % 10) -- True
-- > fromRational $ exact 1.1 -- 1.1
exactFromReal :: Real a => a -> Rational
exactFromReal x
  | asInt      = ratio
  | otherwise  = numer % denom
  where
  asInt  = denominator ratio == 1
  ratio  = toRational x
  numer  = round $ ratio * (denom % 1)
  denom  = 10 ^ (uN - iN)
  iN     = snd digits
  uN     = length $ fst digits
  digits = floatToDigits 10 $ fromRat ratio

ただし,ここで利用している Numeric.floatToDigits が,十進で17桁以上は切ってしまうので, 精度はそこまで良いわけではない.
QuickCheck でテストした場合.だいたい ±10^(-12) (ピコ) の精度は保証できている

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away