0 | module Data.ScientificNotation
28 | interface Num a => ScientificDisplay a where
30 | showSci : a -> String
45 | defaultScientificPrecision : Nat
46 | defaultScientificPrecision = 4
55 | needsScientific : Double -> Bool
56 | needsScientific d = d /= 0.0 && (m < sciLowerM || m >= sciUpperM)
67 | formatExp : Integer -> String
68 | formatExp n = singleton sciSymbol ++ sign ++ applyWhen (length ds < 2) ("0" ++) ds
70 | sign = if n < 0 then "-" else "+"
79 | roundScaled : (prec : Nat) -> Double -> Integer
80 | roundScaled prec d = cast (floor (abs d * pow 10.0 (cast prec) + 0.5))
93 | formatDigits : (prec : Nat) -> (digits : Integer) -> String
94 | formatDigits 0 n = show n
95 | formatDigits prec n = substr 0 nDig padded ++ "." ++ substr nDig prec padded
97 | len = length (show n)
99 | padded = applyWhen (len <= prec)
100 | (pack (replicate (S prec `minus` len) '0') ++)
103 | nDig = length padded `minus` prec
115 | showDoublePrecision : (precision : Nat) -> Double -> String
116 | showDoublePrecision prec d = applyWhen (d < 0) ("-" ++) $
117 | formatDigits prec (roundScaled prec d)
123 | decimalDecompose : Double -> (Double, Integer)
124 | decimalDecompose d =
126 | e = cast (floor (log m / log 10.0))
127 | m0 = m / pow 10.0 (cast e)
128 | in if m0 >= 10.0 then (m0 / 10.0, e + 1)
129 | else if m0 < 1.0 then (m0 * 10.0, e - 1)
142 | showDoubleScientific : (precision : Nat) -> Double -> String
143 | showDoubleScientific prec 0.0 = formatDigits prec 0 ++ formatExp 0
144 | showDoubleScientific prec d =
145 | applyWhen (d < 0) ("-" ++) $
formatDigits prec mantInt ++ formatExp expFinal
147 | decomp : (Double, Integer)
148 | decomp = decimalDecompose d
152 | rounded = roundScaled prec (fst decomp)
156 | overflow = rounded >= cast (pow 10.0 (cast (S prec)))
159 | mantInt = applyWhen overflow (`div` 10) rounded
162 | expFinal = applyWhen overflow (+ 1) (snd decomp)
167 | trimTrailingZeros : String -> String
168 | trimTrailingZeros s = case break (== sciSymbol) (unpack s) of
169 | (mant, expPart) => case break (== '.') mant of
171 | (whole, _ :: frac) =>
172 | let trimmed : String
173 | trimmed = case reverse (dropWhile (== '0') (reverse frac)) of
176 | in pack whole ++ "." ++ trimmed ++ pack expPart
184 | showAsScientific : Cast a Double => a -> String
185 | showAsScientific n = trimTrailingZeros $
186 | showDoubleScientific defaultScientificPrecision (cast n)
192 | ScientificDisplay Double where
193 | showSci d = trimTrailingZeros $
case needsScientific d of
194 | True => showDoubleScientific defaultScientificPrecision d
195 | False => showDoublePrecision defaultScientificPrecision d
198 | ScientificDisplay Integer where
199 | showSci n = case cast (abs n) < sciUpperM of
201 | False => showAsScientific n
204 | ScientificDisplay Nat where
205 | showSci n = case cast n < sciUpperM of
207 | False => showAsScientific n
210 | ScientificDisplay Unit where
214 | ScientificDisplay a => ScientificDisplay b => ScientificDisplay (a, b) where
215 | showSci (x, y) = "(\{showSci x}, \{showSci y})"