module Numeric(fromRat,
showSigned, showIntAtBase,
showInt, showOct, showHex,
readSigned, readInt,
readDec, readOct, readHex,
floatToDigits,
showEFloat, showFFloat, showGFloat, showFloat,
readFloat, lexDigits) where
fromRat :: (RealFloat a) => Rational -> a
showSigned :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS
showIntAtBase :: Integral a => a -> (Int -> Char) -> a -> ShowS
showInt :: Integral a => a -> ShowS
showOct :: Integral a => a -> ShowS
showHex :: Integral a => a -> ShowS
readSigned :: (Real a) => ReadS a -> ReadS a
readInt :: (Integral a) =>
a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
readDec :: (Integral a) => ReadS a
readOct :: (Integral a) => ReadS a
readHex :: (Integral a) => ReadS a
showEFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
showFFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
showGFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
showFloat :: (RealFloat a) => a -> ShowS
floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
readFloat :: (RealFrac a) => ReadS a
lexDigits :: ReadS String
Эта библиотека содержит
Далее, напомним следующие определения типов из Prelude:
type ShowS = String -> String type ReadS = String -> [(a,String)]
showSigned :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS
преобразует возможно отрицательное значение Real типа a в строку. В вызове (showSigned show prec val) val является значением для отображения, prec - приоритетом внешнего контекста, а show - функцией, которая может отобразить (преобразовать в строку) значения без знака.showIntAtBase :: Integral a => a -> (Int -> Char) -> a -> ShowS
отображает неотрицательное число Integral, используя основание, указанное в первом аргументе, и showInt, showOct, showHex :: Integral a => a -> ShowS отображает неотрицательные числа Integral по основанию 10, 8 и 16 соответственно.showFFloat, showEFloat, showGFloat
:: (RealFloat a) => Maybe Int -> a -> ShowSЭти три функции отображают значения RealFloat со знаком:
showFFloat использует стандартную десятичную запись (например, 245000, 0.0015).showEFloat использует научную (показательную) запись (например, 2.45e2, 1.5e-3).showGFloat использует стандартную десятичную запись для аргументов, чье абсолютное значение находится между 0.1 и 9,999,999, и научную запись иначе.В вызове (showEFloat digs val), если digs является Nothing, значение отображается с полной точностью; если digs является Just d, то самое большее d цифр после десятичный точки будет отображено. В точности то же самое касается аргумента digs двух других функций.
floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
преобразует основание и значение в величину в цифрах плюс показатель степени.
прБолее точно, если floatToDigits b r = ([ d1, d2... dn ], e ), то выполняются следующие свойства:
r = 0.d1 d2 ..., dn * b e n >=0 d1 /=0 (когда n > 0)0 >=d_i >=b-1readSigned :: (Real a) => ReadS a -> ReadS a
считывает значение Real со знаком, учитывая наличие функции для считывания значений без знака.readInt :: (Integral a) => a -> (Char-> Bool) -> (Char -> Int) -> ReadS a
считывает значение Integral без знака с произвольным основанием. В вызове (readInt base isdig d2i) base является основанием, isdig - предикатом, различающим допустимые цифры по этому основанию, а d2i преобразует символ допустимой цифры в Int.readFloat :: (RealFrac a) => ReadS a считывает значение RealFrac без знака, изображенное в десятичной научной записи.readDec, readOct, readHex :: (Integral a) => ReadS a
считывают число без знака в десятичной, восьмиричной и шестнадцатиричной записи соответственно. В случае шестнадцатиричной записи допустимы буквы верхнего и нижнего регистра.lexDigits :: ReadS String считывает непустую строку десятичных цифр.( NB: readInt является "двойственной" для showIntAtBase, а readDec является "двойственной" для showInt. Противоречивые имена этих функций сложились исторически.)
fromRat :: (RealFloat a) => Rational ->; a преобразует значение Rational к любому типу в классе RealFloat.
module Numeric(fromRat,
showSigned, showIntAtBase,
showInt, showOct, showHex,
readSigned, readInt,
readDec, readOct, readHex,
floatToDigits,
showEFloat, showFFloat, showGFloat, showFloat,
readFloat, lexDigits) where
import Char ( isDigit, isOctDigit, isHexDigit
, digitToInt, intToDigit )
import Ratio ( (%), numerator, denominator )
import Array ( (!), Array, array )
- Эта функция выполняет преобразование рационального числа в число с плавающей точкой.
- Ее следует использовать в экземплярах классов Float и Double.
fromRat :: (RealFloat a) => Rational -> a
fromRat x =
if x == 0 then encodeFloat 0 0
- Сначала обрабатывает исключительные ситуации
else if x < 0 then - fromRat' (-x)
else fromRat' x
- Процесс преобразования:
- Перевести (масштабировать) RealFloat, пока
- оно не будет лежать в диапазоне decodeFloat/encodeFloat ).
- Затем округлить Integer и закодировать его с помощью экспоненты,
- полученной при переводе числа в систему счисления.
- Для того чтобы ускорить процесс масштабирования, мы вычисляем log2 числа, чтобы получить
- первое приближение экспоненты.
fromRat' :: (RealFloat a) => Rational -> a
fromRat' x = r
where b = floatRadix r
p = floatDigits r
(minExp0, _) = floatRange r
minExp = minExp0 - p
- действительная минимальная экспонента
xMin = toRational (expt b (p-1))
xMax = toRational (expt b p)
p0 = (integerLogBase b (numerator x) -
integerLogBase b (denominator x) - p) `max` minExp
f = if p0 < 0 then 1 % expt b (-p0) else expt b p0 % 1
(x', p') = scaleRat (toRational b) minExp xMin xMax p0 (x / f)
r = encodeFloat (round x') p'
- Масштабировать x, пока не выполнится условие xMin >=x < xMax или p (экспонета) <= minExp.
scaleRat :: Rational -> Int -> Rational -> Rational ->
Int -> Rational -> (Rational, Int)
scaleRat b minExp xMin xMax p x =
if p <= minExp then
(x, p)
else if x >= xMax then
scaleRat b minExp xMin xMax (p+1) (x/b)
else if x < xMin then
scaleRat b minExp xMin xMax (p-1) (x*b)
else
(x, p)
- Возведение в степень с помощью кэша наиболее частых чисел.
minExpt = 0::Int
maxExpt = 1100::Int
expt :: Integer -> Int -> Integer
expt base n =
if base == 2 n >= minExpt n <= maxExpt then
expts!n
else
base^n
expts :: Array Int Integer
expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]]
- Вычисляет (нижнюю границу) log i по основанию b.
- Наиболее простой способ - просто делить i на b, пока оно не станет меньше b,
- но это было бы очень медленно! Мы просто немного более сообразительны.
integerLogBase :: Integer -> Integer -> Int
integerLogBase b i =
if i < b then
0
else
- Пытается сначала возвести в квадрат основание, чтобы сократить число делений.
let l = 2 * integerLogBase (b*b) i
doDiv :: Integer -> Int -> Int
doDiv i l = if i < b then l else doDiv (i `div` b) (l+1)
in doDiv (i `div` (b^l)) l
- Разные утилиты для отображения целых чисел и чисел с плавающей точкой
showSigned :: Real a => (a -> ShowS) -> Int -> a -> ShowS
showSigned showPos p x
| x < 0 = showParen (p > 6) (showChar '-' . showPos (-x))
| otherwise = showPos x
- showInt, showOct, showHex используются только для положительных чисел
showInt, showOct, showHex :: Integral a => a -> ShowS
showOct = showIntAtBase 8 intToDigit
showInt = showIntAtBase 10 intToDigit
showHex = showIntAtBase 16 intToDigit
showIntAtBase :: Integral a
=> a - основание
-> (Int -> Char) - цифра для символа
-> a - число для отображения
-> ShowS
showIntAtBase base intToDig n rest
| n < 0 = error "Numeric.showIntAtBase: не могу отображать отрицательные числа"
| n' == 0 = rest'
| otherwise = showIntAtBase base intToDig n' rest'
where
(n',d) = quotRem n base
rest' = intToDig (fromIntegral d) : rest
readSigned :: (Real a) => ReadS a -> ReadS a
readSigned readPos = readParen False read'
where read' r = read'' r ++
[(-x,t) | ("-",s) <- lex r,
(x,t) <- read'' s]
read'' r = [(n,s) | (str,s) <- lex r,
(n,"") <- readPos str]
- readInt считывает строку цифр, используя произвольное основание.
- Знаки минус в начале строки должны обрабатываться где-то в другом месте.
readInt :: (Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
readInt radix isDig digToInt s =
[(foldl1 (\n d -> n * radix + d) (map (fromIntegral . digToInt) ds), r)
| (ds,r) <- nonnull isDig s ]
- Функции для считывания беззнаковых чисел с различными основаниями
readDec, readOct, readHex :: (Integral a) => ReadS a readDec = readInt 10 isDigit digitToInt readOct = readInt 8 isOctDigit digitToInt readHex = readInt 16 isHexDigit digitToInt showEFloat :: (RealFloat a) => Maybe Int -> a -> ShowS showFFloat :: (RealFloat a) => Maybe Int -> a -> ShowS showGFloat :: (RealFloat a) => Maybe Int -> a -> ShowS showFloat :: (RealFloat a) => a -> ShowS showEFloat d x = showString (formatRealFloat FFExponent d x) showFFloat d x = showString (formatRealFloat FFFixed d x) showGFloat d x = showString (formatRealFloat FFGeneric d x) showFloat = showGFloat Nothing
- Это типы форматов. Этот тип не экспортируется.
data FFFormat = FFExponent | FFFixed | FFGeneric
formatRealFloat :: (RealFloat a) => FFFormat -> Maybe Int -> a -> String
formatRealFloat fmt decs x
= s
where
base = 10
s = if isNaN x then
"NaN"
else if isInfinite x then
if x < 0 then "-Infinity" else "Infinity"
else if x < 0 || isNegativeZero x then
'-' : doFmt fmt (floatToDigits (toInteger base) (-x))
else
doFmt fmt (floatToDigits (toInteger base) x)
doFmt fmt (is, e)
= let
ds = map intToDigit is
in
case fmt of
FFGeneric ->
doFmt (if e < 0 || e > 7 then FFExponent else FFFixed)
(is, e)
FFExponent ->
case decs of
Nothing ->
case ds of
[] -> "0.0e0"
[d] -> d : ".0e" ++ show (e-1)
d:ds -> d : '.' : ds ++ 'e':show (e-1)
Just dec ->
let dec' = max dec 1 in
case is of
[] -> '0':'.':take dec' (repeat '0') ++ "e0"
_ ->
let (ei, is') = roundTo base (dec'+1) is
d:ds = map intToDigit
(if ei > 0 then init is' else is')
in d:'.':ds ++ "e" ++ show (e-1+ei)
FFFixed ->
case decs of
Nothing - Всегда печатает десятичную точку
| e > 0 -> take e (ds ++ repeat '0')
++ '.' : mk0 (drop e ds)
| otherwise -> "0." ++ mk0 (replicate (-e) '0' ++ ds)
Just dec -> - Печатает десятичную точку, если dec > 0
let dec' = max dec 0 in
if e >= 0 then
let (ei, is') = roundTo base (dec' + e) is
(ls, rs) = splitAt (e+ei)
(map intToDigit is')
in mk0 ls ++ mkdot0 rs
else
let (ei, is') = roundTo base dec'
(replicate (-e) 0 ++ is)
d : ds = map intToDigit
(if ei > 0 then is' else 0:is')
in d : mkdot0 ds
where
mk0 "" = "0" - Печатает 0.34, а не .34
mk0 s = s
mkdot0 "" = "" - Печатает 34, а не 34.
mkdot0 s = '.' : s - когда формат задает отсутствие
- цифр после десятичной точки
roundTo :: Int -> Int -> [Int] -> (Int, [Int])
roundTo base d is = case f d is of
(0, is) -> (0, is)
(1, is) -> (1, 1 : is)
where b2 = base `div` 2
f n [] = (0, replicate n 0)
f 0 (i:_) = (if i >= b2 then 1 else 0, [])
f d (i:is) =
let (c, ds) = f (d-1) is
i' = c + i
in if i' == base then (1, 0:ds) else (0, i':ds)
- Базируется на "Быстрой и точной печати чисел с плавающей точкой"
- Р.Г. Бургера и Р.К. Дайбвига
- ("Printing floatToDigits r = ([a, b, ... z], e)
- то
- r = 0.ab..z * base^e
-
floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
floatToDigits _ 0 = ([], 0)
floatToDigits base x =
let (f0, e0) = decodeFloat x
(minExp0, _) = floatRange x
p = floatDigits x
b = floatRadix x
minExp = minExp0 - p - действительная минимальная экспонента
- В Haskell требуется, чтобы f было скорректировано так, чтобы денормализационные числа - имели невозможно низкую экспоненту. Для этого используется коррекция.
f :: Integer
e :: Int
(f, e) = let n = minExp - e0
in if n > 0 then (f0 `div` (b^n), e0+n) else (f0, e0)
(r, s, mUp, mDn) =
if e >= 0 then
let be = b^e in
if f == b^(p-1) then
(f*be*b*2, 2*b, be*b, b)
else
(f*be*2, 2, be, be)
else
if e > minExp f == b^(p-1) then
(f*b*2, b^(-e+1)*2, b, 1)
else
(f*2, b^(-e)*2, 1, 1)
k =
let k0 =
if b==2 base==10 then
- logBase 10 2 немного больше, чем 3/10, поэтому
- следующее вызовет ошибку на нижней стороне. Игнорирование
- дроби создаст эту ошибку даже больше.
- Haskell обещает, что p-1 <= logBase b f < p.
(p - 1 + e0) * 3 `div` 10
else
ceiling ((log (fromInteger (f+1)) +
fromIntegral e * log (fromInteger b)) /
log (fromInteger base))
fixup n =
if n >= 0 then
if r + mUp <= expt base n * s then n else fixup (n+1)
else
if expt base (-n) * (r + mUp) <= s then n
else fixup (n+1)
in fixup k0
gen ds rn sN mUpN mDnN =
let (dn, rn') = (rn * base) `divMod` sN
mUpN' = mUpN * base
mDnN' = mDnN * base
in case (rn' < mDnN', rn' + mUpN' > sN) of
(True, False) -> dn : ds
(False, True) -> dn+1 : ds
(True, True) -> if rn' * 2 < sN then dn : ds else dn+1 : ds
(False, False) -> gen (dn:ds) rn' sN mUpN' mDnN'
rds =
if k >= 0 then
gen [] r (s * expt base k) mUp mDn
else
let bk = expt base (-k)
in gen [] (r * bk) s (mUp * bk) (mDn * bk)
in (map fromIntegral (reverse rds), k)
- Эта функция для считывания чисел с плавающей точкой использует менее ограничивающий синтаксис - для чисел с плавающей точкой, чем лексический анализатор Haskell. `.' является необязательной.
readFloat :: (RealFrac a) => ReadS a
readFloat r = [(fromRational ((n%1)*10^^(k-d)),t) | (n,d,s) <- readFix r,
(k,t) <- readExp s] ++
[ (0/0, t) | ("NaN",t) <- lex r] ++
[ (1/0, t) | ("Infinity",t) <- lex r]
where
readFix r = [(read (ds++ds'), length ds', t)
| (ds,d) <- lexDigits r,
(ds',t) <- lexFrac d ]
lexFrac ('.':ds) = lexDigits ds
lexFrac s = [("",s)]
readExp (e:s) | e `elem` "eE" = readExp' s
readExp s = [(0,s)]
readExp' ('-':s) = [(-k,t) | (k,t) <- readDec s]
readExp' ('+':s) = readDec s
readExp' s = readDec s
lexDigits :: ReadS String
lexDigits = nonnull isDigit
nonnull :: (Char -> Bool) -> ReadS String
nonnull p s = [(cs,t) | (cs@(_:_),t) <- [span p s]]
module Numeric(fromRat,
showSigned, showIntAtBase,
showInt, showOct, showHex,
readSigned, readInt,
readDec, readOct, readHex,
floatToDigits,
showEFloat, showFFloat, showGFloat, showFloat,
readFloat, lexDigits) where
fromRat :: (RealFloat a) => Rational -> a
showSigned :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS
showIntAtBase :: Integral a => a -> (Int -> Char) -> a -> ShowS
showInt :: Integral a => a -> ShowS
showOct :: Integral a => a -> ShowS
showHex :: Integral a => a -> ShowS
readSigned :: (Real a) => ReadS a -> ReadS a
readInt :: (Integral a) =>
a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
readDec :: (Integral a) => ReadS a
readOct :: (Integral a) => ReadS a
readHex :: (Integral a) => ReadS a
showEFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
showFFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
showGFloat :: (RealFloat a) => Maybe Int -> a -> ShowS
showFloat :: (RealFloat a) => a -> ShowS
floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
readFloat :: (RealFrac a) => ReadS a
lexDigits :: ReadS String
Эта библиотека содержит
Далее, напомним следующие определения типов из Prelude:
type ShowS = String -> String type ReadS = String -> [(a,String)]
showSigned :: (Real a) => (a -> ShowS) -> Int -> a -> ShowS
преобразует возможно отрицательное значение Real типа a в строку. В вызове (showSigned show prec val) val является значением для отображения, prec - приоритетом внешнего контекста, а show - функцией, которая может отобразить (преобразовать в строку) значения без знака.showIntAtBase :: Integral a => a -> (Int -> Char) -> a -> ShowS
отображает неотрицательное число Integral, используя основание, указанное в первом аргументе, и showInt, showOct, showHex :: Integral a => a -> ShowS отображает неотрицательные числа Integral по основанию 10, 8 и 16 соответственно.showFFloat, showEFloat, showGFloat
:: (RealFloat a) => Maybe Int -> a -> ShowSЭти три функции отображают значения RealFloat со знаком:
showFFloat использует стандартную десятичную запись (например, 245000, 0.0015).showEFloat использует научную (показательную) запись (например, 2.45e2, 1.5e-3).showGFloat использует стандартную десятичную запись для аргументов, чье абсолютное значение находится между 0.1 и 9,999,999, и научную запись иначе.В вызове (showEFloat digs val), если digs является Nothing, значение отображается с полной точностью; если digs является Just d, то самое большее d цифр после десятичный точки будет отображено. В точности то же самое касается аргумента digs двух других функций.
floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
преобразует основание и значение в величину в цифрах плюс показатель степени.
прБолее точно, если floatToDigits b r = ([ d1, d2... dn ], e ), то выполняются следующие свойства:
r = 0.d1 d2 ..., dn * b e n >=0 d1 /=0 (когда n > 0)0 >=d_i >=b-1readSigned :: (Real a) => ReadS a -> ReadS a
считывает значение Real со знаком, учитывая наличие функции для считывания значений без знака.readInt :: (Integral a) => a -> (Char-> Bool) -> (Char -> Int) -> ReadS a
считывает значение Integral без знака с произвольным основанием. В вызове (readInt base isdig d2i) base является основанием, isdig - предикатом, различающим допустимые цифры по этому основанию, а d2i преобразует символ допустимой цифры в Int.readFloat :: (RealFrac a) => ReadS a считывает значение RealFrac без знака, изображенное в десятичной научной записи.readDec, readOct, readHex :: (Integral a) => ReadS a
считывают число без знака в десятичной, восьмиричной и шестнадцатиричной записи соответственно. В случае шестнадцатиричной записи допустимы буквы верхнего и нижнего регистра.lexDigits :: ReadS String считывает непустую строку десятичных цифр.( NB: readInt является "двойственной" для showIntAtBase, а readDec является "двойственной" для showInt. Противоречивые имена этих функций сложились исторически.)
fromRat :: (RealFloat a) => Rational ->; a преобразует значение Rational к любому типу в классе RealFloat.
module Numeric(fromRat,
showSigned, showIntAtBase,
showInt, showOct, showHex,
readSigned, readInt,
readDec, readOct, readHex,
floatToDigits,
showEFloat, showFFloat, showGFloat, showFloat,
readFloat, lexDigits) where
import Char ( isDigit, isOctDigit, isHexDigit
, digitToInt, intToDigit )
import Ratio ( (%), numerator, denominator )
import Array ( (!), Array, array )
- Эта функция выполняет преобразование рационального числа в число с плавающей точкой.
- Ее следует использовать в экземплярах классов Float и Double.
fromRat :: (RealFloat a) => Rational -> a
fromRat x =
if x == 0 then encodeFloat 0 0
- Сначала обрабатывает исключительные ситуации
else if x < 0 then - fromRat' (-x)
else fromRat' x
- Процесс преобразования:
- Перевести (масштабировать) RealFloat, пока
- оно не будет лежать в диапазоне decodeFloat/encodeFloat ).
- Затем округлить Integer и закодировать его с помощью экспоненты,
- полученной при переводе числа в систему счисления.
- Для того чтобы ускорить процесс масштабирования, мы вычисляем log2 числа, чтобы получить
- первое приближение экспоненты.
fromRat' :: (RealFloat a) => Rational -> a
fromRat' x = r
where b = floatRadix r
p = floatDigits r
(minExp0, _) = floatRange r
minExp = minExp0 - p
- действительная минимальная экспонента
xMin = toRational (expt b (p-1))
xMax = toRational (expt b p)
p0 = (integerLogBase b (numerator x) -
integerLogBase b (denominator x) - p) `max` minExp
f = if p0 < 0 then 1 % expt b (-p0) else expt b p0 % 1
(x', p') = scaleRat (toRational b) minExp xMin xMax p0 (x / f)
r = encodeFloat (round x') p'
- Масштабировать x, пока не выполнится условие xMin >=x < xMax или p (экспонета) <= minExp.
scaleRat :: Rational -> Int -> Rational -> Rational ->
Int -> Rational -> (Rational, Int)
scaleRat b minExp xMin xMax p x =
if p <= minExp then
(x, p)
else if x >= xMax then
scaleRat b minExp xMin xMax (p+1) (x/b)
else if x < xMin then
scaleRat b minExp xMin xMax (p-1) (x*b)
else
(x, p)
- Возведение в степень с помощью кэша наиболее частых чисел.
minExpt = 0::Int
maxExpt = 1100::Int
expt :: Integer -> Int -> Integer
expt base n =
if base == 2 n >= minExpt n <= maxExpt then
expts!n
else
base^n
expts :: Array Int Integer
expts = array (minExpt,maxExpt) [(n,2^n) | n <- [minExpt .. maxExpt]]
- Вычисляет (нижнюю границу) log i по основанию b.
- Наиболее простой способ - просто делить i на b, пока оно не станет меньше b,
- но это было бы очень медленно! Мы просто немного более сообразительны.
integerLogBase :: Integer -> Integer -> Int
integerLogBase b i =
if i < b then
0
else
- Пытается сначала возвести в квадрат основание, чтобы сократить число делений.
let l = 2 * integerLogBase (b*b) i
doDiv :: Integer -> Int -> Int
doDiv i l = if i < b then l else doDiv (i `div` b) (l+1)
in doDiv (i `div` (b^l)) l
- Разные утилиты для отображения целых чисел и чисел с плавающей точкой
showSigned :: Real a => (a -> ShowS) -> Int -> a -> ShowS
showSigned showPos p x
| x < 0 = showParen (p > 6) (showChar '-' . showPos (-x))
| otherwise = showPos x
- showInt, showOct, showHex используются только для положительных чисел
showInt, showOct, showHex :: Integral a => a -> ShowS
showOct = showIntAtBase 8 intToDigit
showInt = showIntAtBase 10 intToDigit
showHex = showIntAtBase 16 intToDigit
showIntAtBase :: Integral a
=> a - основание
-> (Int -> Char) - цифра для символа
-> a - число для отображения
-> ShowS
showIntAtBase base intToDig n rest
| n < 0 = error "Numeric.showIntAtBase: не могу отображать отрицательные числа"
| n' == 0 = rest'
| otherwise = showIntAtBase base intToDig n' rest'
where
(n',d) = quotRem n base
rest' = intToDig (fromIntegral d) : rest
readSigned :: (Real a) => ReadS a -> ReadS a
readSigned readPos = readParen False read'
where read' r = read'' r ++
[(-x,t) | ("-",s) <- lex r,
(x,t) <- read'' s]
read'' r = [(n,s) | (str,s) <- lex r,
(n,"") <- readPos str]
- readInt считывает строку цифр, используя произвольное основание.
- Знаки минус в начале строки должны обрабатываться где-то в другом месте.
readInt :: (Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
readInt radix isDig digToInt s =
[(foldl1 (\n d -> n * radix + d) (map (fromIntegral . digToInt) ds), r)
| (ds,r) <- nonnull isDig s ]
- Функции для считывания беззнаковых чисел с различными основаниями
readDec, readOct, readHex :: (Integral a) => ReadS a readDec = readInt 10 isDigit digitToInt readOct = readInt 8 isOctDigit digitToInt readHex = readInt 16 isHexDigit digitToInt showEFloat :: (RealFloat a) => Maybe Int -> a -> ShowS showFFloat :: (RealFloat a) => Maybe Int -> a -> ShowS showGFloat :: (RealFloat a) => Maybe Int -> a -> ShowS showFloat :: (RealFloat a) => a -> ShowS showEFloat d x = showString (formatRealFloat FFExponent d x) showFFloat d x = showString (formatRealFloat FFFixed d x) showGFloat d x = showString (formatRealFloat FFGeneric d x) showFloat = showGFloat Nothing
- Это типы форматов. Этот тип не экспортируется.
data FFFormat = FFExponent | FFFixed | FFGeneric
formatRealFloat :: (RealFloat a) => FFFormat -> Maybe Int -> a -> String
formatRealFloat fmt decs x
= s
where
base = 10
s = if isNaN x then
"NaN"
else if isInfinite x then
if x < 0 then "-Infinity" else "Infinity"
else if x < 0 || isNegativeZero x then
'-' : doFmt fmt (floatToDigits (toInteger base) (-x))
else
doFmt fmt (floatToDigits (toInteger base) x)
doFmt fmt (is, e)
= let
ds = map intToDigit is
in
case fmt of
FFGeneric ->
doFmt (if e < 0 || e > 7 then FFExponent else FFFixed)
(is, e)
FFExponent ->
case decs of
Nothing ->
case ds of
[] -> "0.0e0"
[d] -> d : ".0e" ++ show (e-1)
d:ds -> d : '.' : ds ++ 'e':show (e-1)
Just dec ->
let dec' = max dec 1 in
case is of
[] -> '0':'.':take dec' (repeat '0') ++ "e0"
_ ->
let (ei, is') = roundTo base (dec'+1) is
d:ds = map intToDigit
(if ei > 0 then init is' else is')
in d:'.':ds ++ "e" ++ show (e-1+ei)
FFFixed ->
case decs of
Nothing - Всегда печатает десятичную точку
| e > 0 -> take e (ds ++ repeat '0')
++ '.' : mk0 (drop e ds)
| otherwise -> "0." ++ mk0 (replicate (-e) '0' ++ ds)
Just dec -> - Печатает десятичную точку, если dec > 0
let dec' = max dec 0 in
if e >= 0 then
let (ei, is') = roundTo base (dec' + e) is
(ls, rs) = splitAt (e+ei)
(map intToDigit is')
in mk0 ls ++ mkdot0 rs
else
let (ei, is') = roundTo base dec'
(replicate (-e) 0 ++ is)
d : ds = map intToDigit
(if ei > 0 then is' else 0:is')
in d : mkdot0 ds
where
mk0 "" = "0" - Печатает 0.34, а не .34
mk0 s = s
mkdot0 "" = "" - Печатает 34, а не 34.
mkdot0 s = '.' : s - когда формат задает отсутствие
- цифр после десятичной точки
roundTo :: Int -> Int -> [Int] -> (Int, [Int])
roundTo base d is = case f d is of
(0, is) -> (0, is)
(1, is) -> (1, 1 : is)
where b2 = base `div` 2
f n [] = (0, replicate n 0)
f 0 (i:_) = (if i >= b2 then 1 else 0, [])
f d (i:is) =
let (c, ds) = f (d-1) is
i' = c + i
in if i' == base then (1, 0:ds) else (0, i':ds)
- Базируется на "Быстрой и точной печати чисел с плавающей точкой"
- Р.Г. Бургера и Р.К. Дайбвига
- ("Printing floatToDigits r = ([a, b, ... z], e)
- то
- r = 0.ab..z * base^e
-
floatToDigits :: (RealFloat a) => Integer -> a -> ([Int], Int)
floatToDigits _ 0 = ([], 0)
floatToDigits base x =
let (f0, e0) = decodeFloat x
(minExp0, _) = floatRange x
p = floatDigits x
b = floatRadix x
minExp = minExp0 - p - действительная минимальная экспонента
- В Haskell требуется, чтобы f было скорректировано так, чтобы денормализационные числа - имели невозможно низкую экспоненту. Для этого используется коррекция.
f :: Integer
e :: Int
(f, e) = let n = minExp - e0
in if n > 0 then (f0 `div` (b^n), e0+n) else (f0, e0)
(r, s, mUp, mDn) =
if e >= 0 then
let be = b^e in
if f == b^(p-1) then
(f*be*b*2, 2*b, be*b, b)
else
(f*be*2, 2, be, be)
else
if e > minExp f == b^(p-1) then
(f*b*2, b^(-e+1)*2, b, 1)
else
(f*2, b^(-e)*2, 1, 1)
k =
let k0 =
if b==2 base==10 then
- logBase 10 2 немного больше, чем 3/10, поэтому
- следующее вызовет ошибку на нижней стороне. Игнорирование
- дроби создаст эту ошибку даже больше.
- Haskell обещает, что p-1 <= logBase b f < p.
(p - 1 + e0) * 3 `div` 10
else
ceiling ((log (fromInteger (f+1)) +
fromIntegral e * log (fromInteger b)) /
log (fromInteger base))
fixup n =
if n >= 0 then
if r + mUp <= expt base n * s then n else fixup (n+1)
else
if expt base (-n) * (r + mUp) <= s then n
else fixup (n+1)
in fixup k0
gen ds rn sN mUpN mDnN =
let (dn, rn') = (rn * base) `divMod` sN
mUpN' = mUpN * base
mDnN' = mDnN * base
in case (rn' < mDnN', rn' + mUpN' > sN) of
(True, False) -> dn : ds
(False, True) -> dn+1 : ds
(True, True) -> if rn' * 2 < sN then dn : ds else dn+1 : ds
(False, False) -> gen (dn:ds) rn' sN mUpN' mDnN'
rds =
if k >= 0 then
gen [] r (s * expt base k) mUp mDn
else
let bk = expt base (-k)
in gen [] (r * bk) s (mUp * bk) (mDn * bk)
in (map fromIntegral (reverse rds), k)
- Эта функция для считывания чисел с плавающей точкой использует менее ограничивающий синтаксис - для чисел с плавающей точкой, чем лексический анализатор Haskell. `.' является необязательной.
readFloat :: (RealFrac a) => ReadS a
readFloat r = [(fromRational ((n%1)*10^^(k-d)),t) | (n,d,s) <- readFix r,
(k,t) <- readExp s] ++
[ (0/0, t) | ("NaN",t) <- lex r] ++
[ (1/0, t) | ("Infinity",t) <- lex r]
where
readFix r = [(read (ds++ds'), length ds', t)
| (ds,d) <- lexDigits r,
(ds',t) <- lexFrac d ]
lexFrac ('.':ds) = lexDigits ds
lexFrac s = [("",s)]
readExp (e:s) | e `elem` "eE" = readExp' s
readExp s = [(0,s)]
readExp' ('-':s) = [(-k,t) | (k,t) <- readDec s]
readExp' ('+':s) = readDec s
readExp' s = readDec s
lexDigits :: ReadS String
lexDigits = nonnull isDigit
nonnull :: (Char -> Bool) -> ReadS String
nonnull p s = [(cs,t) | (cs@(_:_),t) <- [span p s]]
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.