@@ -82,7 +82,18 @@ formatParser = do
8282 , abbreviations: isJust abbreviations
8383 }
8484
85-
85+ -- converts a number to a string of the nearest integer _without_ appending ".0" (like `show` for `Number`) or
86+ -- clamping to +/- 2 billion (like when working with `Int`). This is important for performance compared to other
87+ -- means of showing an integer potentially larger than +/- 2 billion.
88+ foreign import showNumberAsInt :: Number -> String
89+
90+ -- | Formats a number according to the format object provided.
91+ -- | Due to the nature of floating point numbers, may yield unpredictable results for extremely
92+ -- | large or extremely small numbers, such as numbers whose absolute values are ≥ 1e21 or ≤ 1e-21,
93+ -- | or when formatting with > 20 digits after the decimal place.
94+ -- | See [purescript-decimals](https://pursuit.purescript.org/packages/purescript-decimals/4.0.0)
95+ -- | for working with arbitrary precision decimals, which supports simple number
96+ -- | formatting for numbers that go beyond the precision available with `Number`.
8697format ∷ Formatter → Number → String
8798format (Formatter f) num =
8899 let
@@ -111,18 +122,20 @@ format (Formatter f) num =
111122 else
112123 let
113124 zeros = f.before - tens - one
114- integer = Int .floor absed
115- leftover = absed - Int .toNumber integer
116- rounded = Int .round $ leftover * (Math .pow 10.0 (Int .toNumber f.after))
117- roundedWithZeros =
118- let roundedString = show rounded
119- roundedLength = Str .length roundedString
120- zeros' = repeat " 0" (f.after - roundedLength)
121- in zeros' <> roundedString
122- shownNumber =
125+ factor = Math .pow 10.0 (Int .toNumber (max 0 f.after))
126+ rounded = Math .round (absed * factor) / factor
127+ integer = Math .floor rounded
128+ leftoverDecimal = rounded - integer
129+ leftover = Math .round $ leftoverDecimal * factor
130+ leftoverWithZeros =
131+ let leftoverString = showNumberAsInt leftover
132+ leftoverLength = Str .length leftoverString
133+ zeros' = repeat " 0" (f.after - leftoverLength)
134+ in zeros' <> leftoverString
135+ shownInt =
123136 if f.comma
124- then addCommas [] zero (Arr .reverse (CU .toCharArray (repeat " 0" zeros <> show integer)))
125- else repeat " 0" zeros <> show integer
137+ then addCommas [] zero (Arr .reverse (CU .toCharArray (repeat " 0" zeros <> showNumberAsInt integer)))
138+ else repeat " 0" zeros <> showNumberAsInt integer
126139
127140 addCommas ∷ Array Char → Int → Array Char → String
128141 addCommas acc counter input = case Arr .uncons input of
@@ -133,13 +146,13 @@ format (Formatter f) num =
133146 addCommas (Arr .cons ' ,' acc) zero input
134147 in
135148 (if num < zero then " -" else if num > zero && f.sign then " +" else " " )
136- <> shownNumber
149+ <> shownInt
137150 <> (if f.after < 1
138151 then " "
139152 else
140153 " ."
141- <> (if rounded == 0 then repeat " 0" f.after else " " )
142- <> (if rounded > 0 then roundedWithZeros else " " ))
154+ <> (if leftover == 0. 0 then repeat " 0" f.after else " " )
155+ <> (if leftover > 0.0 then leftoverWithZeros else " " ))
143156
144157
145158unformat ∷ Formatter → String → Either String Number
0 commit comments