diff --git a/Data/ByteString/Builder/RealFloat.hs b/Data/ByteString/Builder/RealFloat.hs index 1fef16a0..cc5842a0 100644 --- a/Data/ByteString/Builder/RealFloat.hs +++ b/Data/ByteString/Builder/RealFloat.hs @@ -70,11 +70,12 @@ module Data.ByteString.Builder.RealFloat , generic ) where -import Data.ByteString.Builder.Internal (Builder) +import Data.ByteString.Builder.Internal (Builder, shortByteString) import qualified Data.ByteString.Builder.RealFloat.Internal as R 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) @@ -253,19 +254,29 @@ 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. +-- 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` string7 (replicate (-e) '0') - `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) + <> buildDigits m + | e >= olength + -> buildDigits m + <> zeros (e - olength) + <> string7 ".0" + | otherwise -> let + wholeDigits = m `div` (10 ^ (olength - e)) + fractDigits = m `mod` (10 ^ (olength - e)) + in buildDigits wholeDigits + <> char7 '.' + <> zeros (olength - e - R.decimalLength17 fractDigits) + <> buildDigits fractDigits Just p | e >= 0 -> let (ei, is') = roundTo 10 (p' + e) ds @@ -285,3 +296,6 @@ showStandard m e prec = ds = digits m digitsToBuilder = fmap (char7 . intToDigit) + zeros n = shortByteString $ BS.take n $ BS.replicate 308 48 + olength = R.decimalLength17 m + buildDigits = BP.primBounded BP.word64Dec