Описание библиотеки Haskell 98: Рациональные числа
Описание Haskell 98 наверх |
назад |
вперед |
содержание |
предметный указатель функций
12 Рациональные числа
module Ratio (
Ratio, Rational, (%), numerator, denominator, approxRational ) where
infixl 7 %
data (Integral a) => Ratio a = ...
type Rational = Ratio Integer
(%) :: (Integral a) => a -> a -> Ratio a
numerator, denominator :: (Integral a) => Ratio a -> a
approxRational :: (RealFrac a) => a -> a -> Rational
instance (Integral a) => Eq (Ratio a) where ...
instance (Integral a) => Ord (Ratio a) where ...
instance (Integral a) => Num (Ratio a) where ...
instance (Integral a) => Real (Ratio a) where ...
instance (Integral a) => Fractional (Ratio a) where ...
instance (Integral a) => RealFrac (Ratio a) where ...
instance (Integral a) => Enum (Ratio a) where ...
instance (Read a,Integral a) => Read (Ratio a) where ...
instance (Integral a) => Show (Ratio a) where ...
|
Для каждого типа Integral t есть
тип Ratio t рациональных пар с компонентами
типа t . Имя типа Rational является синонимом для
Ratio Integer.
Ratio является экземпляром классов Eq, Ord, Num, Real,
Fractional, RealFrac, Enum, Read и Show. В каждом случае
экземпляр для Ratio t просто "повышает" соответствующие операции
над t . Если t является ограниченным типом, результаты могут быть непредсказуемы;
например, Ratio Int может вызвать переполнение целого числа даже для
небольших по абсолютной величине рациональных чисел.
Оператор (%) составляет отношение двух
целых чисел, сокращая дробь до членов без общего делителя
и таких, что знаменатель является положительным. Функции
numerator
и denominator извлекают компоненты
отношения (соответственно числитель и знаменатель дроби); эти компоненты находятся в приведенном виде с положительным знаменателем.
Ratio является абстрактным типом. Например, 12 % 8 сокращается до 3/2,
а 12 % (-8) сокращается до (-3)/2.
Функция approxRational, будучи примененной к двум действительным дробным числам
x и epsilon, возвращает простейшее рациональное число в пределах открытого
интервала (x-epsilon, x+epsilon).
Говорят, что рациональное число n/d в приведенном виде является более простым, чем другое число n'/d', если |n| <=|n'| и d <=d'.
Обратите внимание, что можно доказать, что любой действительный интервал содержит единственное
простейшее рациональное число.
12.1 Библиотека Ratio
-- Стандартные функции над рациональными числами
module Ratio (
Ratio, Rational, (%), numerator, denominator, approxRational ) where
infixl 7 %
ratPrec = 7 :: Int
data (Integral a) => Ratio a = !a :% !a deriving (Eq)
type Rational = Ratio Integer
(%) :: (Integral a) => a -> a -> Ratio a
numerator, denominator :: (Integral a) => Ratio a -> a
approxRational :: (RealFrac a) => a -> a -> Rational
-- "reduce" --- это вспомогательная функция, которая используется только в этом модуле.
-- Она нормирует отношение путем деления числителя и знаменателя
-- на их наибольший общий делитель.
--
-- Например, 12 `reduce` 8 == 3 :% 2
-- 12 `reduce` (-8) == 3 :% (-2)
reduce _ 0 = error "Ratio.% : нулевой знаменатель"
reduce x y = (x `quot` d) :% (y `quot` d)
where d = gcd x y
x % y = reduce (x * signum y) (abs y)
numerator (x :% _) = x
denominator (_ :% y) = y
instance (Integral a) => Ord (Ratio a) where
(x:%y) <= (x':%y') = x * y' <= x' * y
(x:%y) < (x':%y') = x * y' < x' * y
instance (Integral a) => Num (Ratio a) where
(x:%y) + (x':%y') = reduce (x*y' + x'*y) (y*y')
(x:%y) * (x':%y') = reduce (x * x') (y * y')
negate (x:%y) = (-x) :% y
abs (x:%y) = abs x :% y
signum (x:%y) = signum x :% 1
fromInteger x = fromInteger x :% 1
instance (Integral a) => Real (Ratio a) where
toRational (x:%y) = toInteger x :% toInteger y
instance (Integral a) => Fractional (Ratio a) where
(x:%y) / (x':%y') = (x*y') % (y*x')
recip (x:%y) = y % x
fromRational (x:%y) = fromInteger x :% fromInteger y
instance (Integral a) => RealFrac (Ratio a) where
properFraction (x:%y) = (fromIntegral q, r:%y)
where (q,r) = quotRem x y
instance (Integral a) => Enum (Ratio a) where
succ x = x+1
pred x = x-1
toEnum = fromIntegral
fromEnum = fromInteger . truncate -- Может вызвать переполнение
enumFrom = numericEnumFrom -- Эти функции вида numericEnumXXX
enumFromThen = numericEnumFromThen -- определены в Prelude.hs
enumFromTo = numericEnumFromTo -- но не экспортируются оттуда!
enumFromThenTo = numericEnumFromThenTo
instance (Read a, Integral a) => Read (Ratio a) where
readsPrec p = readParen (p > ratPrec)
(\r -> [(x%y,u) | (x,s) <- readsPrec (ratPrec+1) r,
("%",t) <- lex s,
(y,u) <- readsPrec (ratPrec+1) t ])
instance (Integral a) => Show (Ratio a) where
showsPrec p (x:%y) = showParen (p > ratPrec)
(showsPrec (ratPrec+1) x .
showString " % " .
showsPrec (ratPrec+1) y)
approxRational x eps = simplest (x-eps) (x+eps)
where simplest x y | y < x = simplest y x
| x == y = xr
| x > 0 = simplest' n d n' d'
| y < 0 = - simplest' (-n') d' (-n) d
| otherwise = 0 :% 1
where xr@(n:%d) = toRational x
(n':%d') = toRational y
simplest' n d n' d' -- предполагает, что 0 < n%d < n'%d'
| r == 0 = q :% 1
| q /= q' = (q+1) :% 1
| otherwise = (q*n''+d'') :% n''
where (q,r) = quotRem n d
(q',r') = quotRem n' d'
(n'':%d'') = simplest' d' r' d r
Описание Haskell 98наверх |
назад |
вперед |
содержание |
предметный указатель функций Декабрь 2002