From 9086882d96990db5a0a296ac673fa6da08c2ee0c Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Jan 2024 22:08:49 -0500 Subject: [PATCH 1/4] use preallocated bytestring of zeros instead of a String of zeros --- Data/ByteString/Builder/RealFloat.hs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Data/ByteString/Builder/RealFloat.hs b/Data/ByteString/Builder/RealFloat.hs index 1fef16a0b..4cbbeaa9b 100644 --- a/Data/ByteString/Builder/RealFloat.hs +++ b/Data/ByteString/Builder/RealFloat.hs @@ -70,8 +70,9 @@ module Data.ByteString.Builder.RealFloat , generic ) where -import Data.ByteString.Builder.Internal (Builder) +import Data.ByteString.Builder.Internal (Builder, byteString) import qualified Data.ByteString.Builder.RealFloat.Internal as R +import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Builder.RealFloat.F2S as RF import qualified Data.ByteString.Builder.RealFloat.D2S as RD import qualified Data.ByteString.Builder.Prim as BP @@ -259,7 +260,7 @@ showStandard m e prec = Nothing | e <= 0 -> char7 '0' `mappend` char7 '.' - `mappend` string7 (replicate (-e) '0') + `mappend` zeros (-e) `mappend` mconcat (digitsToBuilder ds) | otherwise -> let f 0 s rs = mk0 (reverse s) `mappend` char7 '.' `mappend` mk0 rs @@ -284,4 +285,4 @@ showStandard m e prec = mkDot rs = if null rs then mempty else char7 '.' `mappend` mconcat rs ds = digits m digitsToBuilder = fmap (char7 . intToDigit) - + zeros n = byteString $ BC.take n $ BC.replicate 308 '0' From 5ed732e4378ae8af1aedb869d3de90de0e4dd720 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Sun, 14 Jan 2024 22:14:58 -0500 Subject: [PATCH 2/4] added TODO for improving showStandard --- Data/ByteString/Builder/RealFloat.hs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Data/ByteString/Builder/RealFloat.hs b/Data/ByteString/Builder/RealFloat.hs index 4cbbeaa9b..6d71b867c 100644 --- a/Data/ByteString/Builder/RealFloat.hs +++ b/Data/ByteString/Builder/RealFloat.hs @@ -254,6 +254,8 @@ digits w = go [] w in go ((R.word64ToInt r) : ds) q -- | Show a floating point value in standard notation. Based on GHC.Float.showFloat +-- TODO: Remove the use of String and lists because it makes this very slow compared +-- to the actual implementation of the Ryu algorithm. showStandard :: Word64 -> Int -> Maybe Int -> Builder showStandard m e prec = case prec of From a5e453e4f56facb11a854b80c9b019d9da0e363b Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Mon, 15 Jan 2024 11:54:07 -0500 Subject: [PATCH 3/4] removed String usage from the showStandard no precision --- Data/ByteString/Builder/RealFloat.hs | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Data/ByteString/Builder/RealFloat.hs b/Data/ByteString/Builder/RealFloat.hs index 6d71b867c..c31a1f06d 100644 --- a/Data/ByteString/Builder/RealFloat.hs +++ b/Data/ByteString/Builder/RealFloat.hs @@ -256,19 +256,27 @@ digits w = go [] w -- | Show a floating point value in standard notation. Based on GHC.Float.showFloat -- TODO: Remove the use of String and lists because it makes this very slow compared -- to the actual implementation of the Ryu algorithm. +-- TODO: The digits should be found with the look up method described in the Ryu +-- reference algorithm. showStandard :: Word64 -> Int -> Maybe Int -> Builder showStandard m e prec = case prec of Nothing - | e <= 0 -> char7 '0' - `mappend` char7 '.' - `mappend` zeros (-e) - `mappend` mconcat (digitsToBuilder ds) - | otherwise -> - let f 0 s rs = mk0 (reverse s) `mappend` char7 '.' `mappend` mk0 rs - f n s [] = f (n-1) (char7 '0':s) [] - f n s (r:rs) = f (n-1) (r:s) rs - in f e [] (digitsToBuilder ds) + | e <= 0 + -> string7 "0." + <> zeros (-e) + <> BP.primBounded BP.word64Dec m + | e >= olength + -> BP.primBounded BP.word64Dec m + <> zeros (e - olength) + <> string7 ".0" + | otherwise -> let + wholeDigits = m `div` (10 ^ (olength - e)) + fractDigits = m `mod` (10 ^ (olength - e)) + in BP.primBounded BP.word64Dec wholeDigits + <> char7 '.' + <> zeros (olength - e - R.decimalLength17 fractDigits) + <> BP.primBounded BP.word64Dec fractDigits Just p | e >= 0 -> let (ei, is') = roundTo 10 (p' + e) ds @@ -287,4 +295,6 @@ showStandard m e prec = mkDot rs = if null rs then mempty else char7 '.' `mappend` mconcat rs ds = digits m digitsToBuilder = fmap (char7 . intToDigit) + zeros n = byteString $ BC.take n $ BC.replicate 308 '0' + olength = R.decimalLength17 m From f6baa8ca36e60c2cba5632e854145eb2f1416206 Mon Sep 17 00:00:00 2001 From: William Rusnack Date: Mon, 15 Jan 2024 15:16:49 -0500 Subject: [PATCH 4/4] use ShortByteString to hold zeros and named 'primBBounded word64Dec' --- Data/ByteString/Builder/RealFloat.hs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Data/ByteString/Builder/RealFloat.hs b/Data/ByteString/Builder/RealFloat.hs index c31a1f06d..cc5842a0e 100644 --- a/Data/ByteString/Builder/RealFloat.hs +++ b/Data/ByteString/Builder/RealFloat.hs @@ -70,12 +70,12 @@ module Data.ByteString.Builder.RealFloat , generic ) where -import Data.ByteString.Builder.Internal (Builder, byteString) +import Data.ByteString.Builder.Internal (Builder, shortByteString) import qualified Data.ByteString.Builder.RealFloat.Internal as R -import qualified Data.ByteString.Char8 as BC import qualified Data.ByteString.Builder.RealFloat.F2S as RF import qualified Data.ByteString.Builder.RealFloat.D2S as RD import qualified Data.ByteString.Builder.Prim as BP +import qualified Data.ByteString.Short as BS import GHC.Float (roundTo) import GHC.Word (Word64) import GHC.Show (intToDigit) @@ -265,18 +265,18 @@ showStandard m e prec = | e <= 0 -> string7 "0." <> zeros (-e) - <> BP.primBounded BP.word64Dec m + <> buildDigits m | e >= olength - -> BP.primBounded BP.word64Dec m + -> buildDigits m <> zeros (e - olength) <> string7 ".0" | otherwise -> let wholeDigits = m `div` (10 ^ (olength - e)) fractDigits = m `mod` (10 ^ (olength - e)) - in BP.primBounded BP.word64Dec wholeDigits + in buildDigits wholeDigits <> char7 '.' <> zeros (olength - e - R.decimalLength17 fractDigits) - <> BP.primBounded BP.word64Dec fractDigits + <> buildDigits fractDigits Just p | e >= 0 -> let (ei, is') = roundTo 10 (p' + e) ds @@ -296,5 +296,6 @@ showStandard m e prec = ds = digits m digitsToBuilder = fmap (char7 . intToDigit) - zeros n = byteString $ BC.take n $ BC.replicate 308 '0' + zeros n = shortByteString $ BS.take n $ BS.replicate 308 48 olength = R.decimalLength17 m + buildDigits = BP.primBounded BP.word64Dec