fptest-0.2.3.0: src/FPTypes.hs
{- |
Module : FPTypes
Description : "FPTypes" defines the types needed to represent floating point test cases.
Copyright : (c) John Pavel, 2014
IBM Corp 2004
License : BSD3
Maintainer : jrp@dial.pipex.com
Stability : alpha
Portability : portable
See
<https://www.research.ibm.com/haifa/projects/verification/fpgen/papers/ieee-test-suite-v2.pdfi
Floating-Point Test-Suite for IEEE> and
<https://www.research.ibm.com/haifa/projects/verification/fpgen/syntax.txt
Syntax of the Test Cases>
-}
module FPTypes where
import qualified Control.Exception.Base as H
import Data.List (intercalate)
-- |
-- = Test case specification rendering
-- | 'Display' is used to 'show' values in the original test suite notation
class Show a => Display a where
{- | 'display' shows a test specification element in test suite notation
(defaulting to Haskell show notation if a specialisation
is not provided explicitly) -}
display :: a -> String
display = show
-- | 'display' a list of test specification elements
displayList :: [a] -> String
displayList list = unwords (map display list)
-- | 'printd' wraps display in 'putStrLn'
printd :: a -> IO ()
printd = putStrLn . display
instance Display a => Display [a] where
display = displayList
instance Display Char where
displayList = id
-- |
-- = Test case specification
-- | 'TestCase' provides a test case specification
data TestCase operandType = TestCase {
format :: Format,
operation :: Operation,
roundingMode :: RoundingMode,
trappedExceptions :: [TrappedException],
inputs :: [operandType],
output :: operandType,
outputExceptions :: [Exception]
} deriving (Show)
{- | 'ParsedTestCase' retains the operands and expected output as
the original strings -}
type ParsedTestCase = TestCase String
instance Display a => Display (TestCase a) where
display TestCase {
format = f,
operation = op,
roundingMode = rm,
trappedExceptions = te,
inputs = ins,
output = out,
outputExceptions = oe} =
display f ++ "{" ++ display op ++ "}" ++ display rm ++ " " ++ display te ++ " " ++ display ins ++ " -> "
++ display out ++ " " ++ display oe
displayList list = intercalate "\n" (map display list)
{- | Tests can use either on of the basic floating point formats from
IEEE754R or they can be based on a pair of such formats (for comparison
tests). -}
data Format = BasicFormat BasicFormat |
ComparisonFormat BasicFormat BasicFormat deriving (Show, Eq)
instance Display Format where
display (BasicFormat bf) = display bf
display (ComparisonFormat bf1 bf2) = display bf1 ++ display bf2
{- | 'BasicFormat' represents IEE754R basic formats.
Only 'Binary32' (@b32@ in test specification notation, @Float@)
and 'Binary64' (@b64@, @Double@) tests are implemented.
The binary IBM sample scripts are 'Binary32'only.
'Decimal32 is not required by IEEE754R -}
data BasicFormat = Binary32 | Binary64 | Binary128 |
Decimal32 | Decimal64 | Decimal128 deriving (Show, Eq)
instance Display BasicFormat where
display Binary32 = "b32"
display Binary64 = "b64"
display Binary128 = "b128"
display Decimal32 = "d32"
display Decimal64 = "d64"
display Decimal128 = "d128"
{- | The 'Operation' under test (add, subtract, multiply, divide,
fused multiply-add, square root, remainder, compare, min, max,
round to integer, convert float to float, convert float to integer,
convert integer to float, and convert and round float to integral value,
etc). For arithmetic operations the operands are assumed to have the
same format. -}
data Operation = Add | Subtract | Multiply | Divide | FusedMultiplyAdd |
SquareRoot | Remainder | RoundFloatToInteger |
ConvertFloatToFloat | ConvertFloatToInteger | ConvertIntegerToFloat |
ConvertDecimalToString | ConvertStringToDecimal |
QuietComparison | SignallingComparison |
Copy | Negate | Abs | CopySign | Scalb | Logb | NextAfter | Class |
IsSigned | IsNormal | IsFinite | IsZero | IsSubNormal |
IsInf | IsNaN | IsSignalling |
MinNum | MaxNum | MinNumMag | MaxNumMag | SameQuantum | Quantize |
NextUp | NextDown | Equivalent deriving (Show)
{- | For the moment, 'display' the 'Operation' in Haskell format as it is less
cryptic than the native test specification format -}
instance Display Operation where
display = show
{- display Add = "+"
display Subtract = "-"
display Multiply = "*"
display Divide = "/"
display FusedMultiplyAdd = "*+"
display SquareRoot = "V"
display Remainder = "%"
display RoundFloatToInteger = "rfi"
display ConvertFloatToFloat = "cff"
display ConvertFloatToInteger = "cfi"
display ConvertIntegerToFloat = "cif"
display ConvertDecimalToString = "cfd"
display ConvertStringToDecimal = "cdf"
display QuietComparison = "qC"
display SignallingComparison = "sC"
display Copy = "cp"
display Negate = "~"
display Abs = "A"
display CopySign = "@"
display Scalb = "S"
display Logb = "L"
display NextAfter = "Na"
display Class = "?"
display IsSigned = "?-"
display IsNormal = "?n"
display IsFinite = "?f"
display IsZero = "?0"
display IsSubNormal = "?s"
display IsInf = "?i"
display IsNaN = "?N"
display IsSignalling = "?sN"
display MinNum = "<C"
display MaxNum = ">C"
display MinNumMag = "<A"
display MaxNumMag = ">A"
display SameQuantum = "=quant"
display Quantize = "quant"
display NextUp = "Nu"
display NextDown = "Nd"
display Equivalent = "eq" -}
{- | 'RoundingMode' specifies the rounding mode to be used when executing the test.
It is currently unimplemented as Haskell provides no way of changing rounding
mode. -}
data RoundingMode = PositiveInfinity | NegativeInfinity | Zero | NearestEven |
NearestAwayFromZero deriving (Show, Eq)
instance Display RoundingMode where
display PositiveInfinity = ">"
display NegativeInfinity = "<"
display Zero = "0"
display NearestEven = "=0"
display NearestAwayFromZero = "^0"
{- | 'TrappedException' specifies the exceptions that should be trapped when
the test is executed. This is unimplemented. -}
data TrappedException = TrappedInexact | TrappedUnderflow | TrappedOverflow |
TrappedDivisionByZero | TrappedInvalid deriving (Show, Eq)
instance Display TrappedException where
display TrappedInexact = "x"
display TrappedUnderflow = "u"
display TrappedOverflow = "o"
display TrappedDivisionByZero = "z"
display TrappedInvalid = "i"
{- | 'Exception' specifies a type exception that the test should raise.
This is unimplemented. -}
data Exception = Inexact |
ExtraordinaryUnderflow | InexactTinyUnderflow | TinyInexactUnderflow |
Overflow | DivisionByZero | Invalid deriving (Show, Eq)
instance Display Exception where
display Inexact = "x"
display ExtraordinaryUnderflow = "u"
display InexactTinyUnderflow = "v"
display TinyInexactUnderflow = "w"
display Overflow = "o"
display DivisionByZero = "z"
display Invalid = "i"
-- | 'arithExceptionToException' translates from Haskell native exceptions to
-- the exception type used in test cases.
-- NB: Not used, as Haskell does not raise these exceptions
arithExceptionToException :: H.ArithException -> Exception
arithExceptionToException e =
case e of
H.Overflow -> Overflow
H.Underflow -> ExtraordinaryUnderflow
H.LossOfPrecision -> Inexact
H.DivideByZero -> DivisionByZero
H.Denormal -> ExtraordinaryUnderflow -- Not sure that this is the right mapping
H.RatioZeroDenominator -> error "RatioZeroDenominator is not a floating point exception"