From c5cddd581b43851d1104080e2d21ca79436c1a88 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Mon, 8 Jan 2024 20:27:16 -0500 Subject: [PATCH 01/18] improved RealFloat benchmarks --- bench/BenchAll.hs | 163 +++++++++++++++++++++++++++++++++++++++++++--- bytestring.cabal | 3 +- 2 files changed, 156 insertions(+), 10 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 7f95a3e6..e358234f 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -7,6 +7,8 @@ -- Portability : tested on GHC only -- +{-# LANGUAGE ViewPatterns #-} + module Main (main) where import Data.Foldable (foldMap) @@ -19,6 +21,12 @@ import Prelude hiding (words) import qualified Data.List as List import Control.DeepSeq import Control.Exception +import Numeric.IEEE +import GHC.Float (powerFloat, + castWord32ToFloat, + castWord64ToDouble, + castFloatToWord32, + castDoubleToWord64) import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8 @@ -65,7 +73,7 @@ countToZero n = Just (n, n - 1) -- | Few-enough repetitions to avoid making GC too expensive. nRepl :: Int -nRepl = 10000 +nRepl = 1000000 {-# NOINLINE intData #-} intData :: [Int] @@ -79,14 +87,69 @@ smallIntegerData = map fromIntegral intData largeIntegerData :: [Integer] largeIntegerData = map (* (10 ^ (100 :: Integer))) smallIntegerData +{-# NOINLINE floatPosData #-} +floatPosData :: [Float] +floatPosData = map evenlyDistribute intData + where + evenlyDistribute :: Int -> Float + evenlyDistribute x = castWord32ToFloat $ increment * fromIntegral x + increment = castFloatToWord32 maxFinite `div` fromIntegral nRepl + +{-# NOINLINE floatNegData #-} +floatNegData :: [Float] +floatNegData = map negate floatPosData + +{-# NOINLINE floatNaN #-} +floatNaN :: [Float] +floatNaN = map (const nan) intData + +{-# NOINLINE floatPosInf #-} +floatPosInf :: [Float] +floatPosInf = map (const infinity) intData -{-# NOINLINE floatData #-} -floatData :: [Float] -floatData = map (\x -> (3.14159 * fromIntegral x) ^ (3 :: Int)) intData +{-# NOINLINE floatNegInf #-} +floatNegInf :: [Float] +floatNegInf = map (const (negate infinity)) intData + +{-# NOINLINE floatPosZero #-} +floatPosZero :: [Float] +floatPosZero = map (const 0) intData + +{-# NOINLINE floatNegZero #-} +floatNegZero :: [Float] +floatNegZero = map (const (-0)) intData + +{-# NOINLINE doublePosData #-} +doublePosData :: [Double] +doublePosData = map evenlyDistribute intData + where + evenlyDistribute :: Int -> Double + evenlyDistribute x = castWord64ToDouble $ increment * fromIntegral x + increment = castDoubleToWord64 maxFinite `div` fromIntegral nRepl -{-# NOINLINE doubleData #-} -doubleData :: [Double] -doubleData = map (\x -> (3.14159 * fromIntegral x) ^ (3 :: Int)) intData +{-# NOINLINE doubleNegData #-} +doubleNegData :: [Double] +doubleNegData = map negate doublePosData + +{-# NOINLINE doubleNaN #-} +doubleNaN :: [Double] +doubleNaN = map (const nan) intData + +{-# NOINLINE doublePosInf #-} +doublePosInf :: [Double] +doublePosInf = map (const infinity) intData + +{-# NOINLINE doubleNegInf #-} +doubleNegInf :: [Double] +doubleNegInf = map (const (negate infinity)) intData + +{-# NOINLINE doublePosZero #-} +doublePosZero :: [Double] +doublePosZero = map (const 0) intData + +{-# NOINLINE doubleNegZero #-} +doubleNegZero :: [Double] +doubleNegZero = map (const (-0)) intData {-# NOINLINE byteStringData #-} byteStringData :: S.ByteString @@ -353,12 +416,94 @@ main = do , bgroup "Non-bounded encodings" [ benchB "byteStringHex" byteStringData $ byteStringHex , benchB "lazyByteStringHex" lazyByteStringData $ lazyByteStringHex - , benchB "foldMap floatDec" floatData $ foldMap floatDec - , benchB "foldMap doubleDec" doubleData $ foldMap doubleDec -- Note that the small data corresponds to the intData pre-converted -- to Integer. , benchB "foldMap integerDec (small)" smallIntegerData $ foldMap integerDec , benchB "foldMap integerDec (large)" largeIntegerData $ foldMap integerDec + , bgroup "RealFloat" + [ bgroup "FGeneric" + [ bgroup "Positive" + [ benchB "foldMap (formatFloat generic)" floatPosData $ foldMap (formatFloat generic) + , benchB "foldMap (formatDouble generic)" doublePosData $ foldMap (formatDouble generic) + ] + , bgroup "Negative" + [ benchB "foldMap (formatFloat generic)" floatNegData $ foldMap (formatFloat generic) + , benchB "foldMap (formatDouble generic)" doubleNegData $ foldMap (formatDouble generic) + ] + , bgroup "Special" + [ benchB "foldMap (formatFloat generic)" floatNaN $ foldMap (formatFloat generic) + , benchB "foldMap (formatDouble generic)" doubleNaN $ foldMap (formatDouble generic) + , benchB "foldMap (formatFloat generic)" floatPosInf $ foldMap (formatFloat generic) + , benchB "foldMap (formatDouble generic)" doublePosInf $ foldMap (formatDouble generic) + , benchB "foldMap (formatFloat generic)" floatNegInf $ foldMap (formatFloat generic) + , benchB "foldMap (formatDouble generic)" doubleNegInf $ foldMap (formatDouble generic) + , benchB "foldMap (formatFloat generic)" floatPosZero $ foldMap (formatFloat generic) + , benchB "foldMap (formatDouble generic)" doublePosZero $ foldMap (formatDouble generic) + , benchB "foldMap (formatFloat generic)" floatNegZero $ foldMap (formatFloat generic) + , benchB "foldMap (formatDouble generic)" doubleNegZero $ foldMap (formatDouble generic) + ] + ] + , bgroup "FScientific" + [ bgroup "Positive" + [ benchB "foldMap (formatFloat scientific)" floatPosData $ foldMap (formatFloat scientific) + , benchB "foldMap (formatDouble scientific)" doublePosData $ foldMap (formatDouble scientific) + ] + , bgroup "Negative" + [ benchB "foldMap (formatFloat scientific)" floatNegData $ foldMap (formatFloat scientific) + , benchB "foldMap (formatDouble scientific)" doubleNegData $ foldMap (formatDouble scientific) + ] + , bgroup "Special" + [ benchB "foldMap (formatFloat scientific)" floatNaN $ foldMap (formatFloat scientific) + , benchB "foldMap (formatDouble scientific)" doubleNaN $ foldMap (formatDouble scientific) + , benchB "foldMap (formatFloat scientific)" floatPosInf $ foldMap (formatFloat scientific) + , benchB "foldMap (formatDouble scientific)" doublePosInf $ foldMap (formatDouble scientific) + , benchB "foldMap (formatFloat scientific)" floatNegInf $ foldMap (formatFloat scientific) + , benchB "foldMap (formatDouble scientific)" doubleNegInf $ foldMap (formatDouble scientific) + , benchB "foldMap (formatFloat scientific)" floatPosZero $ foldMap (formatFloat scientific) + , benchB "foldMap (formatDouble scientific)" doublePosZero $ foldMap (formatDouble scientific) + , benchB "foldMap (formatFloat scientific)" floatNegZero $ foldMap (formatFloat scientific) + , benchB "foldMap (formatDouble scientific)" doubleNegZero $ foldMap (formatDouble scientific) + ] + ] + , bgroup "FStandard" + [ bgroup "Positive" + [ bgroup "without" + [ benchB "foldMap (formatFloat standardDefaultPrecision)" floatPosData $ foldMap (formatFloat standardDefaultPrecision) + , benchB "foldMap (formatDouble standardDefaultPrecision)" doublePosData $ foldMap (formatDouble standardDefaultPrecision) + ] + , bgroup "precision" + [ benchB "foldMap (formatFloat (standard 1))" floatPosData $ foldMap (formatFloat (standard 1)) + , benchB "foldMap (formatDouble (standard 1))" doublePosData $ foldMap (formatDouble (standard 1)) + , benchB "foldMap (formatFloat (standard 6))" floatPosData $ foldMap (formatFloat (standard 6)) + , benchB "foldMap (formatDouble (standard 6))" doublePosData $ foldMap (formatDouble (standard 6)) + ] + ] + , bgroup "Negative" + [ bgroup "without" + [ benchB "foldMap (formatFloat standardDefaultPrecision)" floatNegData $ foldMap (formatFloat standardDefaultPrecision) + , benchB "foldMap (formatDouble standardDefaultPrecision)" doubleNegData $ foldMap (formatDouble standardDefaultPrecision) + ] + , bgroup "precision" + [ benchB "foldMap (formatFloat (standard 1))" floatNegData $ foldMap (formatFloat (standard 1)) + , benchB "foldMap (formatDouble (standard 1))" doubleNegData $ foldMap (formatDouble (standard 1)) + , benchB "foldMap (formatFloat (standard 6))" floatNegData $ foldMap (formatFloat (standard 6)) + , benchB "foldMap (formatDouble (standard 6))" doubleNegData $ foldMap (formatDouble (standard 6)) + ] + ] + , bgroup "Special" + [ benchB "foldMap (formatFloat standard)" floatNaN $ foldMap (formatFloat standardDefaultPrecision) + , benchB "foldMap (formatDouble standard)" doubleNaN $ foldMap (formatDouble standardDefaultPrecision) + , benchB "foldMap (formatFloat standard)" floatPosInf $ foldMap (formatFloat standardDefaultPrecision) + , benchB "foldMap (formatDouble standard)" doublePosInf $ foldMap (formatDouble standardDefaultPrecision) + , benchB "foldMap (formatFloat standard)" floatNegInf $ foldMap (formatFloat standardDefaultPrecision) + , benchB "foldMap (formatDouble standard)" doubleNegInf $ foldMap (formatDouble standardDefaultPrecision) + , benchB "foldMap (formatFloat standard)" floatPosZero $ foldMap (formatFloat standardDefaultPrecision) + , benchB "foldMap (formatDouble standard)" doublePosZero $ foldMap (formatDouble standardDefaultPrecision) + , benchB "foldMap (formatFloat standard)" floatNegZero $ foldMap (formatFloat standardDefaultPrecision) + , benchB "foldMap (formatDouble standard)" doubleNegZero $ foldMap (formatDouble standardDefaultPrecision) + ] + ] + ] ] ] diff --git a/bytestring.cabal b/bytestring.cabal index 03f09c08..45a344ff 100644 --- a/bytestring.cabal +++ b/bytestring.cabal @@ -241,4 +241,5 @@ benchmark bytestring-bench bytestring, deepseq, tasty-bench, - random + random, + ieee754 From 9e248ac6139c0a134d2e3d6ad54cd4125e46b18a Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Mon, 8 Jan 2024 21:46:04 -0500 Subject: [PATCH 02/18] better names for RealFloat tests --- bench/BenchAll.hs | 84 +++++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index e358234f..6d11b9f6 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -423,53 +423,53 @@ main = do , bgroup "RealFloat" [ bgroup "FGeneric" [ bgroup "Positive" - [ benchB "foldMap (formatFloat generic)" floatPosData $ foldMap (formatFloat generic) - , benchB "foldMap (formatDouble generic)" doublePosData $ foldMap (formatDouble generic) + [ benchB "Float" floatPosData $ foldMap (formatFloat generic) + , benchB "Double" doublePosData $ foldMap (formatDouble generic) ] , bgroup "Negative" - [ benchB "foldMap (formatFloat generic)" floatNegData $ foldMap (formatFloat generic) - , benchB "foldMap (formatDouble generic)" doubleNegData $ foldMap (formatDouble generic) + [ benchB "Float" floatNegData $ foldMap (formatFloat generic) + , benchB "Double" doubleNegData $ foldMap (formatDouble generic) ] , bgroup "Special" - [ benchB "foldMap (formatFloat generic)" floatNaN $ foldMap (formatFloat generic) - , benchB "foldMap (formatDouble generic)" doubleNaN $ foldMap (formatDouble generic) - , benchB "foldMap (formatFloat generic)" floatPosInf $ foldMap (formatFloat generic) - , benchB "foldMap (formatDouble generic)" doublePosInf $ foldMap (formatDouble generic) - , benchB "foldMap (formatFloat generic)" floatNegInf $ foldMap (formatFloat generic) - , benchB "foldMap (formatDouble generic)" doubleNegInf $ foldMap (formatDouble generic) - , benchB "foldMap (formatFloat generic)" floatPosZero $ foldMap (formatFloat generic) - , benchB "foldMap (formatDouble generic)" doublePosZero $ foldMap (formatDouble generic) - , benchB "foldMap (formatFloat generic)" floatNegZero $ foldMap (formatFloat generic) - , benchB "foldMap (formatDouble generic)" doubleNegZero $ foldMap (formatDouble generic) + [ benchB "Float NaN" floatNaN $ foldMap (formatFloat generic) + , benchB "Double NaN" doubleNaN $ foldMap (formatDouble generic) + , benchB "Float PosInf" floatPosInf $ foldMap (formatFloat generic) + , benchB "Double PosInf" doublePosInf $ foldMap (formatDouble generic) + , benchB "Float NegInf" floatNegInf $ foldMap (formatFloat generic) + , benchB "Double NegInf" doubleNegInf $ foldMap (formatDouble generic) + , benchB "Float PosZero" floatPosZero $ foldMap (formatFloat generic) + , benchB "Double PosZero" doublePosZero $ foldMap (formatDouble generic) + , benchB "Float NegZero" floatNegZero $ foldMap (formatFloat generic) + , benchB "Double NegZero" doubleNegZero $ foldMap (formatDouble generic) ] ] , bgroup "FScientific" [ bgroup "Positive" - [ benchB "foldMap (formatFloat scientific)" floatPosData $ foldMap (formatFloat scientific) - , benchB "foldMap (formatDouble scientific)" doublePosData $ foldMap (formatDouble scientific) + [ benchB "Float" floatPosData $ foldMap (formatFloat scientific) + , benchB "Double" doublePosData $ foldMap (formatDouble scientific) ] , bgroup "Negative" - [ benchB "foldMap (formatFloat scientific)" floatNegData $ foldMap (formatFloat scientific) - , benchB "foldMap (formatDouble scientific)" doubleNegData $ foldMap (formatDouble scientific) + [ benchB "Float" floatNegData $ foldMap (formatFloat scientific) + , benchB "Double" doubleNegData $ foldMap (formatDouble scientific) ] , bgroup "Special" - [ benchB "foldMap (formatFloat scientific)" floatNaN $ foldMap (formatFloat scientific) - , benchB "foldMap (formatDouble scientific)" doubleNaN $ foldMap (formatDouble scientific) - , benchB "foldMap (formatFloat scientific)" floatPosInf $ foldMap (formatFloat scientific) - , benchB "foldMap (formatDouble scientific)" doublePosInf $ foldMap (formatDouble scientific) - , benchB "foldMap (formatFloat scientific)" floatNegInf $ foldMap (formatFloat scientific) - , benchB "foldMap (formatDouble scientific)" doubleNegInf $ foldMap (formatDouble scientific) - , benchB "foldMap (formatFloat scientific)" floatPosZero $ foldMap (formatFloat scientific) - , benchB "foldMap (formatDouble scientific)" doublePosZero $ foldMap (formatDouble scientific) - , benchB "foldMap (formatFloat scientific)" floatNegZero $ foldMap (formatFloat scientific) - , benchB "foldMap (formatDouble scientific)" doubleNegZero $ foldMap (formatDouble scientific) + [ benchB "Float NaN" floatNaN $ foldMap (formatFloat scientific) + , benchB "Double NaN" doubleNaN $ foldMap (formatDouble scientific) + , benchB "Float PosInf" floatPosInf $ foldMap (formatFloat scientific) + , benchB "Double PosInf" doublePosInf $ foldMap (formatDouble scientific) + , benchB "Float NegInf" floatNegInf $ foldMap (formatFloat scientific) + , benchB "Double NegInf" doubleNegInf $ foldMap (formatDouble scientific) + , benchB "Float PosZero" floatPosZero $ foldMap (formatFloat scientific) + , benchB "Double PosZero" doublePosZero $ foldMap (formatDouble scientific) + , benchB "Float NegZero" floatNegZero $ foldMap (formatFloat scientific) + , benchB "Double NegZero" doubleNegZero $ foldMap (formatDouble scientific) ] ] , bgroup "FStandard" [ bgroup "Positive" [ bgroup "without" - [ benchB "foldMap (formatFloat standardDefaultPrecision)" floatPosData $ foldMap (formatFloat standardDefaultPrecision) - , benchB "foldMap (formatDouble standardDefaultPrecision)" doublePosData $ foldMap (formatDouble standardDefaultPrecision) + [ benchB "Float" floatPosData $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double" doublePosData $ foldMap (formatDouble standardDefaultPrecision) ] , bgroup "precision" [ benchB "foldMap (formatFloat (standard 1))" floatPosData $ foldMap (formatFloat (standard 1)) @@ -480,8 +480,8 @@ main = do ] , bgroup "Negative" [ bgroup "without" - [ benchB "foldMap (formatFloat standardDefaultPrecision)" floatNegData $ foldMap (formatFloat standardDefaultPrecision) - , benchB "foldMap (formatDouble standardDefaultPrecision)" doubleNegData $ foldMap (formatDouble standardDefaultPrecision) + [ benchB "Float" floatNegData $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double" doubleNegData $ foldMap (formatDouble standardDefaultPrecision) ] , bgroup "precision" [ benchB "foldMap (formatFloat (standard 1))" floatNegData $ foldMap (formatFloat (standard 1)) @@ -491,16 +491,16 @@ main = do ] ] , bgroup "Special" - [ benchB "foldMap (formatFloat standard)" floatNaN $ foldMap (formatFloat standardDefaultPrecision) - , benchB "foldMap (formatDouble standard)" doubleNaN $ foldMap (formatDouble standardDefaultPrecision) - , benchB "foldMap (formatFloat standard)" floatPosInf $ foldMap (formatFloat standardDefaultPrecision) - , benchB "foldMap (formatDouble standard)" doublePosInf $ foldMap (formatDouble standardDefaultPrecision) - , benchB "foldMap (formatFloat standard)" floatNegInf $ foldMap (formatFloat standardDefaultPrecision) - , benchB "foldMap (formatDouble standard)" doubleNegInf $ foldMap (formatDouble standardDefaultPrecision) - , benchB "foldMap (formatFloat standard)" floatPosZero $ foldMap (formatFloat standardDefaultPrecision) - , benchB "foldMap (formatDouble standard)" doublePosZero $ foldMap (formatDouble standardDefaultPrecision) - , benchB "foldMap (formatFloat standard)" floatNegZero $ foldMap (formatFloat standardDefaultPrecision) - , benchB "foldMap (formatDouble standard)" doubleNegZero $ foldMap (formatDouble standardDefaultPrecision) + [ benchB "Float NaN" floatNaN $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double NaN" doubleNaN $ foldMap (formatDouble standardDefaultPrecision) + , benchB "Float PosInf" floatPosInf $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double PosInf" doublePosInf $ foldMap (formatDouble standardDefaultPrecision) + , benchB "Float NegInf" floatNegInf $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double NegInf" doubleNegInf $ foldMap (formatDouble standardDefaultPrecision) + , benchB "Float PosZero" floatPosZero $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double PosZero" doublePosZero $ foldMap (formatDouble standardDefaultPrecision) + , benchB "Float NegZero" floatNegZero $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double NegZero" doubleNegZero $ foldMap (formatDouble standardDefaultPrecision) ] ] ] From 07a60c3233420f70c8f05d13eccbb0a3da892197 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Thu, 11 Jan 2024 21:29:11 -0500 Subject: [PATCH 03/18] averaged realfloat specal strings instead of checking each special value since order changes the bench mark --- bench/BenchAll.hs | 86 ++++++++++------------------------------------- 1 file changed, 17 insertions(+), 69 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 6d11b9f6..410c0bc5 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -73,7 +73,7 @@ countToZero n = Just (n, n - 1) -- | Few-enough repetitions to avoid making GC too expensive. nRepl :: Int -nRepl = 1000000 +nRepl = 100000 {-# NOINLINE intData #-} intData :: [Int] @@ -99,25 +99,11 @@ floatPosData = map evenlyDistribute intData floatNegData :: [Float] floatNegData = map negate floatPosData -{-# NOINLINE floatNaN #-} -floatNaN :: [Float] -floatNaN = map (const nan) intData - -{-# NOINLINE floatPosInf #-} -floatPosInf :: [Float] -floatPosInf = map (const infinity) intData - -{-# NOINLINE floatNegInf #-} -floatNegInf :: [Float] -floatNegInf = map (const (negate infinity)) intData - -{-# NOINLINE floatPosZero #-} -floatPosZero :: [Float] -floatPosZero = map (const 0) intData - -{-# NOINLINE floatNegZero #-} -floatNegZero :: [Float] -floatNegZero = map (const (-0)) intData +{-# NOINLINE floatSpecials #-} +floatSpecials :: [Float] +floatSpecials = foldMap (const specials) [1..nRepl `div` length specials] + where + specials = [nan, infinity, negate infinity, 0 -0] {-# NOINLINE doublePosData #-} doublePosData :: [Double] @@ -131,25 +117,11 @@ doublePosData = map evenlyDistribute intData doubleNegData :: [Double] doubleNegData = map negate doublePosData -{-# NOINLINE doubleNaN #-} -doubleNaN :: [Double] -doubleNaN = map (const nan) intData - -{-# NOINLINE doublePosInf #-} -doublePosInf :: [Double] -doublePosInf = map (const infinity) intData - -{-# NOINLINE doubleNegInf #-} -doubleNegInf :: [Double] -doubleNegInf = map (const (negate infinity)) intData - -{-# NOINLINE doublePosZero #-} -doublePosZero :: [Double] -doublePosZero = map (const 0) intData - -{-# NOINLINE doubleNegZero #-} -doubleNegZero :: [Double] -doubleNegZero = map (const (-0)) intData +{-# NOINLINE doubleSpecials #-} +doubleSpecials :: [Double] +doubleSpecials = foldMap (const specials) [1..nRepl `div` length specials] + where + specials = [nan, infinity, negate infinity, 0 -0] {-# NOINLINE byteStringData #-} byteStringData :: S.ByteString @@ -431,16 +403,8 @@ main = do , benchB "Double" doubleNegData $ foldMap (formatDouble generic) ] , bgroup "Special" - [ benchB "Float NaN" floatNaN $ foldMap (formatFloat generic) - , benchB "Double NaN" doubleNaN $ foldMap (formatDouble generic) - , benchB "Float PosInf" floatPosInf $ foldMap (formatFloat generic) - , benchB "Double PosInf" doublePosInf $ foldMap (formatDouble generic) - , benchB "Float NegInf" floatNegInf $ foldMap (formatFloat generic) - , benchB "Double NegInf" doubleNegInf $ foldMap (formatDouble generic) - , benchB "Float PosZero" floatPosZero $ foldMap (formatFloat generic) - , benchB "Double PosZero" doublePosZero $ foldMap (formatDouble generic) - , benchB "Float NegZero" floatNegZero $ foldMap (formatFloat generic) - , benchB "Double NegZero" doubleNegZero $ foldMap (formatDouble generic) + [ benchB "Float Average" floatSpecials $ foldMap (formatFloat generic) + , benchB "Double Average" doubleSpecials $ foldMap (formatDouble generic) ] ] , bgroup "FScientific" @@ -453,16 +417,8 @@ main = do , benchB "Double" doubleNegData $ foldMap (formatDouble scientific) ] , bgroup "Special" - [ benchB "Float NaN" floatNaN $ foldMap (formatFloat scientific) - , benchB "Double NaN" doubleNaN $ foldMap (formatDouble scientific) - , benchB "Float PosInf" floatPosInf $ foldMap (formatFloat scientific) - , benchB "Double PosInf" doublePosInf $ foldMap (formatDouble scientific) - , benchB "Float NegInf" floatNegInf $ foldMap (formatFloat scientific) - , benchB "Double NegInf" doubleNegInf $ foldMap (formatDouble scientific) - , benchB "Float PosZero" floatPosZero $ foldMap (formatFloat scientific) - , benchB "Double PosZero" doublePosZero $ foldMap (formatDouble scientific) - , benchB "Float NegZero" floatNegZero $ foldMap (formatFloat scientific) - , benchB "Double NegZero" doubleNegZero $ foldMap (formatDouble scientific) + [ benchB "Float Average" floatSpecials $ foldMap (formatFloat scientific) + , benchB "Double Average" doubleSpecials $ foldMap (formatDouble scientific) ] ] , bgroup "FStandard" @@ -491,16 +447,8 @@ main = do ] ] , bgroup "Special" - [ benchB "Float NaN" floatNaN $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double NaN" doubleNaN $ foldMap (formatDouble standardDefaultPrecision) - , benchB "Float PosInf" floatPosInf $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double PosInf" doublePosInf $ foldMap (formatDouble standardDefaultPrecision) - , benchB "Float NegInf" floatNegInf $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double NegInf" doubleNegInf $ foldMap (formatDouble standardDefaultPrecision) - , benchB "Float PosZero" floatPosZero $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double PosZero" doublePosZero $ foldMap (formatDouble standardDefaultPrecision) - , benchB "Float NegZero" floatNegZero $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double NegZero" doubleNegZero $ foldMap (formatDouble standardDefaultPrecision) + [ benchB "Float Average" floatSpecials $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double Average" doubleSpecials $ foldMap (formatDouble standardDefaultPrecision) ] ] ] From 9d995097afd14dc02d8add952f71f6b23882680d Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Fri, 12 Jan 2024 14:32:54 -0500 Subject: [PATCH 04/18] improved test and add bench for small doubles --- bench/BenchAll.hs | 69 +++++++++++++------ bytestring.cabal | 1 + .../builder/Data/ByteString/Builder/Tests.hs | 8 ++- 3 files changed, 55 insertions(+), 23 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 410c0bc5..085d0cee 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -11,6 +11,7 @@ module Main (main) where +import Control.Exception (assert) import Data.Foldable (foldMap) import Data.Monoid import Data.Semigroup @@ -111,12 +112,28 @@ doublePosData = map evenlyDistribute intData where evenlyDistribute :: Int -> Double evenlyDistribute x = castWord64ToDouble $ increment * fromIntegral x - increment = castDoubleToWord64 maxFinite `div` fromIntegral nRepl + increment = (maximum - minimum) `div` fromIntegral nRepl + minimum = castDoubleToWord64 $ succIEEE $ 2 ^ 53 + maximum = castDoubleToWord64 maxFinite {-# NOINLINE doubleNegData #-} doubleNegData :: [Double] doubleNegData = map negate doublePosData +-- f is an integer in the range [1, 2^53). +{-# NOINLINE doublePosSmallData #-} +doublePosSmallData :: [Double] +doublePosSmallData = map evenlyDistribute intData + where + evenlyDistribute = assert (increment > 0) $ \x -> castWord64ToDouble $ increment * fromIntegral x + minimum + increment = (maximum - minimum) `div` fromIntegral nRepl + minimum = castDoubleToWord64 1.0 + maximum = castDoubleToWord64 $ 2 ^ 53 + +{-# NOINLINE doubleNegSmallData #-} +doubleNegSmallData :: [Double] +doubleNegSmallData = map negate doublePosSmallData + {-# NOINLINE doubleSpecials #-} doubleSpecials :: [Double] doubleSpecials = foldMap (const specials) [1..nRepl `div` length specials] @@ -395,12 +412,14 @@ main = do , bgroup "RealFloat" [ bgroup "FGeneric" [ bgroup "Positive" - [ benchB "Float" floatPosData $ foldMap (formatFloat generic) - , benchB "Double" doublePosData $ foldMap (formatDouble generic) + [ benchB "Float" floatPosData $ foldMap (formatFloat generic) + , benchB "Double" doublePosData $ foldMap (formatDouble generic) + , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble generic) ] , bgroup "Negative" - [ benchB "Float" floatNegData $ foldMap (formatFloat generic) - , benchB "Double" doubleNegData $ foldMap (formatDouble generic) + [ benchB "Float" floatNegData $ foldMap (formatFloat generic) + , benchB "Double" doubleNegData $ foldMap (formatDouble generic) + , benchB "DoubleSmall" doubleNegData $ foldMap (formatDouble generic) ] , bgroup "Special" [ benchB "Float Average" floatSpecials $ foldMap (formatFloat generic) @@ -409,12 +428,14 @@ main = do ] , bgroup "FScientific" [ bgroup "Positive" - [ benchB "Float" floatPosData $ foldMap (formatFloat scientific) - , benchB "Double" doublePosData $ foldMap (formatDouble scientific) + [ benchB "Float" floatPosData $ foldMap (formatFloat scientific) + , benchB "Double" doublePosData $ foldMap (formatDouble scientific) + , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble scientific) ] , bgroup "Negative" - [ benchB "Float" floatNegData $ foldMap (formatFloat scientific) - , benchB "Double" doubleNegData $ foldMap (formatDouble scientific) + [ benchB "Float" floatNegData $ foldMap (formatFloat scientific) + , benchB "Double" doubleNegData $ foldMap (formatDouble scientific) + , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble scientific) ] , bgroup "Special" [ benchB "Float Average" floatSpecials $ foldMap (formatFloat scientific) @@ -424,26 +445,32 @@ main = do , bgroup "FStandard" [ bgroup "Positive" [ bgroup "without" - [ benchB "Float" floatPosData $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double" doublePosData $ foldMap (formatDouble standardDefaultPrecision) + [ benchB "Float" floatPosData $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double" doublePosData $ foldMap (formatDouble standardDefaultPrecision) + , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble standardDefaultPrecision) ] , bgroup "precision" - [ benchB "foldMap (formatFloat (standard 1))" floatPosData $ foldMap (formatFloat (standard 1)) - , benchB "foldMap (formatDouble (standard 1))" doublePosData $ foldMap (formatDouble (standard 1)) - , benchB "foldMap (formatFloat (standard 6))" floatPosData $ foldMap (formatFloat (standard 6)) - , benchB "foldMap (formatDouble (standard 6))" doublePosData $ foldMap (formatDouble (standard 6)) + [ benchB "Float-Preciaion-1" floatPosData $ foldMap (formatFloat (standard 1)) + , benchB "Double-Preciaion-1" doublePosData $ foldMap (formatDouble (standard 1)) + , benchB "DoubleSmall-Preciaion-1" doublePosSmallData $ foldMap (formatDouble (standard 1)) + , benchB "Float-Preciaion-6" floatPosData $ foldMap (formatFloat (standard 6)) + , benchB "Double-Preciaion-6" doublePosData $ foldMap (formatDouble (standard 6)) + , benchB "DoubleSmall-Preciaion-6" doublePosSmallData $ foldMap (formatDouble (standard 6)) ] ] , bgroup "Negative" [ bgroup "without" - [ benchB "Float" floatNegData $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double" doubleNegData $ foldMap (formatDouble standardDefaultPrecision) + [ benchB "Float" floatNegData $ foldMap (formatFloat standardDefaultPrecision) + , benchB "Double" doubleNegData $ foldMap (formatDouble standardDefaultPrecision) + , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble standardDefaultPrecision) ] , bgroup "precision" - [ benchB "foldMap (formatFloat (standard 1))" floatNegData $ foldMap (formatFloat (standard 1)) - , benchB "foldMap (formatDouble (standard 1))" doubleNegData $ foldMap (formatDouble (standard 1)) - , benchB "foldMap (formatFloat (standard 6))" floatNegData $ foldMap (formatFloat (standard 6)) - , benchB "foldMap (formatDouble (standard 6))" doubleNegData $ foldMap (formatDouble (standard 6)) + [ benchB "Float-Preciaion-1" floatNegData $ foldMap (formatFloat (standard 1)) + , benchB "Double-Preciaion-1" doubleNegData $ foldMap (formatDouble (standard 1)) + , benchB "DoubleSmall-Preciaion-1" doubleNegSmallData $ foldMap (formatDouble (standard 1)) + , benchB "Float-Preciaion-6" floatNegData $ foldMap (formatFloat (standard 6)) + , benchB "Double-Preciaion-6" doubleNegData $ foldMap (formatDouble (standard 6)) + , benchB "DoubleSmall-Preciaion-6" doubleNegSmallData $ foldMap (formatDouble (standard 6)) ] ] , bgroup "Special" diff --git a/bytestring.cabal b/bytestring.cabal index 45a344ff..bd006dc2 100644 --- a/bytestring.cabal +++ b/bytestring.cabal @@ -214,6 +214,7 @@ test-suite bytestring-tests deepseq, QuickCheck, tasty, + tasty-hunit, tasty-quickcheck >= 0.8.1, template-haskell, transformers >= 0.3, diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index 224f2753..df1f1e3f 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -1,3 +1,6 @@ +{-# LANGUAGE BlockArguments #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} + -- | -- Copyright : (c) 2011 Simon Meier -- License : BSD3-style (see LICENSE) @@ -29,6 +32,7 @@ import Data.Word import qualified Data.ByteString as S import qualified Data.ByteString.Internal as S import qualified Data.ByteString.Lazy as L +import qualified Data.ByteString.Lazy.Char8 as LC import qualified Data.ByteString.Short as Sh import Data.ByteString.Builder @@ -45,6 +49,7 @@ import Numeric (showFFloat) import System.Posix.Internals (c_unlink) import Test.Tasty (TestTree, TestName, testGroup) +import Test.Tasty.HUnit (testCase, (@?=)) import Test.Tasty.QuickCheck ( Arbitrary(..), oneof, choose, listOf, elements , counterexample, ioProperty, Property, testProperty @@ -954,8 +959,7 @@ testsFloating = ] where testExpected :: TestName -> (a -> Builder) -> [(a, String)] -> TestTree - testExpected name dec lst = testProperty name . conjoin $ - fmap (\(x, ref) -> L.unpack (toLazyByteString (dec x)) === encodeASCII ref) lst + testExpected name dec = testCase name . traverse_ \(x, ref) -> LC.unpack (toLazyByteString (dec x)) @?= ref singleMatches :: (a -> Builder) -> (a -> String) -> (a, String) -> Property singleMatches dec refdec (x, ref) = L.unpack (toLazyByteString (dec x)) === encodeASCII (refdec x) .&&. refdec x === ref From 0145d9656c5f20a20b12543ca14ab8d69bd11b6c Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Jan 2024 20:36:55 -0500 Subject: [PATCH 05/18] improved tests for FStandard --- .../builder/Data/ByteString/Builder/Tests.hs | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index df1f1e3f..5e729dec 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -1,4 +1,5 @@ {-# LANGUAGE BlockArguments #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- | @@ -49,7 +50,7 @@ import Numeric (showFFloat) import System.Posix.Internals (c_unlink) import Test.Tasty (TestTree, TestName, testGroup) -import Test.Tasty.HUnit (testCase, (@?=)) +import Test.Tasty.HUnit (testCase, (@?=), Assertion) import Test.Tasty.QuickCheck ( Arbitrary(..), oneof, choose, listOf, elements , counterexample, ioProperty, Property, testProperty @@ -777,12 +778,22 @@ testsFloating = , ( 4.294967294 , "4.294967294e0" ) , ( 4.294967295 , "4.294967295e0" ) ] - , testProperty "d2sStandard" $ conjoin - [ singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34" ) - , singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0050 , "0.00" ) - , singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0051 , "0.01" ) - , singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" ) - ] + , testGroup "d2sStandard" + [ testCase "specific" do + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3 , "12.30" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3451 , "12.35" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0050 , "0.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.999 , "1000.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.199 , "999.20" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.999 , "1.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0051 , "0.01" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0056 , "0.006" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0096 , "0.010" ) + singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0 , "0.000" ) + , testProperty "standard N" \(NonNegative p, d :: Double) -> (LC.unpack . toLazyByteString) (formatDouble (standard p) d) === showFFloat (Just p) d "" + ] , testMatches "d2sLooksLikePowerOf5" doubleDec show [ ( (coerceWord64ToDouble 0x4830F0CF064DD592) , "5.764607523034235e39" ) , ( (coerceWord64ToDouble 0x4840F0CF064DD592) , "1.152921504606847e40" ) @@ -961,11 +972,13 @@ testsFloating = testExpected :: TestName -> (a -> Builder) -> [(a, String)] -> TestTree testExpected name dec = testCase name . traverse_ \(x, ref) -> LC.unpack (toLazyByteString (dec x)) @?= ref - singleMatches :: (a -> Builder) -> (a -> String) -> (a, String) -> Property - singleMatches dec refdec (x, ref) = L.unpack (toLazyByteString (dec x)) === encodeASCII (refdec x) .&&. refdec x === ref + singleMatches :: (a -> Builder) -> (a -> String) -> (a, String) -> Assertion + singleMatches dec refdec (x, ref) = do + LC.unpack (toLazyByteString (dec x)) @?= refdec x + refdec x @?= ref testMatches :: TestName -> (a -> Builder) -> (a -> String) -> [(a, String)] -> TestTree - testMatches name dec refdec lst = testProperty name . conjoin $ fmap (singleMatches dec refdec) lst + testMatches name dec refdec = testCase name . traverse_ (singleMatches dec refdec) maxMantissa = (1 `shiftL` 53) - 1 :: Word64 From fe5d0c1b3f991dfa81907f0f8b8d55a81eeb1623 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Jan 2024 20:56:18 -0500 Subject: [PATCH 06/18] added better labels to real float tests --- .../builder/Data/ByteString/Builder/Tests.hs | 646 +++++++++--------- 1 file changed, 325 insertions(+), 321 deletions(-) diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index 5e729dec..58d50e35 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -74,7 +74,7 @@ tests = testsEncodingToBuilder ++ testsBinary ++ testsASCII ++ - testsFloating ++ + testsFloating : testsChar8 ++ testsUtf8 ++ [testLaziness] @@ -642,327 +642,331 @@ testsASCII = enlarge (n, e) = n ^ (abs (e `mod` (50 :: Integer))) testsFloating :: [TestTree] -testsFloating = - [ testMatches "f2sBasic" floatDec show - [ ( 0.0 , "0.0" ) - , ( (-0.0) , "-0.0" ) - , ( 1.0 , "1.0" ) - , ( (-1.0) , "-1.0" ) - , ( (0/0) , "NaN" ) - , ( (1/0) , "Infinity" ) - , ( (-1/0) , "-Infinity" ) - ] - , testMatches "f2sSubnormal" floatDec show - [ ( 1.1754944e-38 , "1.1754944e-38" ) - ] - , testMatches "f2sMinAndMax" floatDec show - [ ( coerceWord32ToFloat 0x7f7fffff , "3.4028235e38" ) - , ( coerceWord32ToFloat 0x00000001 , "1.0e-45" ) - ] - , testMatches "f2sBoundaryRound" floatDec show - [ ( 3.355445e7 , "3.3554448e7" ) - , ( 8.999999e9 , "8.999999e9" ) - , ( 3.4366717e10 , "3.4366718e10" ) - ] - , testMatches "f2sExactValueRound" floatDec show - [ ( 3.0540412e5 , "305404.13" ) - , ( 8.0990312e3 , "8099.0313" ) - ] - , testMatches "f2sTrailingZeros" floatDec show - -- Pattern for the first test: 00111001100000000000000000000000 - [ ( 2.4414062e-4 , "2.4414063e-4" ) - , ( 2.4414062e-3 , "2.4414063e-3" ) - , ( 4.3945312e-3 , "4.3945313e-3" ) - , ( 6.3476562e-3 , "6.3476563e-3" ) - ] - , testMatches "f2sRegression" floatDec show - [ ( 4.7223665e21 , "4.7223665e21" ) - , ( 8388608.0 , "8388608.0" ) - , ( 1.6777216e7 , "1.6777216e7" ) - , ( 3.3554436e7 , "3.3554436e7" ) - , ( 6.7131496e7 , "6.7131496e7" ) - , ( 1.9310392e-38 , "1.9310392e-38" ) - , ( (-2.47e-43) , "-2.47e-43" ) - , ( 1.993244e-38 , "1.993244e-38" ) - , ( 4103.9003 , "4103.9004" ) - , ( 5.3399997e9 , "5.3399997e9" ) - , ( 6.0898e-39 , "6.0898e-39" ) - , ( 0.0010310042 , "1.0310042e-3" ) - , ( 2.8823261e17 , "2.882326e17" ) - , ( 7.0385309e-26 , "7.038531e-26" ) - , ( 9.2234038e17 , "9.223404e17" ) - , ( 6.7108872e7 , "6.710887e7" ) - , ( 1.0e-44 , "1.0e-44" ) - , ( 2.816025e14 , "2.816025e14" ) - , ( 9.223372e18 , "9.223372e18" ) - , ( 1.5846085e29 , "1.5846086e29" ) - , ( 1.1811161e19 , "1.1811161e19" ) - , ( 5.368709e18 , "5.368709e18" ) - , ( 4.6143165e18 , "4.6143166e18" ) - , ( 0.007812537 , "7.812537e-3" ) - , ( 1.4e-45 , "1.0e-45" ) - , ( 1.18697724e20 , "1.18697725e20" ) - , ( 1.00014165e-36 , "1.00014165e-36" ) - , ( 200.0 , "200.0" ) - , ( 3.3554432e7 , "3.3554432e7" ) - , ( 2.0019531 , "2.0019531" ) - , ( 2.001953 , "2.001953" ) - ] - , testExpected "f2sScientific" (formatFloat scientific) - [ ( 0.0 , "0.0e0" ) - , ( 8388608.0 , "8.388608e6" ) - , ( 1.6777216e7 , "1.6777216e7" ) - , ( 3.3554436e7 , "3.3554436e7" ) - , ( 6.7131496e7 , "6.7131496e7" ) - , ( 1.9310392e-38 , "1.9310392e-38" ) - , ( (-2.47e-43) , "-2.47e-43" ) - , ( 1.993244e-38 , "1.993244e-38" ) - , ( 4103.9003 , "4.1039004e3" ) - , ( 0.0010310042 , "1.0310042e-3" ) - , ( 0.007812537 , "7.812537e-3" ) - , ( 200.0 , "2.0e2" ) - , ( 2.0019531 , "2.0019531e0" ) - , ( 2.001953 , "2.001953e0" ) - ] - , testMatches "f2sLooksLikePowerOf5" floatDec show - [ ( coerceWord32ToFloat 0x5D1502F9 , "6.7108864e17" ) - , ( coerceWord32ToFloat 0x5D9502F9 , "1.3421773e18" ) - , ( coerceWord32ToFloat 0x5e1502F9 , "2.6843546e18" ) - ] - , testMatches "f2sOutputLength" floatDec show - [ ( 1.0 , "1.0" ) - , ( 1.2 , "1.2" ) - , ( 1.23 , "1.23" ) - , ( 1.234 , "1.234" ) - , ( 1.2345 , "1.2345" ) - , ( 1.23456 , "1.23456" ) - , ( 1.234567 , "1.234567" ) - , ( 1.2345678 , "1.2345678" ) - , ( 1.23456735e-36 , "1.23456735e-36" ) - ] - , testMatches "d2sBasic" doubleDec show - [ ( 0.0 , "0.0" ) - , ( (-0.0) , "-0.0" ) - , ( 1.0 , "1.0" ) - , ( (-1.0) , "-1.0" ) - , ( (0/0) , "NaN" ) - , ( (1/0) , "Infinity" ) - , ( (-1/0) , "-Infinity" ) - ] - , testMatches "d2sSubnormal" doubleDec show - [ ( 2.2250738585072014e-308 , "2.2250738585072014e-308" ) - ] - , testMatches "d2sMinAndMax" doubleDec show - [ ( (coerceWord64ToDouble 0x7fefffffffffffff) , "1.7976931348623157e308" ) - , ( (coerceWord64ToDouble 0x0000000000000001) , "5.0e-324" ) - ] - , testMatches "d2sTrailingZeros" doubleDec show - [ ( 2.98023223876953125e-8 , "2.9802322387695313e-8" ) - ] - , testMatches "d2sRegression" doubleDec show - [ ( (-2.109808898695963e16) , "-2.1098088986959632e16" ) - , ( 4.940656e-318 , "4.940656e-318" ) - , ( 1.18575755e-316 , "1.18575755e-316" ) - , ( 2.989102097996e-312 , "2.989102097996e-312" ) - , ( 9.0608011534336e15 , "9.0608011534336e15" ) - , ( 4.708356024711512e18 , "4.708356024711512e18" ) - , ( 9.409340012568248e18 , "9.409340012568248e18" ) - , ( 1.2345678 , "1.2345678" ) - , ( 1.9430376160308388e16 , "1.9430376160308388e16" ) - , ( (-6.9741824662760956e19), "-6.9741824662760956e19" ) - , ( 4.3816050601147837e18 , "4.3816050601147837e18" ) - ] - , testExpected "d2sScientific" (formatDouble scientific) - [ ( 0.0 , "0.0e0" ) - , ( 1.2345678 , "1.2345678e0" ) - , ( 4.294967294 , "4.294967294e0" ) - , ( 4.294967295 , "4.294967295e0" ) - ] - , testGroup "d2sStandard" - [ testCase "specific" do - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3 , "12.30" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3451 , "12.35" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0050 , "0.00" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.999 , "1000.00" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.199 , "999.20" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.999 , "1.00" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0051 , "0.01" ) - singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0056 , "0.006" ) - singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0096 , "0.010" ) - singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" ) - singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0 , "0.000" ) - , testProperty "standard N" \(NonNegative p, d :: Double) -> (LC.unpack . toLazyByteString) (formatDouble (standard p) d) === showFFloat (Just p) d "" - ] - , testMatches "d2sLooksLikePowerOf5" doubleDec show - [ ( (coerceWord64ToDouble 0x4830F0CF064DD592) , "5.764607523034235e39" ) - , ( (coerceWord64ToDouble 0x4840F0CF064DD592) , "1.152921504606847e40" ) - , ( (coerceWord64ToDouble 0x4850F0CF064DD592) , "2.305843009213694e40" ) - , ( (coerceWord64ToDouble 0x4400000000000004) , "3.689348814741914e19" ) - - -- here v- is a power of 5 but since we don't accept bounds there is no - -- interesting trailing behavior - , ( (coerceWord64ToDouble 0x440000000000301d) , "3.6893488147520004e19" ) - ] - , testMatches "d2sOutputLength" doubleDec show - [ ( 1 , "1.0" ) - , ( 1.2 , "1.2" ) - , ( 1.23 , "1.23" ) - , ( 1.234 , "1.234" ) - , ( 1.2345 , "1.2345" ) - , ( 1.23456 , "1.23456" ) - , ( 1.234567 , "1.234567" ) - , ( 1.2345678 , "1.2345678" ) - , ( 1.23456789 , "1.23456789" ) - , ( 1.234567895 , "1.234567895" ) - , ( 1.2345678901 , "1.2345678901" ) - , ( 1.23456789012 , "1.23456789012" ) - , ( 1.234567890123 , "1.234567890123" ) - , ( 1.2345678901234 , "1.2345678901234" ) - , ( 1.23456789012345 , "1.23456789012345" ) - , ( 1.234567890123456 , "1.234567890123456" ) - , ( 1.2345678901234567 , "1.2345678901234567" ) - - -- Test 32-bit chunking - , ( 4.294967294 , "4.294967294" ) - , ( 4.294967295 , "4.294967295" ) - , ( 4.294967296 , "4.294967296" ) - , ( 4.294967297 , "4.294967297" ) - , ( 4.294967298 , "4.294967298" ) - ] - , testMatches "d2sMinMaxShift" doubleDec show - [ ( (ieeeParts2Double False 4 0) , "1.7800590868057611e-307" ) - -- 32-bit opt-size=0: 49 <= dist <= 49 - -- 32-bit opt-size=1: 28 <= dist <= 49 - -- 64-bit opt-size=0: 50 <= dist <= 50 - -- 64-bit opt-size=1: 28 <= dist <= 50 - , ( (ieeeParts2Double False 6 maxMantissa) , "2.8480945388892175e-306" ) - -- 32-bit opt-size=0: 52 <= dist <= 53 - -- 32-bit opt-size=1: 2 <= dist <= 53 - -- 64-bit opt-size=0: 53 <= dist <= 53 - -- 64-bit opt-size=1: 2 <= dist <= 53 - , ( (ieeeParts2Double False 41 0) , "2.446494580089078e-296" ) - -- 32-bit opt-size=0: 52 <= dist <= 52 - -- 32-bit opt-size=1: 2 <= dist <= 52 - -- 64-bit opt-size=0: 53 <= dist <= 53 - -- 64-bit opt-size=1: 2 <= dist <= 53 - , ( (ieeeParts2Double False 40 maxMantissa) , "4.8929891601781557e-296" ) - -- 32-bit opt-size=0: 57 <= dist <= 58 - -- 32-bit opt-size=1: 57 <= dist <= 58 - -- 64-bit opt-size=0: 58 <= dist <= 58 - -- 64-bit opt-size=1: 58 <= dist <= 58 - , ( (ieeeParts2Double False 1077 0) , "1.8014398509481984e16" ) - -- 32-bit opt-size=0: 57 <= dist <= 57 - -- 32-bit opt-size=1: 57 <= dist <= 57 - -- 64-bit opt-size=0: 58 <= dist <= 58 - -- 64-bit opt-size=1: 58 <= dist <= 58 - , ( (ieeeParts2Double False 1076 maxMantissa) , "3.6028797018963964e16" ) - -- 32-bit opt-size=0: 51 <= dist <= 52 - -- 32-bit opt-size=1: 51 <= dist <= 59 - -- 64-bit opt-size=0: 52 <= dist <= 52 - -- 64-bit opt-size=1: 52 <= dist <= 59 - , ( (ieeeParts2Double False 307 0) , "2.900835519859558e-216" ) - -- 32-bit opt-size=0: 51 <= dist <= 51 - -- 32-bit opt-size=1: 51 <= dist <= 59 - -- 64-bit opt-size=0: 52 <= dist <= 52 - -- 64-bit opt-size=1: 52 <= dist <= 59 - , ( (ieeeParts2Double False 306 maxMantissa) , "5.801671039719115e-216" ) - -- 32-bit opt-size=0: 49 <= dist <= 49 - -- 32-bit opt-size=1: 44 <= dist <= 49 - -- 64-bit opt-size=0: 50 <= dist <= 50 - -- 64-bit opt-size=1: 44 <= dist <= 50 - , ( (ieeeParts2Double False 934 0x000FA7161A4D6e0C) , "3.196104012172126e-27" ) - ] - , testMatches "d2sSmallIntegers" doubleDec show - [ ( 9007199254740991.0 , "9.007199254740991e15" ) - , ( 9007199254740992.0 , "9.007199254740992e15" ) - - , ( 1.0e+0 , "1.0" ) - , ( 1.2e+1 , "12.0" ) - , ( 1.23e+2 , "123.0" ) - , ( 1.234e+3 , "1234.0" ) - , ( 1.2345e+4 , "12345.0" ) - , ( 1.23456e+5 , "123456.0" ) - , ( 1.234567e+6 , "1234567.0" ) - , ( 1.2345678e+7 , "1.2345678e7" ) - , ( 1.23456789e+8 , "1.23456789e8" ) - , ( 1.23456789e+9 , "1.23456789e9" ) - , ( 1.234567895e+9 , "1.234567895e9" ) - , ( 1.2345678901e+10 , "1.2345678901e10" ) - , ( 1.23456789012e+11 , "1.23456789012e11" ) - , ( 1.234567890123e+12 , "1.234567890123e12" ) - , ( 1.2345678901234e+13 , "1.2345678901234e13" ) - , ( 1.23456789012345e+14 , "1.23456789012345e14" ) - , ( 1.234567890123456e+15 , "1.234567890123456e15" ) - - -- 10^i - , ( 1.0e+0 , "1.0" ) - , ( 1.0e+1 , "10.0" ) - , ( 1.0e+2 , "100.0" ) - , ( 1.0e+3 , "1000.0" ) - , ( 1.0e+4 , "10000.0" ) - , ( 1.0e+5 , "100000.0" ) - , ( 1.0e+6 , "1000000.0" ) - , ( 1.0e+7 , "1.0e7" ) - , ( 1.0e+8 , "1.0e8" ) - , ( 1.0e+9 , "1.0e9" ) - , ( 1.0e+10 , "1.0e10" ) - , ( 1.0e+11 , "1.0e11" ) - , ( 1.0e+12 , "1.0e12" ) - , ( 1.0e+13 , "1.0e13" ) - , ( 1.0e+14 , "1.0e14" ) - , ( 1.0e+15 , "1.0e15" ) - - -- 10^15 + 10^i - , ( (1.0e+15 + 1.0e+0) , "1.000000000000001e15" ) - , ( (1.0e+15 + 1.0e+1) , "1.00000000000001e15" ) - , ( (1.0e+15 + 1.0e+2) , "1.0000000000001e15" ) - , ( (1.0e+15 + 1.0e+3) , "1.000000000001e15" ) - , ( (1.0e+15 + 1.0e+4) , "1.00000000001e15" ) - , ( (1.0e+15 + 1.0e+5) , "1.0000000001e15" ) - , ( (1.0e+15 + 1.0e+6) , "1.000000001e15" ) - , ( (1.0e+15 + 1.0e+7) , "1.00000001e15" ) - , ( (1.0e+15 + 1.0e+8) , "1.0000001e15" ) - , ( (1.0e+15 + 1.0e+9) , "1.000001e15" ) - , ( (1.0e+15 + 1.0e+10) , "1.00001e15" ) - , ( (1.0e+15 + 1.0e+11) , "1.0001e15" ) - , ( (1.0e+15 + 1.0e+12) , "1.001e15" ) - , ( (1.0e+15 + 1.0e+13) , "1.01e15" ) - , ( (1.0e+15 + 1.0e+14) , "1.1e15" ) - - -- Largest power of 2 <= 10^(i+1) - , ( 8.0 , "8.0" ) - , ( 64.0 , "64.0" ) - , ( 512.0 , "512.0" ) - , ( 8192.0 , "8192.0" ) - , ( 65536.0 , "65536.0" ) - , ( 524288.0 , "524288.0" ) - , ( 8388608.0 , "8388608.0" ) - , ( 67108864.0 , "6.7108864e7" ) - , ( 536870912.0 , "5.36870912e8" ) - , ( 8589934592.0 , "8.589934592e9" ) - , ( 68719476736.0 , "6.8719476736e10" ) - , ( 549755813888.0 , "5.49755813888e11" ) - , ( 8796093022208.0 , "8.796093022208e12" ) - , ( 70368744177664.0 , "7.0368744177664e13" ) - , ( 562949953421312.0 , "5.62949953421312e14" ) - , ( 9007199254740992.0 , "9.007199254740992e15" ) - - -- 1000 * (Largest power of 2 <= 10^(i+1)) - , ( 8.0e+3 , "8000.0" ) - , ( 64.0e+3 , "64000.0" ) - , ( 512.0e+3 , "512000.0" ) - , ( 8192.0e+3 , "8192000.0" ) - , ( 65536.0e+3 , "6.5536e7" ) - , ( 524288.0e+3 , "5.24288e8" ) - , ( 8388608.0e+3 , "8.388608e9" ) - , ( 67108864.0e+3 , "6.7108864e10" ) - , ( 536870912.0e+3 , "5.36870912e11" ) - , ( 8589934592.0e+3 , "8.589934592e12" ) - , ( 68719476736.0e+3 , "6.8719476736e13" ) - , ( 549755813888.0e+3 , "5.49755813888e14" ) - , ( 8796093022208.0e+3 , "8.796093022208e15" ) +testsFloating = testGroup "RealFloat" + [ testGroup "Float" + [ testMatches "f2sBasic" floatDec show + [ ( 0.0 , "0.0" ) + , ( (-0.0) , "-0.0" ) + , ( 1.0 , "1.0" ) + , ( (-1.0) , "-1.0" ) + , ( (0/0) , "NaN" ) + , ( (1/0) , "Infinity" ) + , ( (-1/0) , "-Infinity" ) + ] + , testMatches "f2sSubnormal" floatDec show + [ ( 1.1754944e-38 , "1.1754944e-38" ) + ] + , testMatches "f2sMinAndMax" floatDec show + [ ( coerceWord32ToFloat 0x7f7fffff , "3.4028235e38" ) + , ( coerceWord32ToFloat 0x00000001 , "1.0e-45" ) + ] + , testMatches "f2sBoundaryRound" floatDec show + [ ( 3.355445e7 , "3.3554448e7" ) + , ( 8.999999e9 , "8.999999e9" ) + , ( 3.4366717e10 , "3.4366718e10" ) + ] + , testMatches "f2sExactValueRound" floatDec show + [ ( 3.0540412e5 , "305404.13" ) + , ( 8.0990312e3 , "8099.0313" ) + ] + , testMatches "f2sTrailingZeros" floatDec show + -- Pattern for the first test: 00111001100000000000000000000000 + [ ( 2.4414062e-4 , "2.4414063e-4" ) + , ( 2.4414062e-3 , "2.4414063e-3" ) + , ( 4.3945312e-3 , "4.3945313e-3" ) + , ( 6.3476562e-3 , "6.3476563e-3" ) + ] + , testMatches "f2sRegression" floatDec show + [ ( 4.7223665e21 , "4.7223665e21" ) + , ( 8388608.0 , "8388608.0" ) + , ( 1.6777216e7 , "1.6777216e7" ) + , ( 3.3554436e7 , "3.3554436e7" ) + , ( 6.7131496e7 , "6.7131496e7" ) + , ( 1.9310392e-38 , "1.9310392e-38" ) + , ( (-2.47e-43) , "-2.47e-43" ) + , ( 1.993244e-38 , "1.993244e-38" ) + , ( 4103.9003 , "4103.9004" ) + , ( 5.3399997e9 , "5.3399997e9" ) + , ( 6.0898e-39 , "6.0898e-39" ) + , ( 0.0010310042 , "1.0310042e-3" ) + , ( 2.8823261e17 , "2.882326e17" ) + , ( 7.0385309e-26 , "7.038531e-26" ) + , ( 9.2234038e17 , "9.223404e17" ) + , ( 6.7108872e7 , "6.710887e7" ) + , ( 1.0e-44 , "1.0e-44" ) + , ( 2.816025e14 , "2.816025e14" ) + , ( 9.223372e18 , "9.223372e18" ) + , ( 1.5846085e29 , "1.5846086e29" ) + , ( 1.1811161e19 , "1.1811161e19" ) + , ( 5.368709e18 , "5.368709e18" ) + , ( 4.6143165e18 , "4.6143166e18" ) + , ( 0.007812537 , "7.812537e-3" ) + , ( 1.4e-45 , "1.0e-45" ) + , ( 1.18697724e20 , "1.18697725e20" ) + , ( 1.00014165e-36 , "1.00014165e-36" ) + , ( 200.0 , "200.0" ) + , ( 3.3554432e7 , "3.3554432e7" ) + , ( 2.0019531 , "2.0019531" ) + , ( 2.001953 , "2.001953" ) + ] + , testExpected "f2sScientific" (formatFloat scientific) + [ ( 0.0 , "0.0e0" ) + , ( 8388608.0 , "8.388608e6" ) + , ( 1.6777216e7 , "1.6777216e7" ) + , ( 3.3554436e7 , "3.3554436e7" ) + , ( 6.7131496e7 , "6.7131496e7" ) + , ( 1.9310392e-38 , "1.9310392e-38" ) + , ( (-2.47e-43) , "-2.47e-43" ) + , ( 1.993244e-38 , "1.993244e-38" ) + , ( 4103.9003 , "4.1039004e3" ) + , ( 0.0010310042 , "1.0310042e-3" ) + , ( 0.007812537 , "7.812537e-3" ) + , ( 200.0 , "2.0e2" ) + , ( 2.0019531 , "2.0019531e0" ) + , ( 2.001953 , "2.001953e0" ) + ] + , testMatches "f2sLooksLikePowerOf5" floatDec show + [ ( coerceWord32ToFloat 0x5D1502F9 , "6.7108864e17" ) + , ( coerceWord32ToFloat 0x5D9502F9 , "1.3421773e18" ) + , ( coerceWord32ToFloat 0x5e1502F9 , "2.6843546e18" ) + ] + , testMatches "f2sOutputLength" floatDec show + [ ( 1.0 , "1.0" ) + , ( 1.2 , "1.2" ) + , ( 1.23 , "1.23" ) + , ( 1.234 , "1.234" ) + , ( 1.2345 , "1.2345" ) + , ( 1.23456 , "1.23456" ) + , ( 1.234567 , "1.234567" ) + , ( 1.2345678 , "1.2345678" ) + , ( 1.23456735e-36 , "1.23456735e-36" ) + ] + ] + testGroup "Double" + [ testMatches "d2sBasic" doubleDec show + [ ( 0.0 , "0.0" ) + , ( (-0.0) , "-0.0" ) + , ( 1.0 , "1.0" ) + , ( (-1.0) , "-1.0" ) + , ( (0/0) , "NaN" ) + , ( (1/0) , "Infinity" ) + , ( (-1/0) , "-Infinity" ) + ] + , testMatches "d2sSubnormal" doubleDec show + [ ( 2.2250738585072014e-308 , "2.2250738585072014e-308" ) + ] + , testMatches "d2sMinAndMax" doubleDec show + [ ( (coerceWord64ToDouble 0x7fefffffffffffff) , "1.7976931348623157e308" ) + , ( (coerceWord64ToDouble 0x0000000000000001) , "5.0e-324" ) + ] + , testMatches "d2sTrailingZeros" doubleDec show + [ ( 2.98023223876953125e-8 , "2.9802322387695313e-8" ) + ] + , testMatches "d2sRegression" doubleDec show + [ ( (-2.109808898695963e16) , "-2.1098088986959632e16" ) + , ( 4.940656e-318 , "4.940656e-318" ) + , ( 1.18575755e-316 , "1.18575755e-316" ) + , ( 2.989102097996e-312 , "2.989102097996e-312" ) + , ( 9.0608011534336e15 , "9.0608011534336e15" ) + , ( 4.708356024711512e18 , "4.708356024711512e18" ) + , ( 9.409340012568248e18 , "9.409340012568248e18" ) + , ( 1.2345678 , "1.2345678" ) + , ( 1.9430376160308388e16 , "1.9430376160308388e16" ) + , ( (-6.9741824662760956e19), "-6.9741824662760956e19" ) + , ( 4.3816050601147837e18 , "4.3816050601147837e18" ) + ] + , testExpected "d2sScientific" (formatDouble scientific) + [ ( 0.0 , "0.0e0" ) + , ( 1.2345678 , "1.2345678e0" ) + , ( 4.294967294 , "4.294967294e0" ) + , ( 4.294967295 , "4.294967295e0" ) + ] + , testGroup "d2sStandard" + [ testCase "specific" do + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3 , "12.30" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3451 , "12.35" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0050 , "0.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.999 , "1000.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.199 , "999.20" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.999 , "1.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0051 , "0.01" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0056 , "0.006" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0096 , "0.010" ) + singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0 , "0.000" ) + , testProperty "standard N" \(NonNegative p, d :: Double) -> (LC.unpack . toLazyByteString) (formatDouble (standard p) d) === showFFloat (Just p) d "" ] + , testMatches "d2sLooksLikePowerOf5" doubleDec show + [ ( (coerceWord64ToDouble 0x4830F0CF064DD592) , "5.764607523034235e39" ) + , ( (coerceWord64ToDouble 0x4840F0CF064DD592) , "1.152921504606847e40" ) + , ( (coerceWord64ToDouble 0x4850F0CF064DD592) , "2.305843009213694e40" ) + , ( (coerceWord64ToDouble 0x4400000000000004) , "3.689348814741914e19" ) + + -- here v- is a power of 5 but since we don't accept bounds there is no + -- interesting trailing behavior + , ( (coerceWord64ToDouble 0x440000000000301d) , "3.6893488147520004e19" ) + ] + , testMatches "d2sOutputLength" doubleDec show + [ ( 1 , "1.0" ) + , ( 1.2 , "1.2" ) + , ( 1.23 , "1.23" ) + , ( 1.234 , "1.234" ) + , ( 1.2345 , "1.2345" ) + , ( 1.23456 , "1.23456" ) + , ( 1.234567 , "1.234567" ) + , ( 1.2345678 , "1.2345678" ) + , ( 1.23456789 , "1.23456789" ) + , ( 1.234567895 , "1.234567895" ) + , ( 1.2345678901 , "1.2345678901" ) + , ( 1.23456789012 , "1.23456789012" ) + , ( 1.234567890123 , "1.234567890123" ) + , ( 1.2345678901234 , "1.2345678901234" ) + , ( 1.23456789012345 , "1.23456789012345" ) + , ( 1.234567890123456 , "1.234567890123456" ) + , ( 1.2345678901234567 , "1.2345678901234567" ) + + -- Test 32-bit chunking + , ( 4.294967294 , "4.294967294" ) + , ( 4.294967295 , "4.294967295" ) + , ( 4.294967296 , "4.294967296" ) + , ( 4.294967297 , "4.294967297" ) + , ( 4.294967298 , "4.294967298" ) + ] + , testMatches "d2sMinMaxShift" doubleDec show + [ ( (ieeeParts2Double False 4 0) , "1.7800590868057611e-307" ) + -- 32-bit opt-size=0: 49 <= dist <= 49 + -- 32-bit opt-size=1: 28 <= dist <= 49 + -- 64-bit opt-size=0: 50 <= dist <= 50 + -- 64-bit opt-size=1: 28 <= dist <= 50 + , ( (ieeeParts2Double False 6 maxMantissa) , "2.8480945388892175e-306" ) + -- 32-bit opt-size=0: 52 <= dist <= 53 + -- 32-bit opt-size=1: 2 <= dist <= 53 + -- 64-bit opt-size=0: 53 <= dist <= 53 + -- 64-bit opt-size=1: 2 <= dist <= 53 + , ( (ieeeParts2Double False 41 0) , "2.446494580089078e-296" ) + -- 32-bit opt-size=0: 52 <= dist <= 52 + -- 32-bit opt-size=1: 2 <= dist <= 52 + -- 64-bit opt-size=0: 53 <= dist <= 53 + -- 64-bit opt-size=1: 2 <= dist <= 53 + , ( (ieeeParts2Double False 40 maxMantissa) , "4.8929891601781557e-296" ) + -- 32-bit opt-size=0: 57 <= dist <= 58 + -- 32-bit opt-size=1: 57 <= dist <= 58 + -- 64-bit opt-size=0: 58 <= dist <= 58 + -- 64-bit opt-size=1: 58 <= dist <= 58 + , ( (ieeeParts2Double False 1077 0) , "1.8014398509481984e16" ) + -- 32-bit opt-size=0: 57 <= dist <= 57 + -- 32-bit opt-size=1: 57 <= dist <= 57 + -- 64-bit opt-size=0: 58 <= dist <= 58 + -- 64-bit opt-size=1: 58 <= dist <= 58 + , ( (ieeeParts2Double False 1076 maxMantissa) , "3.6028797018963964e16" ) + -- 32-bit opt-size=0: 51 <= dist <= 52 + -- 32-bit opt-size=1: 51 <= dist <= 59 + -- 64-bit opt-size=0: 52 <= dist <= 52 + -- 64-bit opt-size=1: 52 <= dist <= 59 + , ( (ieeeParts2Double False 307 0) , "2.900835519859558e-216" ) + -- 32-bit opt-size=0: 51 <= dist <= 51 + -- 32-bit opt-size=1: 51 <= dist <= 59 + -- 64-bit opt-size=0: 52 <= dist <= 52 + -- 64-bit opt-size=1: 52 <= dist <= 59 + , ( (ieeeParts2Double False 306 maxMantissa) , "5.801671039719115e-216" ) + -- 32-bit opt-size=0: 49 <= dist <= 49 + -- 32-bit opt-size=1: 44 <= dist <= 49 + -- 64-bit opt-size=0: 50 <= dist <= 50 + -- 64-bit opt-size=1: 44 <= dist <= 50 + , ( (ieeeParts2Double False 934 0x000FA7161A4D6e0C) , "3.196104012172126e-27" ) + ] + , testMatches "d2sSmallIntegers" doubleDec show + [ ( 9007199254740991.0 , "9.007199254740991e15" ) + , ( 9007199254740992.0 , "9.007199254740992e15" ) + + , ( 1.0e+0 , "1.0" ) + , ( 1.2e+1 , "12.0" ) + , ( 1.23e+2 , "123.0" ) + , ( 1.234e+3 , "1234.0" ) + , ( 1.2345e+4 , "12345.0" ) + , ( 1.23456e+5 , "123456.0" ) + , ( 1.234567e+6 , "1234567.0" ) + , ( 1.2345678e+7 , "1.2345678e7" ) + , ( 1.23456789e+8 , "1.23456789e8" ) + , ( 1.23456789e+9 , "1.23456789e9" ) + , ( 1.234567895e+9 , "1.234567895e9" ) + , ( 1.2345678901e+10 , "1.2345678901e10" ) + , ( 1.23456789012e+11 , "1.23456789012e11" ) + , ( 1.234567890123e+12 , "1.234567890123e12" ) + , ( 1.2345678901234e+13 , "1.2345678901234e13" ) + , ( 1.23456789012345e+14 , "1.23456789012345e14" ) + , ( 1.234567890123456e+15 , "1.234567890123456e15" ) + + -- 10^i + , ( 1.0e+0 , "1.0" ) + , ( 1.0e+1 , "10.0" ) + , ( 1.0e+2 , "100.0" ) + , ( 1.0e+3 , "1000.0" ) + , ( 1.0e+4 , "10000.0" ) + , ( 1.0e+5 , "100000.0" ) + , ( 1.0e+6 , "1000000.0" ) + , ( 1.0e+7 , "1.0e7" ) + , ( 1.0e+8 , "1.0e8" ) + , ( 1.0e+9 , "1.0e9" ) + , ( 1.0e+10 , "1.0e10" ) + , ( 1.0e+11 , "1.0e11" ) + , ( 1.0e+12 , "1.0e12" ) + , ( 1.0e+13 , "1.0e13" ) + , ( 1.0e+14 , "1.0e14" ) + , ( 1.0e+15 , "1.0e15" ) + + -- 10^15 + 10^i + , ( (1.0e+15 + 1.0e+0) , "1.000000000000001e15" ) + , ( (1.0e+15 + 1.0e+1) , "1.00000000000001e15" ) + , ( (1.0e+15 + 1.0e+2) , "1.0000000000001e15" ) + , ( (1.0e+15 + 1.0e+3) , "1.000000000001e15" ) + , ( (1.0e+15 + 1.0e+4) , "1.00000000001e15" ) + , ( (1.0e+15 + 1.0e+5) , "1.0000000001e15" ) + , ( (1.0e+15 + 1.0e+6) , "1.000000001e15" ) + , ( (1.0e+15 + 1.0e+7) , "1.00000001e15" ) + , ( (1.0e+15 + 1.0e+8) , "1.0000001e15" ) + , ( (1.0e+15 + 1.0e+9) , "1.000001e15" ) + , ( (1.0e+15 + 1.0e+10) , "1.00001e15" ) + , ( (1.0e+15 + 1.0e+11) , "1.0001e15" ) + , ( (1.0e+15 + 1.0e+12) , "1.001e15" ) + , ( (1.0e+15 + 1.0e+13) , "1.01e15" ) + , ( (1.0e+15 + 1.0e+14) , "1.1e15" ) + + -- Largest power of 2 <= 10^(i+1) + , ( 8.0 , "8.0" ) + , ( 64.0 , "64.0" ) + , ( 512.0 , "512.0" ) + , ( 8192.0 , "8192.0" ) + , ( 65536.0 , "65536.0" ) + , ( 524288.0 , "524288.0" ) + , ( 8388608.0 , "8388608.0" ) + , ( 67108864.0 , "6.7108864e7" ) + , ( 536870912.0 , "5.36870912e8" ) + , ( 8589934592.0 , "8.589934592e9" ) + , ( 68719476736.0 , "6.8719476736e10" ) + , ( 549755813888.0 , "5.49755813888e11" ) + , ( 8796093022208.0 , "8.796093022208e12" ) + , ( 70368744177664.0 , "7.0368744177664e13" ) + , ( 562949953421312.0 , "5.62949953421312e14" ) + , ( 9007199254740992.0 , "9.007199254740992e15" ) + + -- 1000 * (Largest power of 2 <= 10^(i+1)) + , ( 8.0e+3 , "8000.0" ) + , ( 64.0e+3 , "64000.0" ) + , ( 512.0e+3 , "512000.0" ) + , ( 8192.0e+3 , "8192000.0" ) + , ( 65536.0e+3 , "6.5536e7" ) + , ( 524288.0e+3 , "5.24288e8" ) + , ( 8388608.0e+3 , "8.388608e9" ) + , ( 67108864.0e+3 , "6.7108864e10" ) + , ( 536870912.0e+3 , "5.36870912e11" ) + , ( 8589934592.0e+3 , "8.589934592e12" ) + , ( 68719476736.0e+3 , "6.8719476736e13" ) + , ( 549755813888.0e+3 , "5.49755813888e14" ) + , ( 8796093022208.0e+3 , "8.796093022208e15" ) + ] + ] , testMatches "f2sPowersOf10" floatDec show $ fmap asShowRef [read ("1.0e" ++ show x) :: Float | x <- [-46..39 :: Int]] , testMatches "d2sPowersOf10" doubleDec show $ From 7bd06191b6822edf914da337646a317e288b3e24 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Jan 2024 22:00:23 -0500 Subject: [PATCH 07/18] differencated special values from basic values and Float from Double --- .../builder/Data/ByteString/Builder/Tests.hs | 59 ++++++++++--------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index 58d50e35..5b8b5155 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -641,18 +641,20 @@ testsASCII = where enlarge (n, e) = n ^ (abs (e `mod` (50 :: Integer))) -testsFloating :: [TestTree] +testsFloating :: TestTree testsFloating = testGroup "RealFloat" [ testGroup "Float" - [ testMatches "f2sBasic" floatDec show + [ testMatches "f2sNonNumbersAndZero" floatDec show [ ( 0.0 , "0.0" ) , ( (-0.0) , "-0.0" ) - , ( 1.0 , "1.0" ) - , ( (-1.0) , "-1.0" ) , ( (0/0) , "NaN" ) , ( (1/0) , "Infinity" ) , ( (-1/0) , "-Infinity" ) ] + , testMatches "f2sBasic" floatDec show + [ ( 1.0 , "1.0" ) + , ( (-1.0) , "-1.0" ) + ] , testMatches "f2sSubnormal" floatDec show [ ( 1.1754944e-38 , "1.1754944e-38" ) ] @@ -742,12 +744,14 @@ testsFloating = testGroup "RealFloat" , ( 1.23456735e-36 , "1.23456735e-36" ) ] ] - testGroup "Double" + , testGroup "Double" [ testMatches "d2sBasic" doubleDec show + [ ( 1.0 , "1.0" ) + , ( (-1.0) , "-1.0" ) + ] + , testMatches "f2sNonNumbersAndZero" doubleDec show [ ( 0.0 , "0.0" ) , ( (-0.0) , "-0.0" ) - , ( 1.0 , "1.0" ) - , ( (-1.0) , "-1.0" ) , ( (0/0) , "NaN" ) , ( (1/0) , "Infinity" ) , ( (-1/0) , "-Infinity" ) @@ -781,22 +785,23 @@ testsFloating = testGroup "RealFloat" , ( 4.294967294 , "4.294967294e0" ) , ( 4.294967295 , "4.294967295e0" ) ] - , testGroup "d2sStandard" - [ testCase "specific" do - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3 , "12.30" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3451 , "12.35" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0050 , "0.00" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.999 , "1000.00" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.199 , "999.20" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.999 , "1.00" ) - singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0051 , "0.01" ) - singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0056 , "0.006" ) - singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0096 , "0.010" ) - singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" ) - singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0 , "0.000" ) - , testProperty "standard N" \(NonNegative p, d :: Double) -> (LC.unpack . toLazyByteString) (formatDouble (standard p) d) === showFFloat (Just p) d "" - ] + , testGroup "d2sStandard" + [ testCase "specific" do + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3 , "12.30" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3451 , "12.35" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0050 , "0.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.999 , "1000.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 999.199 , "999.20" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.999 , "1.00" ) + singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 0.0051 , "0.01" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0056 , "0.006" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0096 , "0.010" ) + singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" ) + singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0 , "0.000" ) + , testProperty "standard N" \(NonNegative p, d :: Double) -> (LC.unpack . toLazyByteString) + (formatDouble (standard p) d) === showFFloat (Just p) d "" + ] , testMatches "d2sLooksLikePowerOf5" doubleDec show [ ( (coerceWord64ToDouble 0x4830F0CF064DD592) , "5.764607523034235e39" ) , ( (coerceWord64ToDouble 0x4840F0CF064DD592) , "1.152921504606847e40" ) @@ -966,11 +971,11 @@ testsFloating = testGroup "RealFloat" , ( 549755813888.0e+3 , "5.49755813888e14" ) , ( 8796093022208.0e+3 , "8.796093022208e15" ) ] + , testMatches "f2sPowersOf10" floatDec show $ + fmap asShowRef [read ("1.0e" ++ show x) :: Float | x <- [-46..39 :: Int]] + , testMatches "d2sPowersOf10" doubleDec show $ + fmap asShowRef [read ("1.0e" ++ show x) :: Double | x <- [-324..309 :: Int]] ] - , testMatches "f2sPowersOf10" floatDec show $ - fmap asShowRef [read ("1.0e" ++ show x) :: Float | x <- [-46..39 :: Int]] - , testMatches "d2sPowersOf10" doubleDec show $ - fmap asShowRef [read ("1.0e" ++ show x) :: Double | x <- [-324..309 :: Int]] ] where testExpected :: TestName -> (a -> Builder) -> [(a, String)] -> TestTree From 10e212f30254905ab36705dd76d71075dec91552 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Tue, 16 Jan 2024 07:32:50 -0500 Subject: [PATCH 08/18] put float test in the correct group --- tests/builder/Data/ByteString/Builder/Tests.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index 5b8b5155..f9f597fa 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -743,6 +743,8 @@ testsFloating = testGroup "RealFloat" , ( 1.2345678 , "1.2345678" ) , ( 1.23456735e-36 , "1.23456735e-36" ) ] + , testMatches "f2sPowersOf10" floatDec show $ + fmap asShowRef [read ("1.0e" ++ show x) :: Float | x <- [-46..39 :: Int]] ] , testGroup "Double" [ testMatches "d2sBasic" doubleDec show @@ -971,8 +973,6 @@ testsFloating = testGroup "RealFloat" , ( 549755813888.0e+3 , "5.49755813888e14" ) , ( 8796093022208.0e+3 , "8.796093022208e15" ) ] - , testMatches "f2sPowersOf10" floatDec show $ - fmap asShowRef [read ("1.0e" ++ show x) :: Float | x <- [-46..39 :: Int]] , testMatches "d2sPowersOf10" doubleDec show $ fmap asShowRef [read ("1.0e" ++ show x) :: Double | x <- [-324..309 :: Int]] ] From 6c72d0ba4b551f017e5fd7c83ea4db7869a8a0f6 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Apr 2024 15:23:29 -0400 Subject: [PATCH 09/18] spelling Co-authored-by: Matthew Craven --- bench/BenchAll.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 085d0cee..712ee748 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -450,7 +450,7 @@ main = do , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble standardDefaultPrecision) ] , bgroup "precision" - [ benchB "Float-Preciaion-1" floatPosData $ foldMap (formatFloat (standard 1)) + [ benchB "Float-Precision-1" floatPosData $ foldMap (formatFloat (standard 1)) , benchB "Double-Preciaion-1" doublePosData $ foldMap (formatDouble (standard 1)) , benchB "DoubleSmall-Preciaion-1" doublePosSmallData $ foldMap (formatDouble (standard 1)) , benchB "Float-Preciaion-6" floatPosData $ foldMap (formatFloat (standard 6)) From a4ca40f9cf335b81ccb8006efa09ede218ecde69 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Apr 2024 15:25:04 -0400 Subject: [PATCH 10/18] default precision Co-authored-by: Matthew Craven --- bench/BenchAll.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 712ee748..2be95f34 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -444,7 +444,7 @@ main = do ] , bgroup "FStandard" [ bgroup "Positive" - [ bgroup "without" + [ bgroup "default precision" [ benchB "Float" floatPosData $ foldMap (formatFloat standardDefaultPrecision) , benchB "Double" doublePosData $ foldMap (formatDouble standardDefaultPrecision) , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble standardDefaultPrecision) From 6d35a200786f4dfc5bf2e5635b272c1813b95544 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Apr 2024 15:25:25 -0400 Subject: [PATCH 11/18] default precision Co-authored-by: Matthew Craven --- bench/BenchAll.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 2be95f34..db00162c 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -459,7 +459,7 @@ main = do ] ] , bgroup "Negative" - [ bgroup "without" + [ bgroup "default precision" [ benchB "Float" floatNegData $ foldMap (formatFloat standardDefaultPrecision) , benchB "Double" doubleNegData $ foldMap (formatDouble standardDefaultPrecision) , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble standardDefaultPrecision) From 11b6ff1aa266589574282b7fefbb6e410ac81b8f Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Apr 2024 16:14:12 -0400 Subject: [PATCH 12/18] resolved some suggestions using non base casting functions floating point data does not depend on intData better generation of specials fixed DoubleSmall bench using the wrong test data --- bench/BenchAll.hs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index db00162c..3b572586 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -23,11 +23,7 @@ import qualified Data.List as List import Control.DeepSeq import Control.Exception import Numeric.IEEE -import GHC.Float (powerFloat, - castWord32ToFloat, - castWord64ToDouble, - castFloatToWord32, - castDoubleToWord64) +import System.IO.Unsafe (unsafePerformIO) import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8 @@ -64,6 +60,17 @@ countToZero :: Int -> Maybe (Int, Int) countToZero 0 = Nothing countToZero n = Just (n, n - 1) +castWord32ToFloat :: Word32 -> Float +castWord32ToFloat x = unsafePerformIO (with x (peek . castPtr)) + +castWord64ToDouble :: Word64 -> Double +castWord64ToDouble x = unsafePerformIO (with x (peek . castPtr)) + +castFloatToWord32 :: Float -> Word32 +castFloatToWord32 x = unsafePerformIO (with x (peek . castPtr)) + +castDoubleToWord64 :: Double -> Word64 +castDoubleToWord64 x = unsafePerformIO (with x (peek . castPtr)) ------------------------------------------------------------------------------ -- Benchmark @@ -90,7 +97,7 @@ largeIntegerData = map (* (10 ^ (100 :: Integer))) smallIntegerData {-# NOINLINE floatPosData #-} floatPosData :: [Float] -floatPosData = map evenlyDistribute intData +floatPosData = map evenlyDistribute [1..nRepl] where evenlyDistribute :: Int -> Float evenlyDistribute x = castWord32ToFloat $ increment * fromIntegral x @@ -102,13 +109,13 @@ floatNegData = map negate floatPosData {-# NOINLINE floatSpecials #-} floatSpecials :: [Float] -floatSpecials = foldMap (const specials) [1..nRepl `div` length specials] +floatSpecials = take nRepl $ cycle specials where specials = [nan, infinity, negate infinity, 0 -0] {-# NOINLINE doublePosData #-} doublePosData :: [Double] -doublePosData = map evenlyDistribute intData +doublePosData = map evenlyDistribute [1..nRepl] where evenlyDistribute :: Int -> Double evenlyDistribute x = castWord64ToDouble $ increment * fromIntegral x @@ -120,10 +127,9 @@ doublePosData = map evenlyDistribute intData doubleNegData :: [Double] doubleNegData = map negate doublePosData --- f is an integer in the range [1, 2^53). {-# NOINLINE doublePosSmallData #-} doublePosSmallData :: [Double] -doublePosSmallData = map evenlyDistribute intData +doublePosSmallData = map evenlyDistribute [1..nRepl] where evenlyDistribute = assert (increment > 0) $ \x -> castWord64ToDouble $ increment * fromIntegral x + minimum increment = (maximum - minimum) `div` fromIntegral nRepl @@ -136,7 +142,7 @@ doubleNegSmallData = map negate doublePosSmallData {-# NOINLINE doubleSpecials #-} doubleSpecials :: [Double] -doubleSpecials = foldMap (const specials) [1..nRepl `div` length specials] +doubleSpecials = take nRepl $ cycle specials where specials = [nan, infinity, negate infinity, 0 -0] @@ -417,9 +423,9 @@ main = do , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble generic) ] , bgroup "Negative" - [ benchB "Float" floatNegData $ foldMap (formatFloat generic) - , benchB "Double" doubleNegData $ foldMap (formatDouble generic) - , benchB "DoubleSmall" doubleNegData $ foldMap (formatDouble generic) + [ benchB "Float" floatNegData $ foldMap (formatFloat generic) + , benchB "Double" doubleNegData $ foldMap (formatDouble generic) + , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble generic) ] , bgroup "Special" [ benchB "Float Average" floatSpecials $ foldMap (formatFloat generic) From c900af5af1c01276484e9bdc60e2f178013647d9 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Tue, 21 May 2024 08:19:43 -0400 Subject: [PATCH 13/18] fix test name Co-authored-by: Matthew Craven --- tests/builder/Data/ByteString/Builder/Tests.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index f9f597fa..5dfe17fb 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -751,7 +751,7 @@ testsFloating = testGroup "RealFloat" [ ( 1.0 , "1.0" ) , ( (-1.0) , "-1.0" ) ] - , testMatches "f2sNonNumbersAndZero" doubleDec show + , testMatches "d2sNonNumbersAndZero" doubleDec show [ ( 0.0 , "0.0" ) , ( (-0.0) , "-0.0" ) , ( (0/0) , "NaN" ) From 0ddb33f5d52feebdfb8a8e1b111f73fa524fdc6a Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Tue, 21 May 2024 08:22:44 -0400 Subject: [PATCH 14/18] fixed Precision spelling error --- bench/BenchAll.hs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 3b572586..4756eae6 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -457,11 +457,11 @@ main = do ] , bgroup "precision" [ benchB "Float-Precision-1" floatPosData $ foldMap (formatFloat (standard 1)) - , benchB "Double-Preciaion-1" doublePosData $ foldMap (formatDouble (standard 1)) - , benchB "DoubleSmall-Preciaion-1" doublePosSmallData $ foldMap (formatDouble (standard 1)) - , benchB "Float-Preciaion-6" floatPosData $ foldMap (formatFloat (standard 6)) - , benchB "Double-Preciaion-6" doublePosData $ foldMap (formatDouble (standard 6)) - , benchB "DoubleSmall-Preciaion-6" doublePosSmallData $ foldMap (formatDouble (standard 6)) + , benchB "Double-Precision-1" doublePosData $ foldMap (formatDouble (standard 1)) + , benchB "DoubleSmall-Precision-1" doublePosSmallData $ foldMap (formatDouble (standard 1)) + , benchB "Float-Precision-6" floatPosData $ foldMap (formatFloat (standard 6)) + , benchB "Double-Precision-6" doublePosData $ foldMap (formatDouble (standard 6)) + , benchB "DoubleSmall-Precision-6" doublePosSmallData $ foldMap (formatDouble (standard 6)) ] ] , bgroup "Negative" @@ -471,12 +471,12 @@ main = do , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble standardDefaultPrecision) ] , bgroup "precision" - [ benchB "Float-Preciaion-1" floatNegData $ foldMap (formatFloat (standard 1)) - , benchB "Double-Preciaion-1" doubleNegData $ foldMap (formatDouble (standard 1)) - , benchB "DoubleSmall-Preciaion-1" doubleNegSmallData $ foldMap (formatDouble (standard 1)) - , benchB "Float-Preciaion-6" floatNegData $ foldMap (formatFloat (standard 6)) - , benchB "Double-Preciaion-6" doubleNegData $ foldMap (formatDouble (standard 6)) - , benchB "DoubleSmall-Preciaion-6" doubleNegSmallData $ foldMap (formatDouble (standard 6)) + [ benchB "Float-Precision-1" floatNegData $ foldMap (formatFloat (standard 1)) + , benchB "Double-Precision-1" doubleNegData $ foldMap (formatDouble (standard 1)) + , benchB "DoubleSmall-Precision-1" doubleNegSmallData $ foldMap (formatDouble (standard 1)) + , benchB "Float-Precision-6" floatNegData $ foldMap (formatFloat (standard 6)) + , benchB "Double-Precision-6" doubleNegData $ foldMap (formatDouble (standard 6)) + , benchB "DoubleSmall-Precision-6" doubleNegSmallData $ foldMap (formatDouble (standard 6)) ] ] , bgroup "Special" From d60ace9141f964f0559502860ea0920cbd3fb9f4 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Tue, 21 May 2024 13:26:51 -0400 Subject: [PATCH 15/18] separated subnormal and normal benchmarks, structured repetition --- bench/BenchAll.hs | 163 +++++++++++++++++++++------------------------- 1 file changed, 75 insertions(+), 88 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 4756eae6..2b672621 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -95,17 +95,22 @@ smallIntegerData = map fromIntegral intData largeIntegerData :: [Integer] largeIntegerData = map (* (10 ^ (100 :: Integer))) smallIntegerData -{-# NOINLINE floatPosData #-} -floatPosData :: [Float] -floatPosData = map evenlyDistribute [1..nRepl] +{-# NOINLINE floatSubnormalData #-} +floatSubnormalData :: [Float] +floatSubnormalData = assert (increment > 0) $ map evenlyDistribute [1..nRepl] where - evenlyDistribute :: Int -> Float evenlyDistribute x = castWord32ToFloat $ increment * fromIntegral x - increment = castFloatToWord32 maxFinite `div` fromIntegral nRepl + increment = castFloatToWord32 maxSubnormal `div` fromIntegral nRepl + maxSubnormal = predIEEE minNormal -{-# NOINLINE floatNegData #-} -floatNegData :: [Float] -floatNegData = map negate floatPosData +{-# NOINLINE floatNormalData #-} +floatNormalData :: [Float] +floatNormalData = assert (increment > 0) $ map evenlyDistribute [0..nRepl] + where + evenlyDistribute x = castWord32ToFloat $ increment * fromIntegral x + minimum + increment = (maximum - minimum) `div` fromIntegral nRepl + minimum = castFloatToWord32 minNormal + maximum = castFloatToWord32 maxFinite {-# NOINLINE floatSpecials #-} floatSpecials :: [Float] @@ -113,32 +118,31 @@ floatSpecials = take nRepl $ cycle specials where specials = [nan, infinity, negate infinity, 0 -0] -{-# NOINLINE doublePosData #-} -doublePosData :: [Double] -doublePosData = map evenlyDistribute [1..nRepl] +{-# NOINLINE doubleSubnormalData #-} +doubleSubnormalData :: [Double] +doubleSubnormalData = assert (increment > 0) $ map evenlyDistribute [1..nRepl] where - evenlyDistribute :: Int -> Double evenlyDistribute x = castWord64ToDouble $ increment * fromIntegral x - increment = (maximum - minimum) `div` fromIntegral nRepl - minimum = castDoubleToWord64 $ succIEEE $ 2 ^ 53 - maximum = castDoubleToWord64 maxFinite - -{-# NOINLINE doubleNegData #-} -doubleNegData :: [Double] -doubleNegData = map negate doublePosData + increment = castDoubleToWord64 maxSubnormal `div` fromIntegral nRepl + maxSubnormal = predIEEE minNormal -{-# NOINLINE doublePosSmallData #-} -doublePosSmallData :: [Double] -doublePosSmallData = map evenlyDistribute [1..nRepl] +{-# NOINLINE doubleSmallData #-} +doubleSmallData :: [Double] +doubleSmallData = assert (increment > 0) $ map evenlyDistribute [1..nRepl] where - evenlyDistribute = assert (increment > 0) $ \x -> castWord64ToDouble $ increment * fromIntegral x + minimum + evenlyDistribute x = castWord64ToDouble $ increment * fromIntegral x + minimum increment = (maximum - minimum) `div` fromIntegral nRepl minimum = castDoubleToWord64 1.0 maximum = castDoubleToWord64 $ 2 ^ 53 -{-# NOINLINE doubleNegSmallData #-} -doubleNegSmallData :: [Double] -doubleNegSmallData = map negate doublePosSmallData +{-# NOINLINE doubleBigData #-} +doubleBigData :: [Double] +doubleBigData = assert (increment > 0) $ map evenlyDistribute [1..nRepl] + where + evenlyDistribute x = castWord64ToDouble $ increment * fromIntegral x + minimum + increment = (maximum - minimum) `div` fromIntegral nRepl + minimum = castDoubleToWord64 $ 2 ^ 53 + maximum = castDoubleToWord64 maxFinite {-# NOINLINE doubleSpecials #-} doubleSpecials :: [Double] @@ -416,69 +420,11 @@ main = do , benchB "foldMap integerDec (small)" smallIntegerData $ foldMap integerDec , benchB "foldMap integerDec (large)" largeIntegerData $ foldMap integerDec , bgroup "RealFloat" - [ bgroup "FGeneric" - [ bgroup "Positive" - [ benchB "Float" floatPosData $ foldMap (formatFloat generic) - , benchB "Double" doublePosData $ foldMap (formatDouble generic) - , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble generic) - ] - , bgroup "Negative" - [ benchB "Float" floatNegData $ foldMap (formatFloat generic) - , benchB "Double" doubleNegData $ foldMap (formatDouble generic) - , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble generic) - ] - , bgroup "Special" - [ benchB "Float Average" floatSpecials $ foldMap (formatFloat generic) - , benchB "Double Average" doubleSpecials $ foldMap (formatDouble generic) - ] - ] - , bgroup "FScientific" - [ bgroup "Positive" - [ benchB "Float" floatPosData $ foldMap (formatFloat scientific) - , benchB "Double" doublePosData $ foldMap (formatDouble scientific) - , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble scientific) - ] - , bgroup "Negative" - [ benchB "Float" floatNegData $ foldMap (formatFloat scientific) - , benchB "Double" doubleNegData $ foldMap (formatDouble scientific) - , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble scientific) - ] - , bgroup "Special" - [ benchB "Float Average" floatSpecials $ foldMap (formatFloat scientific) - , benchB "Double Average" doubleSpecials $ foldMap (formatDouble scientific) - ] - ] + [ bgroup "FGeneric" $ subAndNormalBench generic + , bgroup "FScientific"$ subAndNormalBench scientific , bgroup "FStandard" - [ bgroup "Positive" - [ bgroup "default precision" - [ benchB "Float" floatPosData $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double" doublePosData $ foldMap (formatDouble standardDefaultPrecision) - , benchB "DoubleSmall" doublePosSmallData $ foldMap (formatDouble standardDefaultPrecision) - ] - , bgroup "precision" - [ benchB "Float-Precision-1" floatPosData $ foldMap (formatFloat (standard 1)) - , benchB "Double-Precision-1" doublePosData $ foldMap (formatDouble (standard 1)) - , benchB "DoubleSmall-Precision-1" doublePosSmallData $ foldMap (formatDouble (standard 1)) - , benchB "Float-Precision-6" floatPosData $ foldMap (formatFloat (standard 6)) - , benchB "Double-Precision-6" doublePosData $ foldMap (formatDouble (standard 6)) - , benchB "DoubleSmall-Precision-6" doublePosSmallData $ foldMap (formatDouble (standard 6)) - ] - ] - , bgroup "Negative" - [ bgroup "default precision" - [ benchB "Float" floatNegData $ foldMap (formatFloat standardDefaultPrecision) - , benchB "Double" doubleNegData $ foldMap (formatDouble standardDefaultPrecision) - , benchB "DoubleSmall" doubleNegSmallData $ foldMap (formatDouble standardDefaultPrecision) - ] - , bgroup "precision" - [ benchB "Float-Precision-1" floatNegData $ foldMap (formatFloat (standard 1)) - , benchB "Double-Precision-1" doubleNegData $ foldMap (formatDouble (standard 1)) - , benchB "DoubleSmall-Precision-1" doubleNegSmallData $ foldMap (formatDouble (standard 1)) - , benchB "Float-Precision-6" floatNegData $ foldMap (formatFloat (standard 6)) - , benchB "Double-Precision-6" doubleNegData $ foldMap (formatDouble (standard 6)) - , benchB "DoubleSmall-Precision-6" doubleNegSmallData $ foldMap (formatDouble (standard 6)) - ] - ] + [ bgroup "Positive" $ fixedPrecision id id + , bgroup "Negative" $ fixedPrecision negate negate , bgroup "Special" [ benchB "Float Average" floatSpecials $ foldMap (formatFloat standardDefaultPrecision) , benchB "Double Average" doubleSpecials $ foldMap (formatDouble standardDefaultPrecision) @@ -707,3 +653,44 @@ main = do , benchReadInt , benchShort ] + +subAndNormalBench format = + [ bgroup "Positive" $ benchs id id + , bgroup "Negative" $ benchs negate negate + , bgroup "Special" + [ benchB "Float Average" floatSpecials $ foldMap (formatFloat format) + , benchB "Double Average" doubleSpecials $ foldMap (formatDouble format) + ] + ] + where + benchs f d = + [ bgroup "Float" + [ benchB "Subnormal" (map f floatSubnormalData) $ foldMap $ formatFloat format + , benchB "Normal" (map f floatNormalData) $ foldMap $ formatFloat format + ] + , bgroup "Double" + [ benchB "Subnormal" (map d doubleSubnormalData) $ foldMap $ formatDouble format + , benchB "Small" (map d doubleSmallData) $ foldMap $ formatDouble format + , benchB "Big" (map d doubleBigData) $ foldMap $ formatDouble format + ] + ] + +fixedPrecision f d = + [ bgroup "default precision" + [ bgroup "Float" + [ benchB "Subnormal" (map f floatSubnormalData) $ foldMap $ formatFloat standardDefaultPrecision + , benchB "Normal" (map f floatNormalData) $ foldMap $ formatFloat standardDefaultPrecision + ] + , bgroup "Double" + [ benchB "Subnormal" (map d doubleSubnormalData) $ foldMap $ formatDouble standardDefaultPrecision + , benchB "Small" (map d doubleSmallData) $ foldMap $ formatDouble standardDefaultPrecision + , benchB "Big" (map d doubleBigData) $ foldMap $ formatDouble standardDefaultPrecision + ] + ] + , bgroup "precision" + [ benchB "Float-Precision-1" (map f floatNormalData) $ foldMap $ formatFloat $ standard 1 + , benchB "Double-Precision-1" (map d doubleSmallData) $ foldMap $ formatDouble $ standard 1 + , benchB "Float-Precision-6" (map f floatNormalData) $ foldMap $ formatFloat $ standard 6 + , benchB "Double-Precision-6" (map d doubleSmallData) $ foldMap $ formatDouble $ standard 6 + ] + ] From 7865d42a671eb413c4e864a9d47251b7337e09b0 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Wed, 5 Jun 2024 13:40:27 -0400 Subject: [PATCH 16/18] reduced number of benchmark runs, added expect failure for failing tests --- bench/BenchAll.hs | 2 +- bytestring.cabal | 1 + tests/builder/Data/ByteString/Builder/Tests.hs | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/bench/BenchAll.hs b/bench/BenchAll.hs index 2b672621..6fba4ba7 100644 --- a/bench/BenchAll.hs +++ b/bench/BenchAll.hs @@ -81,7 +81,7 @@ castDoubleToWord64 x = unsafePerformIO (with x (peek . castPtr)) -- | Few-enough repetitions to avoid making GC too expensive. nRepl :: Int -nRepl = 100000 +nRepl = 10000 {-# NOINLINE intData #-} intData :: [Int] diff --git a/bytestring.cabal b/bytestring.cabal index bd006dc2..c30d68d8 100644 --- a/bytestring.cabal +++ b/bytestring.cabal @@ -214,6 +214,7 @@ test-suite bytestring-tests deepseq, QuickCheck, tasty, + tasty-expected-failure, tasty-hunit, tasty-quickcheck >= 0.8.1, template-haskell, diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index 5dfe17fb..3a826ac0 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -50,12 +50,13 @@ import Numeric (showFFloat) import System.Posix.Internals (c_unlink) import Test.Tasty (TestTree, TestName, testGroup) +import Test.Tasty.ExpectedFailure (expectFailBecause) import Test.Tasty.HUnit (testCase, (@?=), Assertion) import Test.Tasty.QuickCheck ( Arbitrary(..), oneof, choose, listOf, elements , counterexample, ioProperty, Property, testProperty , (===), (.&&.), conjoin, forAll, forAllShrink - , UnicodeString(..), NonNegative(..), Positive(..) + , UnicodeString(..), NonNegative(..), Positive(..), NonZero(..) , mapSize, (==>) ) import QuickCheckUtils @@ -800,8 +801,11 @@ testsFloating = testGroup "RealFloat" singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0056 , "0.006" ) singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0096 , "0.010" ) singleMatches (formatDouble (standard 5)) (flip (showFFloat (Just 5)) []) ( 12.345 , "12.34500" ) + , expectFailBecause "incorrect implementation for the zero case" $ + testCase "specific zero" $ singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0 , "0.000" ) - , testProperty "standard N" \(NonNegative p, d :: Double) -> (LC.unpack . toLazyByteString) + -- NonZero should be removed when zero case fixed + , testProperty "standard N" \(NonNegative p, NonZero (d :: Double)) -> (LC.unpack . toLazyByteString) (formatDouble (standard p) d) === showFFloat (Just p) d "" ] , testMatches "d2sLooksLikePowerOf5" doubleDec show From 2a2cdc4e41427d22fc1e35c10c7a23ab4740f079 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Thu, 27 Jun 2024 10:42:50 -0400 Subject: [PATCH 17/18] removed block arguments --- tests/builder/Data/ByteString/Builder/Tests.hs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/builder/Data/ByteString/Builder/Tests.hs b/tests/builder/Data/ByteString/Builder/Tests.hs index 3a826ac0..47d68533 100644 --- a/tests/builder/Data/ByteString/Builder/Tests.hs +++ b/tests/builder/Data/ByteString/Builder/Tests.hs @@ -1,4 +1,3 @@ -{-# LANGUAGE BlockArguments #-} {-# LANGUAGE ScopedTypeVariables #-} {-# OPTIONS_GHC -fno-warn-orphans #-} @@ -789,7 +788,7 @@ testsFloating = testGroup "RealFloat" , ( 4.294967295 , "4.294967295e0" ) ] , testGroup "d2sStandard" - [ testCase "specific" do + [ testCase "specific" $ do singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3 , "12.30" ) singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.345 , "12.34" ) singleMatches (formatDouble (standard 2)) (flip (showFFloat (Just 2)) []) ( 12.3451 , "12.35" ) @@ -805,7 +804,7 @@ testsFloating = testGroup "RealFloat" testCase "specific zero" $ singleMatches (formatDouble (standard 3)) (flip (showFFloat (Just 3)) []) ( 0.0 , "0.000" ) -- NonZero should be removed when zero case fixed - , testProperty "standard N" \(NonNegative p, NonZero (d :: Double)) -> (LC.unpack . toLazyByteString) + , testProperty "standard N" $ \(NonNegative p, NonZero (d :: Double)) -> (LC.unpack . toLazyByteString) (formatDouble (standard p) d) === showFFloat (Just p) d "" ] , testMatches "d2sLooksLikePowerOf5" doubleDec show @@ -983,7 +982,7 @@ testsFloating = testGroup "RealFloat" ] where testExpected :: TestName -> (a -> Builder) -> [(a, String)] -> TestTree - testExpected name dec = testCase name . traverse_ \(x, ref) -> LC.unpack (toLazyByteString (dec x)) @?= ref + testExpected name dec = testCase name . traverse_ (\(x, ref) -> LC.unpack (toLazyByteString (dec x)) @?= ref) singleMatches :: (a -> Builder) -> (a -> String) -> (a, String) -> Assertion singleMatches dec refdec (x, ref) = do From 1cbe24d40db2a60542491d79cf7d06676ad9ca12 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Mon, 22 Jul 2024 10:52:58 -0400 Subject: [PATCH 18/18] add new test dependencies to ci emulated installs --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15985bfd..ac5909cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -135,7 +135,7 @@ jobs: githubToken: ${{ github.token }} install: | apt-get update -y - apt-get install -y curl ghc libghc-tasty-quickcheck-dev libghc-syb-dev + apt-get install -y curl ghc libghc-tasty-quickcheck-dev libghc-tasty-hunit-dev libghc-tasty-expected-failure-dev libghc-syb-dev run: | curl -s https://hackage.haskell.org/package/data-array-byte-0.1/data-array-byte-0.1.tar.gz | tar xz ghc --version