@@ -82,7 +82,18 @@ formatParser = do
82
82
, abbreviations: isJust abbreviations
83
83
}
84
84
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`.
86
97
format ∷ Formatter → Number → String
87
98
format (Formatter f) num =
88
99
let
@@ -111,18 +122,20 @@ format (Formatter f) num =
111
122
else
112
123
let
113
124
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 =
123
136
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
126
139
127
140
addCommas ∷ Array Char → Int → Array Char → String
128
141
addCommas acc counter input = case Arr .uncons input of
@@ -133,13 +146,13 @@ format (Formatter f) num =
133
146
addCommas (Arr .cons ' ,' acc) zero input
134
147
in
135
148
(if num < zero then " -" else if num > zero && f.sign then " +" else " " )
136
- <> shownNumber
149
+ <> shownInt
137
150
<> (if f.after < 1
138
151
then " "
139
152
else
140
153
" ."
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 " " ))
143
156
144
157
145
158
unformat ∷ Formatter → String → Either String Number
0 commit comments