Commits

Bryan O'Sullivan committed 709f19b

Allow more control over floating point rendering.

Comments (0)

Files changed (7)

Data/Text/Buildable.hs

 import Data.Ratio (Ratio, denominator, numerator)
 import Data.Text.Format.Functions ((<>))
 import Data.Text.Format.Int (integral)
-import Data.Text.Format.RealFloat (showFloat)
-import Data.Text.Format.RealFloat.Fast (fshowFloat)
+import Data.Text.Format.RealFloat (formatRealFloat, showFloat)
+import Data.Text.Format.RealFloat.Fast (DispFloat, formatFloat, fshowFloat)
 import Data.Text.Format.Types (Fast(..), Shown(..))
+import Data.Text.Format.Types.Internal (FPControl(..))
 import Data.Text.Lazy.Builder
 import Data.Time.Calendar (Day, showGregorian)
 import Data.Time.Clock (DiffTime, NominalDiffTime, UTCTime, UniversalTime)
     build = showFloat
     {-# INLINE build #-}
 
-instance Buildable (Fast Float) where
+instance (RealFloat a) => Buildable (FPControl a) where
+    build (FPControl fmt decs x) = formatRealFloat fmt decs x
+    {-# INLINE build #-}
+
+instance (RealFloat a, DispFloat a) => Buildable (Fast a) where
     build = fshowFloat . fromFast
     {-# INLINE build #-}
 
-instance Buildable (Fast Double) where
-    build = fshowFloat . fromFast
+instance (RealFloat a, DispFloat a) => Buildable (Fast (FPControl a)) where
+    build (Fast (FPControl fmt decs x)) = formatFloat fmt decs x
     {-# INLINE build #-}
 
 instance Buildable DiffTime where

Data/Text/Format.hs

     -- ** Types for format control
     , Fast(..)
     , Shown(..)
-    -- * Functions
-    -- ** Rendering
+    -- * Rendering
     , format
     , print
     , hprint
     , build
-    -- ** Functions for format control
+    -- * Format control
     , left
     , right
+    -- ** Floating point numbers
+    , expt
+    , expt_
+    , fixed
+    , fixed_
     ) where
 
 import qualified Data.Text.Buildable as B
 import Data.Text.Format.Params (Params(..))
 import Data.Text.Format.Functions ((<>))
-import Data.Text.Format.Types.Internal (Fast(..), Format(..), Only(..), Shown(..))
+import Data.Text.Format.Types.Internal (FPControl(..), FPFormat(..), Fast(..))
+import Data.Text.Format.Types.Internal (Format(..), Only(..), Shown(..))
 import Data.Text.Lazy.Builder
-import Prelude hiding (print)
+import Prelude hiding (exp, print)
 import System.IO (Handle)
 import qualified Data.Text as ST
 import qualified Data.Text.Lazy as LT
 hprint h fmt ps = LT.hPutStr h . toLazyText $ build fmt ps
 
 -- | Pad the left hand side of a string until it reaches @k@
--- characters wide, filling with character @c@.
+-- characters wide, if necessary filling with character @c@.
 left :: B.Buildable a => Int -> Char -> a -> Builder
 left k c =
     fromLazyText . LT.justifyLeft (fromIntegral k) c . toLazyText . B.build
 
 -- | Pad the right hand side of a string until it reaches @k@
--- characters wide, filling with character @c@.
+-- characters wide, if necessary filling with character @c@.
 right :: B.Buildable a => Int -> Char -> a -> Builder
 right k c =
     fromLazyText . LT.justifyRight (fromIntegral k) c . toLazyText . B.build
+
+-- ^ Render a floating point number using normal notation, with the
+-- given number of decimal places.
+fixed :: (B.Buildable a, RealFloat a) =>
+         Int
+      -- ^ Number of digits of precision after the decimal.
+      -> a -> Builder
+fixed decs = B.build . FPControl Fixed (Just decs)
+
+-- ^ Render a floating point number using normal notation.
+fixed_ :: (B.Buildable a, RealFloat a) => -> a -> Builder
+fixed_ = B.build . FPControl Fixed Nothing
+
+-- ^ Render a floating point number using scientific/engineering
+-- notation (e.g. @2.3e123@), with the given number of decimal places.
+expt :: (B.Buildable a, RealFloat a) =>
+        Int
+     -- ^ Number of digits of precision after the decimal.
+     -> a -> Builder
+expt decs = B.build . FPControl Exponent (Just decs)
+
+-- ^ Render a floating point number using scientific/engineering
+-- notation (e.g. @2.3e123@).
+expt_ :: (B.Buildable a, RealFloat a) => -> a -> Builder
+expt_ decs = B.build . FPControl Exponent Nothing

Data/Text/Format/Int.hs

 
 module Data.Text.Format.Int
     (
-      digit
-    , integral
+      integral
     , minus
     ) where
 
          | otherwise = go (n `quot` 10) <> digit (n `rem` 10)
 
 digit :: Integral a => a -> Builder
-digit n = singleton $! i2d (fromIntegral n + 48)
+digit n = singleton $! i2d (fromIntegral n)
 {-# INLINE digit #-}
 
 minus :: Builder

Data/Text/Format/RealFloat.hs

 
 module Data.Text.Format.RealFloat
     (
-      showFloat
+      formatRealFloat
+    , showFloat
     ) where
 
 import Data.Text.Format.Functions ((<>), i2d)

Data/Text/Format/RealFloat/Fast.hs

     , fshowEFloat
     , fshowFFloat
     , fshowGFloat
+    , formatFloat
     ) where
 
 import Data.Text.Format.Functions ((<>), i2d)

Data/Text/Format/Types.hs

 module Data.Text.Format.Types
     (
       Format
-    , Fast(..)
     , Only(..)
     , Shown(..)
+    -- * Floating point format control
+    , FPControl
+    , Fast(..)
+    , DispFloat
     ) where
 
 import Data.Text.Format.Types.Internal
+import Data.Text.Format.RealFloat.Fast (DispFloat)

Data/Text/Format/Types/Internal.hs

 module Data.Text.Format.Types.Internal
     (
       Format(..)
-    , FPFormat(..)
-    , Fast(..)
     , Only(..)
     , Shown(..)
+    -- * Floating point format control
+    , Fast(..)
+    , FPControl(..)
+    , FPFormat(..)
     ) where
 
 import Data.Monoid (Monoid(..))
               -- @9,999,999@, and scientific notation otherwise.
                 deriving (Enum, Read, Show)
 
+-- | A floating point number, complete with rendering instructions.
+data FPControl a = FPControl FPFormat (Maybe Int) a
+
 -- | Render a floating point number using a much faster algorithm than
 -- the default (up to 10x faster). This performance comes with a
 -- potential cost in readability, as the faster algorithm can produce