summaryrefslogtreecommitdiff
path: root/src/binary/Data/Binary/IEEE754.lhs
diff options
context:
space:
mode:
authorKrasimir Angelov <kr.angelov@gmail.com>2017-09-04 09:55:17 +0200
committerKrasimir Angelov <kr.angelov@gmail.com>2017-09-04 09:55:17 +0200
commit4fe9f88128515a75f790c353190f340c4179d464 (patch)
tree2abd8102f4d2196a00af3018acd2a882ad035696 /src/binary/Data/Binary/IEEE754.lhs
parentbbdbf2bc5d34d75cef032b395e4a5cc35a89066d (diff)
move the custom Binary package back to src/runtime/haskell
Diffstat (limited to 'src/binary/Data/Binary/IEEE754.lhs')
-rw-r--r--src/binary/Data/Binary/IEEE754.lhs402
1 files changed, 0 insertions, 402 deletions
diff --git a/src/binary/Data/Binary/IEEE754.lhs b/src/binary/Data/Binary/IEEE754.lhs
deleted file mode 100644
index 96cbefc5a..000000000
--- a/src/binary/Data/Binary/IEEE754.lhs
+++ /dev/null
@@ -1,402 +0,0 @@
-% Copyright (C) 2009 John Millikin <jmillikin@gmail.com>
-%
-% This program is free software: you can redistribute it and/or modify
-% it under the terms of the GNU General Public License as published by
-% the Free Software Foundation, either version 3 of the License, or
-% any later version.
-%
-% This program is distributed in the hope that it will be useful,
-% but WITHOUT ANY WARRANTY; without even the implied warranty of
-% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-% GNU General Public License for more details.
-%
-% You should have received a copy of the GNU General Public License
-% along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-\ignore{
-\begin{code}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-module Data.Binary.IEEE754 (
- -- * Parsing
- getFloat16be, getFloat16le
- , getFloat32be, getFloat32le
- , getFloat64be, getFloat64le
-
- -- * Serializing
- , putFloat32be, putFloat32le
- , putFloat64be, putFloat64le
-) where
-
-import Data.Bits ((.&.), (.|.), shiftL, shiftR, Bits)
-import Data.Word (Word8)
-import Data.List (foldl')
-
-import qualified Data.ByteString as B
-import Data.Binary.Get (Get, getByteString)
-import Data.Binary.Put (Put, putByteString)
-\end{code}
-}
-
-\section{Parsing}
-
-\subsection{Public interface}
-
-\begin{code}
-getFloat16be :: Get Float
-getFloat16be = getFloat (ByteCount 2) splitBytes
-\end{code}
-
-\begin{code}
-getFloat16le :: Get Float
-getFloat16le = getFloat (ByteCount 2) $ splitBytes . reverse
-\end{code}
-
-\begin{code}
-getFloat32be :: Get Float
-getFloat32be = getFloat (ByteCount 4) splitBytes
-\end{code}
-
-\begin{code}
-getFloat32le :: Get Float
-getFloat32le = getFloat (ByteCount 4) $ splitBytes . reverse
-\end{code}
-
-\begin{code}
-getFloat64be :: Get Double
-getFloat64be = getFloat (ByteCount 8) splitBytes
-\end{code}
-
-\begin{code}
-getFloat64le :: Get Double
-getFloat64le = getFloat (ByteCount 8) $ splitBytes . reverse
-\end{code}
-
-\subsection{Implementation}
-
-Split the raw byte array into (sign, exponent, significand) components.
-The exponent and signifcand are drawn directly from the bits in the
-original float, and have not been unbiased or otherwise modified.
-
-\begin{code}
-splitBytes :: [Word8] -> RawFloat
-splitBytes bs = RawFloat width sign exp' sig expWidth sigWidth where
- width = ByteCount (length bs)
- nBits = bitsInWord8 bs
- sign = if head bs .&. 0x80 == 0x80
- then Negative
- else Positive
-
- expStart = 1
- expWidth = exponentWidth nBits
- expEnd = expStart + expWidth
- exp' = Exponent . fromIntegral $ bitSlice bs expStart expEnd
-
- sigWidth = nBits - expEnd
- sig = Significand $ bitSlice bs expEnd nBits
-\end{code}
-
-\subsubsection{Encodings and special values}
-
-The next step depends on the value of the exponent $e$, size of the
-exponent field in bits $w$, and value of the significand.
-
-\begin{table}[h]
-\begin{center}
-\begin{tabular}{lrl}
-\toprule
-Exponent & Significand & Format \\
-\midrule
-$0$ & $0$ & Zero \\
-$0$ & $> 0$ & Denormalised \\
-$1 \leq e \leq 2^w - 2$ & \textit{any} & Normalised \\
-$2^w-1$ & $0$ & Infinity \\
-$2^w-1$ & $> 0$ & NaN \\
-\bottomrule
-\end{tabular}
-\end{center}
-\end{table}
-
-There's no built-in literals for Infinity or NaN, so they
-are constructed using the {\tt Read} instances for {\tt Double} and
-{\tt Float}.
-
-\begin{code}
-merge :: (Read a, RealFloat a) => RawFloat -> a
-merge f@(RawFloat _ _ e sig eWidth _)
- | e == 0 = if sig == 0
- then 0.0
- else denormalised f
- | e == eMax - 1 = if sig == 0
- then read "Infinity"
- else read "NaN"
- | otherwise = normalised f
- where eMax = 2 `pow` eWidth
-\end{code}
-
-If a value is normalised, its significand has an implied {\tt 1} bit
-in its most-significant bit. The significand must be adjusted by
-this value before being passed to {\tt encodeField}.
-
-\begin{code}
-normalised :: RealFloat a => RawFloat -> a
-normalised f = encodeFloat fraction exp' where
- Significand sig = rawSignificand f
- Exponent exp' = unbiased - sigWidth
-
- fraction = sig + (1 `bitShiftL` rawSignificandWidth f)
-
- sigWidth = fromIntegral $ rawSignificandWidth f
- unbiased = unbias (rawExponent f) (rawExponentWidth f)
-\end{code}
-
-For denormalised values, the implied {\tt 1} bit is the least-significant
-bit of the exponent.
-
-\begin{code}
-denormalised :: RealFloat a => RawFloat -> a
-denormalised f = encodeFloat sig exp' where
- Significand sig = rawSignificand f
- Exponent exp' = unbiased - sigWidth + 1
-
- sigWidth = fromIntegral $ rawSignificandWidth f
- unbiased = unbias (rawExponent f) (rawExponentWidth f)
-\end{code}
-
-By composing {\tt splitBytes} and {\tt merge}, the absolute value of the
-float is calculated. Before being returned to the calling function, it
-must be signed appropriately.
-
-\begin{code}
-getFloat :: (Read a, RealFloat a) => ByteCount
- -> ([Word8] -> RawFloat) -> Get a
-getFloat (ByteCount width) parser = do
- raw <- fmap (parser . B.unpack) $ getByteString width
- let absFloat = merge raw
- return $ case rawSign raw of
- Positive -> absFloat
- Negative -> -absFloat
-\end{code}
-
-\section{Serialising}
-
-\subsection{Public interface}
-
-\begin{code}
-putFloat32be :: Float -> Put
-putFloat32be = putFloat (ByteCount 4) id
-\end{code}
-
-\begin{code}
-putFloat32le :: Float -> Put
-putFloat32le = putFloat (ByteCount 4) reverse
-\end{code}
-
-\begin{code}
-putFloat64be :: Double -> Put
-putFloat64be = putFloat (ByteCount 8) id
-\end{code}
-
-\begin{code}
-putFloat64le :: Double -> Put
-putFloat64le = putFloat (ByteCount 8) reverse
-\end{code}
-
-\subsection{Implementation}
-
-Serialisation is similar to parsing. First, the float is converted to
-a structure representing raw bitfields. The values returned from
-{\tt decodeFloat} are clamped to their expected lengths before being
-stored in the {\tt RawFloat}.
-
-\begin{code}
-splitFloat :: RealFloat a => ByteCount -> a -> RawFloat
-splitFloat width x = raw where
- raw = RawFloat width sign clampedExp clampedSig expWidth sigWidth
- sign = if isNegativeNaN x || isNegativeZero x || x < 0
- then Negative
- else Positive
- clampedExp = clamp expWidth exp'
- clampedSig = clamp sigWidth sig
- (exp', sig) = case (dFraction, dExponent, biasedExp) of
- (0, 0, _) -> (0, 0)
- (_, _, 0) -> (0, Significand $ truncatedSig + 1)
- _ -> (biasedExp, Significand truncatedSig)
- expWidth = exponentWidth $ bitCount width
- sigWidth = bitCount width - expWidth - 1 -- 1 for sign bit
-
- (dFraction, dExponent) = decodeFloat x
-
- rawExp = Exponent $ dExponent + fromIntegral sigWidth
- biasedExp = bias rawExp expWidth
- truncatedSig = abs dFraction - (1 `bitShiftL` sigWidth)
-\end{code}
-
-Then, the {\tt RawFloat} is converted to a list of bytes by mashing all
-the fields together into an {\tt Integer}, and chopping up that integer
-in 8-bit blocks.
-
-\begin{code}
-rawToBytes :: RawFloat -> [Word8]
-rawToBytes raw = integerToBytes mashed width where
- RawFloat width sign exp' sig expWidth sigWidth = raw
- sign' :: Word8
- sign' = case sign of
- Positive -> 0
- Negative -> 1
- mashed = mashBits sig sigWidth .
- mashBits exp' expWidth .
- mashBits sign' 1 $ 0
-\end{code}
-
-{\tt clamp}, given a maximum bit count and a value, will strip any 1-bits
-in positions above the count.
-
-\begin{code}
-clamp :: (Num a, Bits a) => BitCount -> a -> a
-clamp = (.&.) . mask where
- mask 1 = 1
- mask n | n > 1 = (mask (n - 1) `shiftL` 1) + 1
- mask _ = undefined
-\end{code}
-
-For merging the fields, just shift the starting integer over a bit and
-then \textsc{or} it with the next value. The weird parameter order allows
-easy composition.
-
-\begin{code}
-mashBits :: (Bits a, Integral a) => a -> BitCount -> Integer -> Integer
-mashBits _ 0 x = x
-mashBits y n x = (x `bitShiftL` n) .|. fromIntegral y
-\end{code}
-
-Given an integer, read it in 255-block increments starting from the LSB.
-Each increment is converted to a byte and added to the final list.
-
-\begin{code}
-integerToBytes :: Integer -> ByteCount -> [Word8]
-integerToBytes _ 0 = []
-integerToBytes x n = bytes where
- bytes = integerToBytes (x `shiftR` 8) (n - 1) ++ [step]
- step = fromIntegral x .&. 0xFF
-\end{code}
-
-Finally, the raw parsing is wrapped up in {\tt Put}. The second parameter
-allows the same code paths to be used for little- and big-endian
-serialisation.
-
-\begin{code}
-putFloat :: (RealFloat a) => ByteCount -> ([Word8] -> [Word8]) -> a -> Put
-putFloat width f x = putByteString $ B.pack bytes where
- bytes = f . rawToBytes . splitFloat width $ x
-\end{code}
-
-\section{Raw float components}
-
-Information about the raw bit patterns in the float is stored in
-{\tt RawFloat}, so they don't have to be passed around to the various
-format cases. The exponent should be biased, and the significand
-shouldn't have it's implied MSB (if applicable).
-
-\begin{code}
-data RawFloat = RawFloat
- { rawWidth :: ByteCount
- , rawSign :: Sign
- , rawExponent :: Exponent
- , rawSignificand :: Significand
- , rawExponentWidth :: BitCount
- , rawSignificandWidth :: BitCount
- }
- deriving (Show)
-\end{code}
-
-\section{Exponents}
-
-Calculate the proper size of the exponent field, in bits, given the
-size of the full structure.
-
-\begin{code}
-exponentWidth :: BitCount -> BitCount
-exponentWidth k
- | k == 16 = 5
- | k == 32 = 8
- | k `mod` 32 == 0 = ceiling (4 * logBase 2 (fromIntegral k)) - 13
- | otherwise = error "Invalid length of floating-point value"
-\end{code}
-
-\begin{code}
-bias :: Exponent -> BitCount -> Exponent
-bias e eWidth = e - (1 - (2 `pow` (eWidth - 1)))
-\end{code}
-
-\begin{code}
-unbias :: Exponent -> BitCount -> Exponent
-unbias e eWidth = e + 1 - (2 `pow` (eWidth - 1))
-\end{code}
-
-\section{Byte and bit counting}
-
-\begin{code}
-data Sign = Positive | Negative
- deriving (Show)
-
-newtype Exponent = Exponent Int
- deriving (Show, Eq, Num, Ord, Real, Enum, Integral, Bits)
-
-newtype Significand = Significand Integer
- deriving (Show, Eq, Num, Ord, Real, Enum, Integral, Bits)
-
-newtype BitCount = BitCount Int
- deriving (Show, Eq, Num, Ord, Real, Enum, Integral)
-
-newtype ByteCount = ByteCount Int
- deriving (Show, Eq, Num, Ord, Real, Enum, Integral)
-
-bitCount :: ByteCount -> BitCount
-bitCount (ByteCount x) = BitCount (x * 8)
-
-bitsInWord8 :: [Word8] -> BitCount
-bitsInWord8 = bitCount . ByteCount . length
-
-bitShiftL :: (Bits a) => a -> BitCount -> a
-bitShiftL x (BitCount n) = shiftL x n
-
-bitShiftR :: (Bits a) => a -> BitCount -> a
-bitShiftR x (BitCount n) = shiftR x n
-\end{code}
-
-\section{Utility}
-
-Considering a byte list as a sequence of bits, slice it from start
-inclusive to end exclusive, and return the resulting bit sequence as an
-integer.
-
-\begin{code}
-bitSlice :: [Word8] -> BitCount -> BitCount -> Integer
-bitSlice bs = sliceInt (foldl' step 0 bs) bitCount' where
- step acc w = shiftL acc 8 + fromIntegral w
- bitCount' = bitsInWord8 bs
-\end{code}
-
-Slice a single integer by start and end bit location
-
-\begin{code}
-sliceInt :: Integer -> BitCount -> BitCount -> BitCount -> Integer
-sliceInt x xBitCount s e = fromIntegral sliced where
- sliced = (x .&. startMask) `bitShiftR` (xBitCount - e)
- startMask = n1Bits (xBitCount - s)
- n1Bits n = (2 `pow` n) - 1
-\end{code}
-
-Integral version of {\tt (**)}
-
-\begin{code}
-pow :: (Integral a, Integral b, Integral c) => a -> b -> c
-pow b e = floor $ fromIntegral b ** fromIntegral e
-\end{code}
-
-Detect whether a float is {\tt $-$NaN}
-
-\begin{code}
-isNegativeNaN :: RealFloat a => a -> Bool
-isNegativeNaN x = isNaN x && (floor x > 0)
-\end{code}