@@ -97,4 +97,138 @@ export function scaleDown(coefficient: bigint, scaleFactor: number): bigint {
97
97
}
98
98
99
99
return coefficient / ( 10n ** BigInt ( scaleFactor ) ) ;
100
+ }
101
+
102
+ /**
103
+ * Rounds a coefficient using round-half-up behavior when scaling down.
104
+ *
105
+ * @param coefficient The BigInt coefficient to round
106
+ * @param currentScale The current scale of the coefficient
107
+ * @param targetScale The target scale after rounding
108
+ * @returns The rounded coefficient
109
+ * @throws Error if targetScale is negative or currentScale is negative
110
+ */
111
+ export function roundHalfUp ( coefficient : bigint , currentScale : number , targetScale : number ) : bigint {
112
+ if ( currentScale < 0 || targetScale < 0 ) {
113
+ throw new Error ( 'Scales must be non-negative' ) ;
114
+ }
115
+
116
+ if ( currentScale <= targetScale ) {
117
+ // Scale up by padding zeros
118
+ return scaleUp ( coefficient , targetScale - currentScale ) ;
119
+ }
120
+
121
+ // Scale down with rounding
122
+ const scaleDiff = currentScale - targetScale ;
123
+ const divisor = 10n ** BigInt ( scaleDiff ) ;
124
+ const quotient = coefficient / divisor ;
125
+ const remainder = coefficient % divisor ;
126
+
127
+ // Round half up logic
128
+ const halfDivisor = divisor / 2n ;
129
+ const absRemainder = remainder < 0n ? - remainder : remainder ;
130
+
131
+ if ( absRemainder >= halfDivisor ) {
132
+ return quotient + ( coefficient >= 0n ? 1n : - 1n ) ;
133
+ }
134
+
135
+ return quotient ;
136
+ }
137
+
138
+ /**
139
+ * Rounds a coefficient using ceiling behavior (always round up) when scaling down.
140
+ *
141
+ * @param coefficient The BigInt coefficient to round
142
+ * @param currentScale The current scale of the coefficient
143
+ * @param targetScale The target scale after rounding
144
+ * @returns The ceiling rounded coefficient
145
+ * @throws Error if targetScale is negative or currentScale is negative
146
+ */
147
+ export function ceilRound ( coefficient : bigint , currentScale : number , targetScale : number ) : bigint {
148
+ if ( currentScale < 0 || targetScale < 0 ) {
149
+ throw new Error ( 'Scales must be non-negative' ) ;
150
+ }
151
+
152
+ if ( currentScale <= targetScale ) {
153
+ // Scale up by padding zeros
154
+ return scaleUp ( coefficient , targetScale - currentScale ) ;
155
+ }
156
+
157
+ // Scale down with ceiling
158
+ const scaleDiff = currentScale - targetScale ;
159
+ const divisor = 10n ** BigInt ( scaleDiff ) ;
160
+ const quotient = coefficient / divisor ;
161
+ const remainder = coefficient % divisor ;
162
+
163
+ // Ceiling logic: if there's any remainder and coefficient is positive, round up
164
+ // If coefficient is negative and there's remainder, don't round (towards zero)
165
+ if ( remainder !== 0n && coefficient > 0n ) {
166
+ return quotient + 1n ;
167
+ }
168
+
169
+ return quotient ;
170
+ }
171
+
172
+ /**
173
+ * Rounds a coefficient using floor behavior (always round down) when scaling down.
174
+ *
175
+ * @param coefficient The BigInt coefficient to round
176
+ * @param currentScale The current scale of the coefficient
177
+ * @param targetScale The target scale after rounding
178
+ * @returns The floor rounded coefficient
179
+ * @throws Error if targetScale is negative or currentScale is negative
180
+ */
181
+ export function floorRound ( coefficient : bigint , currentScale : number , targetScale : number ) : bigint {
182
+ if ( currentScale < 0 || targetScale < 0 ) {
183
+ throw new Error ( 'Scales must be non-negative' ) ;
184
+ }
185
+
186
+ if ( currentScale <= targetScale ) {
187
+ // Scale up by padding zeros
188
+ return scaleUp ( coefficient , targetScale - currentScale ) ;
189
+ }
190
+
191
+ // Scale down with floor
192
+ const scaleDiff = currentScale - targetScale ;
193
+ const divisor = 10n ** BigInt ( scaleDiff ) ;
194
+ const quotient = coefficient / divisor ;
195
+ const remainder = coefficient % divisor ;
196
+
197
+ // Floor logic: if there's any remainder and coefficient is negative, round down
198
+ // If coefficient is positive and there's remainder, don't round (towards zero)
199
+ if ( remainder !== 0n && coefficient < 0n ) {
200
+ return quotient - 1n ;
201
+ }
202
+
203
+ return quotient ;
204
+ }
205
+
206
+ /**
207
+ * Formats a BigInt coefficient as a decimal string with the specified scale.
208
+ *
209
+ * @param coefficient The BigInt coefficient to format
210
+ * @param scale The number of decimal places
211
+ * @returns The formatted decimal string
212
+ */
213
+ export function formatBigIntAsDecimal ( coefficient : bigint , scale : number ) : string {
214
+ // Handle zero case
215
+ if ( coefficient === 0n ) {
216
+ return scale > 0 ? `0.${ '0' . repeat ( scale ) } ` : '0' ;
217
+ }
218
+
219
+ // Extract sign and work with absolute value
220
+ const sign = coefficient < 0n ? '-' : '' ;
221
+ const absCoeff = coefficient < 0n ? - coefficient : coefficient ;
222
+ let coeffStr = absCoeff . toString ( ) ;
223
+
224
+ // Pad with leading zeros if needed
225
+ while ( coeffStr . length <= scale ) {
226
+ coeffStr = '0' + coeffStr ;
227
+ }
228
+
229
+ // Split into integer and fractional parts
230
+ const integerPart = coeffStr . slice ( 0 , coeffStr . length - scale ) || '0' ;
231
+ const fractionalPart = scale > 0 ? coeffStr . slice ( - scale ) : '' ;
232
+
233
+ return sign + integerPart + ( scale > 0 ? '.' + fractionalPart : '' ) ;
100
234
}
0 commit comments