|
9 | 9 | {-# LANGUAGE TypeApplications #-} |
10 | 10 | {-# LANGUAGE AllowAmbiguousTypes #-} |
11 | 11 | {-# LANGUAGE BlockArguments #-} |
| 12 | +{-# LANGUAGE NamedFieldPuns #-} |
| 13 | +{-# LANGUAGE NoFieldSelectors #-} |
| 14 | +{-# LANGUAGE DuplicateRecordFields #-} |
12 | 15 | -- | |
13 | 16 | -- Module : Data.ByteString.Builder.RealFloat.Internal |
14 | 17 | -- Copyright : (c) Lawrence Wu 2021 |
@@ -83,6 +86,9 @@ module Data.ByteString.Builder.RealFloat.Internal |
83 | 86 | , CastToWord(..) |
84 | 87 | , ToInt(..) |
85 | 88 | , FromInt(..) |
| 89 | + , FloatFormat(..) |
| 90 | + , fScientific |
| 91 | + , fGeneric |
86 | 92 |
|
87 | 93 | , module Data.ByteString.Builder.RealFloat.TableGenerator |
88 | 94 | ) where |
@@ -656,43 +662,44 @@ data BoundsState a = BoundsState |
656 | 662 | trimTrailing :: Mantissa a => BoundsState a -> (BoundsState a, Int32) |
657 | 663 | trimTrailing !initial = (res, r + r') |
658 | 664 | where |
659 | | - !(d', r) = trimTrailing' initial |
660 | | - !(d'', r') = if vuIsTrailingZeros d' then trimTrailing'' d' else (d', 0) |
661 | | - res = if vvIsTrailingZeros d'' && lastRemovedDigit d'' == 5 && vv d'' `rem` 2 == 0 |
| 665 | + !(d'@BoundsState{vuIsTrailingZeros = vuIsTrailingZeros'}, r) = trimTrailing' initial |
| 666 | + !(d''@BoundsState{vvIsTrailingZeros = vvIsTrailingZeros'', lastRemovedDigit = lastRemovedDigit'', vv = vv''}, r') = |
| 667 | + if vuIsTrailingZeros' then trimTrailing'' d' else (d', 0) |
| 668 | + res = if vvIsTrailingZeros'' && lastRemovedDigit'' == 5 && vv'' `rem` 2 == 0 |
662 | 669 | -- set `{ lastRemovedDigit = 4 }` to round-even |
663 | 670 | then d'' |
664 | 671 | else d'' |
665 | 672 |
|
666 | | - trimTrailing' !d |
| 673 | + trimTrailing' !d@BoundsState{..} |
667 | 674 | | vw' > vu' = |
668 | 675 | fmap ((+) 1) . trimTrailing' $ |
669 | 676 | d { vu = vu' |
670 | 677 | , vv = vv' |
671 | 678 | , vw = vw' |
672 | 679 | , lastRemovedDigit = vvRem |
673 | | - , vuIsTrailingZeros = vuIsTrailingZeros d && vuRem == 0 |
674 | | - , vvIsTrailingZeros = vvIsTrailingZeros d && lastRemovedDigit d == 0 |
| 680 | + , vuIsTrailingZeros = vuIsTrailingZeros && vuRem == 0 |
| 681 | + , vvIsTrailingZeros = vvIsTrailingZeros && lastRemovedDigit == 0 |
675 | 682 | } |
676 | 683 | | otherwise = (d, 0) |
677 | 684 | where |
678 | | - !(vv', vvRem) = quotRem10 $ vv d |
679 | | - !(vu', vuRem) = quotRem10 $ vu d |
680 | | - !(vw', _ ) = quotRem10 $ vw d |
| 685 | + !(vv', vvRem) = quotRem10 vv |
| 686 | + !(vu', vuRem) = quotRem10 vu |
| 687 | + !(vw', _ ) = quotRem10 vw |
681 | 688 |
|
682 | | - trimTrailing'' !d |
| 689 | + trimTrailing'' !d@BoundsState{..} |
683 | 690 | | vuRem == 0 = |
684 | 691 | fmap ((+) 1) . trimTrailing'' $ |
685 | 692 | d { vu = vu' |
686 | 693 | , vv = vv' |
687 | 694 | , vw = vw' |
688 | 695 | , lastRemovedDigit = vvRem |
689 | | - , vvIsTrailingZeros = vvIsTrailingZeros d && lastRemovedDigit d == 0 |
| 696 | + , vvIsTrailingZeros = vvIsTrailingZeros && lastRemovedDigit == 0 |
690 | 697 | } |
691 | 698 | | otherwise = (d, 0) |
692 | 699 | where |
693 | | - !(vu', vuRem) = quotRem10 $ vu d |
694 | | - !(vv', vvRem) = quotRem10 $ vv d |
695 | | - !(vw', _ ) = quotRem10 $ vw d |
| 700 | + !(vu', vuRem) = quotRem10 vu |
| 701 | + !(vv', vvRem) = quotRem10 vv |
| 702 | + !(vw', _ ) = quotRem10 vw |
696 | 703 |
|
697 | 704 |
|
698 | 705 | -- | Trim digits and update bookkeeping state when the table-computed |
@@ -731,10 +738,10 @@ trimNoTrailing !(BoundsState u v w ld _ _) = |
731 | 738 | -- bounds |
732 | 739 | {-# INLINE closestCorrectlyRounded #-} |
733 | 740 | closestCorrectlyRounded :: Mantissa a => Bool -> BoundsState a -> a |
734 | | -closestCorrectlyRounded acceptBound s = vv s + boolToWord roundUp |
| 741 | +closestCorrectlyRounded acceptBound BoundsState{..} = vv + boolToWord roundUp |
735 | 742 | where |
736 | | - outsideBounds = not (vuIsTrailingZeros s) || not acceptBound |
737 | | - roundUp = (vv s == vu s && outsideBounds) || lastRemovedDigit s >= 5 |
| 743 | + outsideBounds = not vuIsTrailingZeros || not acceptBound |
| 744 | + roundUp = (vv == vu && outsideBounds) || lastRemovedDigit >= 5 |
738 | 745 |
|
739 | 746 | -- Wrappe around int2Word# |
740 | 747 | asciiRaw :: Int -> Word8# |
@@ -972,3 +979,36 @@ instance MantissaBits Double where mantissaBits = 52 |
972 | 979 | class ExponentBits a where exponentBits :: Int |
973 | 980 | instance ExponentBits Float where exponentBits = 8 |
974 | 981 | instance ExponentBits Double where exponentBits = 11 |
| 982 | + |
| 983 | +-- | Format type for use with `formatFloat` and `formatDouble`. |
| 984 | +-- |
| 985 | +-- @since 0.11.2.0 |
| 986 | +data FloatFormat |
| 987 | + -- | scientific notation |
| 988 | + = FScientific |
| 989 | + { eE :: Word8# |
| 990 | + , specials :: SpecialStrings |
| 991 | + } |
| 992 | + -- | standard notation with `Maybe Int` digits after the decimal |
| 993 | + | FStandard |
| 994 | + { precision :: Maybe Int |
| 995 | + , specials :: SpecialStrings |
| 996 | + } |
| 997 | + -- | dispatches to scientific or standard notation based on the exponent |
| 998 | + | FGeneric |
| 999 | + { eE :: Word8# |
| 1000 | + , precision :: Maybe Int |
| 1001 | + , stdExpoRange :: (Int, Int) |
| 1002 | + , specials :: SpecialStrings |
| 1003 | + } |
| 1004 | + deriving Show |
| 1005 | +fScientific :: Char -> SpecialStrings -> FloatFormat |
| 1006 | +fScientific eE specials = FScientific |
| 1007 | + { eE = asciiRaw $ ord eE |
| 1008 | + , specials |
| 1009 | + } |
| 1010 | +fGeneric :: Char -> Maybe Int -> (Int, Int) -> SpecialStrings -> FloatFormat |
| 1011 | +fGeneric eE precision stdExpoRange specials = FGeneric |
| 1012 | + { eE = asciiRaw $ ord eE |
| 1013 | + , .. |
| 1014 | + } |
0 commit comments