{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RebindableSyntax #-}
{-# OPTIONS_GHC -Wall #-}
{-# OPTIONS_GHC -Wno-type-defaults #-}
module Readme.Format
( average,
deciles,
percentile,
fixed,
commas,
prec,
secs,
) where
import NumHask.Prelude
import Data.Scientific
import Data.TDigest
import qualified Data.Text as Text
average :: (Foldable f) => f Double -> Double
average xs = sum xs / fromIntegral (length xs)
deciles :: (Foldable f) => Int -> f Double -> [Double]
deciles n xs =
( \x ->
fromMaybe 0 $
quantile x (tdigest xs :: TDigest 25)
)
<$> ((/ fromIntegral n) . fromIntegral <$> [0 .. n])
percentile :: (Foldable f) => Double -> f Double -> Double
percentile p xs = fromMaybe 0 $ quantile p (tdigest xs :: TDigest 25)
fixed :: Int -> Double -> Text
fixed n x
| Text.length a == 0 = "0." <> (Text.replicate (n - Text.length b) "0") <> b
| Text.length b == 0 = a
| otherwise = a <> "." <> b
where
i = show (round (x * (10.0 ^ n)) :: Integer) :: Text
(a, b) = Text.splitAt (Text.length i - n) i
prec :: Int -> Double -> Text
prec p x = sciprec p (fromFloatDigits x)
commas :: Int -> Double -> Text
commas n a
| a < 0 = "-" <> commas n (- a)
| a < 1000.0 = fixed n a
| otherwise = intPart (floor a) "" <> decPart (a - fromInteger (floor a))
where
intPart :: Integer -> Text -> Text
intPart x t
| x < 1000 = Text.pack (show x) <> t
| otherwise =
let (d, m) = divMod x 1000
in intPart d ("," <> Text.pack (show m))
decPart :: Double -> Text
decPart x = Text.drop 1 $ fixed n x
sciprec :: Int -> Scientific -> Text
sciprec n x = Text.pack $ formatScientific Exponent (Just n) x
secs :: Int -> Double -> Text
secs p s
| s < 0.0 = "-" <> secs p (- s)
| s >= 1.0 = fixed p s <> "s"
| s >= 1e-3 = fixed 0 (s * 1e3) <> "ms"
| s >= 1e-6 = fixed 0 (s * 1e6) <> "μs"
| s >= 1e-9 = fixed 0 (s * 1e9) <> "ns"
| otherwise = fixed p (s * 1e12) <> "ps"