0 | module Data.ScientificNotation
27 | interface Num a => ScientificDisplay a where
29 | showSci : a -> String
44 | defaultScientificPrecision : Nat
45 | defaultScientificPrecision = 4
54 | needsScientific : Double -> Bool
55 | needsScientific d = d /= 0.0 && (m < sciLowerM || m >= sciUpperM)
66 | formatExp : Integer -> String
67 | formatExp n = singleton sciSymbol ++ sign ++ applyWhen (length ds < 2) ("0" ++) ds
69 | sign = if n < 0 then "-" else "+"
78 | roundScaled : (prec : Nat) -> Double -> Integer
79 | roundScaled prec d = cast (floor (abs d * pow 10.0 (cast prec) + 0.5))
92 | formatDigits : (prec : Nat) -> (digits : Integer) -> String
93 | formatDigits 0 n = show n
94 | formatDigits prec n = substr 0 nDig padded ++ "." ++ substr nDig prec padded
96 | len = length (show n)
98 | padded = applyWhen (len <= prec)
99 | (pack (replicate (S prec `minus` len) '0') ++)
102 | nDig = length padded `minus` prec
114 | showDoublePrecision : (precision : Nat) -> Double -> String
115 | showDoublePrecision prec d = applyWhen (d < 0) ("-" ++) $
116 | formatDigits prec (roundScaled prec d)
122 | decimalDecompose : Double -> (Double, Integer)
123 | decimalDecompose d =
125 | e = cast (floor (log m / log 10.0))
126 | m0 = m / pow 10.0 (cast e)
127 | in if m0 >= 10.0 then (m0 / 10.0, e + 1)
128 | else if m0 < 1.0 then (m0 * 10.0, e - 1)
141 | showDoubleScientific : (precision : Nat) -> Double -> String
142 | showDoubleScientific prec 0.0 = formatDigits prec 0 ++ formatExp 0
143 | showDoubleScientific prec d =
144 | applyWhen (d < 0) ("-" ++) $
formatDigits prec mantInt ++ formatExp expFinal
146 | decomp : (Double, Integer)
147 | decomp = decimalDecompose d
151 | rounded = roundScaled prec (fst decomp)
155 | overflow = rounded >= cast (pow 10.0 (cast (S prec)))
158 | mantInt = applyWhen overflow (`div` 10) rounded
161 | expFinal = applyWhen overflow (+ 1) (snd decomp)
166 | trimTrailingZeros : String -> String
167 | trimTrailingZeros s = case break (== sciSymbol) (unpack s) of
168 | (mant, expPart) => case break (== '.') mant of
170 | (whole, _ :: frac) =>
171 | let trimmed : String
172 | trimmed = case reverse (dropWhile (== '0') (reverse frac)) of
175 | in pack whole ++ "." ++ trimmed ++ pack expPart
183 | showAsScientific : Cast a Double => a -> String
184 | showAsScientific n = trimTrailingZeros $
185 | showDoubleScientific defaultScientificPrecision (cast n)
191 | ScientificDisplay Double where
192 | showSci d = trimTrailingZeros $
case needsScientific d of
193 | True => showDoubleScientific defaultScientificPrecision d
194 | False => showDoublePrecision defaultScientificPrecision d
197 | ScientificDisplay Integer where
198 | showSci n = case cast (abs n) < sciUpperM of
200 | False => showAsScientific n
203 | ScientificDisplay Nat where
204 | showSci n = case cast n < sciUpperM of
206 | False => showAsScientific n