@quentinadam/decimal 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/Decimal.d.ts +400 -0
- package/dist/Decimal.js +736 -0
- package/package.json +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @quentinadam/decimal
|
|
2
|
+
|
|
3
|
+
[![JSR][jsr-image]][jsr-url] [![NPM][npm-image]][npm-url] [![CI][ci-image]][ci-url]
|
|
4
|
+
|
|
5
|
+
A library for working with arbitrary precision decimal numbers.
|
|
6
|
+
|
|
7
|
+
Decimal numbers are represented by a mantissa (bigint) and an exponent (number). Instances of the Decimal class are
|
|
8
|
+
immutable; calling functions (like `abs`, `add`, `ceil`, ...) on an instance will return a new Decimal instance with the
|
|
9
|
+
result. Division may fail if the resulting number cannot be represented with a fixed number of decimals (like 1/3).
|
|
10
|
+
Please check the documentation of the `div` function for more details.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import Decimal from '@quentinadam/decimal';
|
|
16
|
+
|
|
17
|
+
const a = Decimal.from('1.11111111111111111111');
|
|
18
|
+
|
|
19
|
+
const b = a.mul(2);
|
|
20
|
+
|
|
21
|
+
console.log(b.toString()); // prints 2.22222222222222222222
|
|
22
|
+
|
|
23
|
+
const c = a.add(b);
|
|
24
|
+
|
|
25
|
+
console.log(c.toString()); // prints 3.33333333333333333333
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
[ci-image]: https://img.shields.io/github/actions/workflow/status/quentinadam/deno-decimal/ci.yml?branch=main&logo=github&style=flat-square
|
|
29
|
+
[ci-url]: https://github.com/quentinadam/deno-decimal/actions/workflows/ci.yml
|
|
30
|
+
[npm-image]: https://img.shields.io/npm/v/@quentinadam/decimal.svg?style=flat-square
|
|
31
|
+
[npm-url]: https://npmjs.org/package/@quentinadam/decimal
|
|
32
|
+
[jsr-image]: https://jsr.io/badges/@quentinadam/decimal?style=flat-square
|
|
33
|
+
[jsr-url]: https://jsr.io/@quentinadam/decimal
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A type alias representing the different types a Decimal instance can be created from.
|
|
3
|
+
*/
|
|
4
|
+
export type DecimalType = Decimal | number | bigint | string;
|
|
5
|
+
/**
|
|
6
|
+
* A class to represent arbitrary precision decimal numbers.
|
|
7
|
+
*/
|
|
8
|
+
export default class Decimal {
|
|
9
|
+
readonly mantissa: bigint;
|
|
10
|
+
readonly exponent: number;
|
|
11
|
+
/**
|
|
12
|
+
* Constructs a new Decimal instance, from a `mantissa` and an `exponent`.
|
|
13
|
+
*
|
|
14
|
+
* Conceptually, a Decimal instance represents the value `mantissa * 10 ^ exponent`.
|
|
15
|
+
*
|
|
16
|
+
* The constructor normalizes the mantissa and exponent, ensuring that the mantissa is as small as possible.
|
|
17
|
+
*
|
|
18
|
+
* If the mantissa is 0, the exponent is set to 0.
|
|
19
|
+
*
|
|
20
|
+
* @param mantissa The mantissa, represented as a bigint.
|
|
21
|
+
* @param exponent The exponent, representing the power of 10 by which the mantissa is multiplied. Defaults to 0.
|
|
22
|
+
* @throws Will throw an error if the exponent is not an integer.
|
|
23
|
+
*/
|
|
24
|
+
constructor(mantissa: bigint, exponent?: number);
|
|
25
|
+
/**
|
|
26
|
+
* Returns the absolute value of the current Decimal instance.
|
|
27
|
+
*
|
|
28
|
+
* @returns A new Decimal instance representing the absolute value.
|
|
29
|
+
*/
|
|
30
|
+
abs(): Decimal;
|
|
31
|
+
/**
|
|
32
|
+
* Adds the provided value to the current Decimal instance.
|
|
33
|
+
*
|
|
34
|
+
* @param value The value to add.
|
|
35
|
+
* @returns A new Decimal instance representing the sum.
|
|
36
|
+
*/
|
|
37
|
+
add(value: DecimalType): Decimal;
|
|
38
|
+
/**
|
|
39
|
+
* Rounds the current value up towards positive infinity to the nearest multiple of the specified precision.
|
|
40
|
+
*
|
|
41
|
+
* @param precision The precision to round to. Defaults to `Decimal.one`, meaning it rounds to the nearest integer.
|
|
42
|
+
* @returns A new Decimal instance representing the rounded value.
|
|
43
|
+
*/
|
|
44
|
+
ceil(precision?: DecimalType): Decimal;
|
|
45
|
+
/**
|
|
46
|
+
* Compares the current Decimal instance with the provided value.
|
|
47
|
+
*
|
|
48
|
+
* @param other The value to compare with.
|
|
49
|
+
* @returns 0 if both values are equal, 1 if the current instance is greater, and -1 if it is less.
|
|
50
|
+
*/
|
|
51
|
+
compare(other: DecimalType): number;
|
|
52
|
+
/**
|
|
53
|
+
* Divides the current Decimal instance by the provided value.
|
|
54
|
+
*
|
|
55
|
+
* Throws if the resulting value cannot be represented with a fixed number of decimals (like 1/3).
|
|
56
|
+
*
|
|
57
|
+
* If you need to divide by such a value, use the optional `significantDigits` parameter to specify the number of significant digits to use in the result.
|
|
58
|
+
*
|
|
59
|
+
* ```ts
|
|
60
|
+
* Decimal.from(1).div(3); // Throws
|
|
61
|
+
* Decimal.from(1).div(3, 2); // Returns 0.33
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @param value The value to divide by.
|
|
65
|
+
* @param significantDigits The number of significant digits to use in the result.
|
|
66
|
+
* @returns A new Decimal instance representing the result of the division.
|
|
67
|
+
*/
|
|
68
|
+
div(value: DecimalType, significantDigits?: number): Decimal;
|
|
69
|
+
/**
|
|
70
|
+
* Multiplies the current Decimal instance by 10 raised to the provided integer exponent.
|
|
71
|
+
*
|
|
72
|
+
* @param exponent The integer exponent to raise 10 to.
|
|
73
|
+
* @returns A new Decimal instance representing the result.
|
|
74
|
+
*/
|
|
75
|
+
e(exponent: number): Decimal;
|
|
76
|
+
/**
|
|
77
|
+
* Checks if the current Decimal instance is equal to the provided value.
|
|
78
|
+
*
|
|
79
|
+
* @param value The value to compare with.
|
|
80
|
+
* @returns True if the values are equal, false otherwise.
|
|
81
|
+
*/
|
|
82
|
+
eq(value: DecimalType): boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Checks if the current Decimal instance is equal to zero.
|
|
85
|
+
*
|
|
86
|
+
* @returns True if the value is zero, false otherwise.
|
|
87
|
+
*/
|
|
88
|
+
eq0(): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* Rounds the current value down towards negative infinity to the nearest multiple of the specified precision.
|
|
91
|
+
*
|
|
92
|
+
* @param precision The precision to round to. Defaults to `Decimal.one`, meaning it rounds to the nearest integer.
|
|
93
|
+
* @returns A new Decimal instance representing the rounded value.
|
|
94
|
+
*/
|
|
95
|
+
floor(precision?: DecimalType): Decimal;
|
|
96
|
+
/**
|
|
97
|
+
* Checks if the current Decimal instance is greater than the provided value.
|
|
98
|
+
*
|
|
99
|
+
* @param value The value to compare with.
|
|
100
|
+
* @returns True if the current instance is greater, false otherwise.
|
|
101
|
+
*/
|
|
102
|
+
gt(value: DecimalType): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Checks if the current Decimal instance is greater than zero.
|
|
105
|
+
*
|
|
106
|
+
* @returns True if the value is greater than zero, false otherwise.
|
|
107
|
+
*/
|
|
108
|
+
gt0(): boolean;
|
|
109
|
+
/**
|
|
110
|
+
* Checks if the current Decimal instance is greater than or equal to the provided value.
|
|
111
|
+
*
|
|
112
|
+
* @param value The value to compare with.
|
|
113
|
+
* @returns True if the current instance is greater or equal, false otherwise.
|
|
114
|
+
*/
|
|
115
|
+
gte(value: DecimalType): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Checks if the current Decimal instance is greater than or equal to zero.
|
|
118
|
+
*
|
|
119
|
+
* @returns True if the value is greater than or equal to zero, false otherwise.
|
|
120
|
+
*/
|
|
121
|
+
gte0(): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Returns the multiplicative inverse of the current Decimal instance.
|
|
124
|
+
*
|
|
125
|
+
* Throws if the resulting value cannot be represented with a fixed number of decimals (like 1/3).
|
|
126
|
+
*
|
|
127
|
+
* If you need to invert such a value, use the optional `significantDigits` parameter to specify the number of significant digits to use in the result.
|
|
128
|
+
*
|
|
129
|
+
* ```ts
|
|
130
|
+
* Decimal.from(3).inv(); // Throws
|
|
131
|
+
* Decimal.from(3).inv(2); // Returns 0.33
|
|
132
|
+
* ```
|
|
133
|
+
*
|
|
134
|
+
* @param significantDigits The number of significant digits to use in the result.
|
|
135
|
+
* @returns A new Decimal instance representing the inverse.
|
|
136
|
+
*/
|
|
137
|
+
inv(significantDigits?: number): Decimal;
|
|
138
|
+
/**
|
|
139
|
+
* Checks if the current Decimal instance is an integer.
|
|
140
|
+
*
|
|
141
|
+
* @returns True if the value is an integer, false otherwise.
|
|
142
|
+
*/
|
|
143
|
+
isInteger(): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Checks if the current Decimal instance is less than the provided value.
|
|
146
|
+
*
|
|
147
|
+
* @param value The value to compare with.
|
|
148
|
+
* @returns True if the current instance is less, false otherwise.
|
|
149
|
+
*/
|
|
150
|
+
lt(value: DecimalType): boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Checks if the current Decimal instance is less than zero.
|
|
153
|
+
*
|
|
154
|
+
* @returns True if the value is less than zero, false otherwise.
|
|
155
|
+
*/
|
|
156
|
+
lt0(): boolean;
|
|
157
|
+
/**
|
|
158
|
+
* Checks if the current Decimal instance is less than or equal to the provided value.
|
|
159
|
+
*
|
|
160
|
+
* @param value The value to compare with.
|
|
161
|
+
* @returns True if the current instance is less or equal, false otherwise.
|
|
162
|
+
*/
|
|
163
|
+
lte(value: DecimalType): boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Checks if the current Decimal instance is less than or equal to zero.
|
|
166
|
+
*
|
|
167
|
+
* @returns True if the value is less than or equal to zero, false otherwise.
|
|
168
|
+
*/
|
|
169
|
+
lte0(): boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Returns the order of magnitude (defined as `floor(log10(abs(value)))`) of the current Decimal instance.
|
|
172
|
+
*
|
|
173
|
+
* @returns A number representing the order of magnitude.
|
|
174
|
+
*/
|
|
175
|
+
magnitude(): number;
|
|
176
|
+
/**
|
|
177
|
+
* Returns the remainder when dividing the current Decimal instance by the provided value.
|
|
178
|
+
*
|
|
179
|
+
* @param value The value to divide by.
|
|
180
|
+
* @returns A new Decimal instance representing the remainder.
|
|
181
|
+
*/
|
|
182
|
+
mod(value: DecimalType): Decimal;
|
|
183
|
+
/**
|
|
184
|
+
* Multiplies the current Decimal instance by the provided value.
|
|
185
|
+
*
|
|
186
|
+
* @param value The value to multiply by.
|
|
187
|
+
* @returns A new Decimal instance representing the product.
|
|
188
|
+
*/
|
|
189
|
+
mul(value: DecimalType): Decimal;
|
|
190
|
+
/**
|
|
191
|
+
* Negates the current Decimal instance.
|
|
192
|
+
*
|
|
193
|
+
* @returns A new Decimal instance representing the negated value.
|
|
194
|
+
*/
|
|
195
|
+
neg(): Decimal;
|
|
196
|
+
/**
|
|
197
|
+
* Checks if the current value is not equal to the provided value.
|
|
198
|
+
*
|
|
199
|
+
* @param value The value to compare against.
|
|
200
|
+
* @returns True if the values are not equal, false otherwise.
|
|
201
|
+
*/
|
|
202
|
+
neq(value: DecimalType): boolean;
|
|
203
|
+
/**
|
|
204
|
+
* Checks if the current value is not equal to zero.
|
|
205
|
+
*
|
|
206
|
+
* @returns True if the value is not zero, false otherwise.
|
|
207
|
+
*/
|
|
208
|
+
neq0(): boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Raises the current Decimal instance to the power of the provided integer exponent.
|
|
211
|
+
*
|
|
212
|
+
* @param value The integer exponent to raise to.
|
|
213
|
+
* @returns A new Decimal instance representing the result of the exponentiation.
|
|
214
|
+
*/
|
|
215
|
+
pow(value: number): Decimal;
|
|
216
|
+
/**
|
|
217
|
+
* Rounds the current value towards the nearest multiple of the specified precision.
|
|
218
|
+
*
|
|
219
|
+
* If the current value is exactly halfway between two multiples of the precision, it is rounded up towards positive infinity.
|
|
220
|
+
*
|
|
221
|
+
* @param precision The precision to round to. Defaults to `Decimal.one`, meaning it rounds to the nearest integer.
|
|
222
|
+
* @returns A new Decimal instance representing the rounded value.
|
|
223
|
+
*/
|
|
224
|
+
round(precision?: DecimalType): Decimal;
|
|
225
|
+
/**
|
|
226
|
+
* Returns the sign of the current value as a Decimal instance.
|
|
227
|
+
*
|
|
228
|
+
* @returns A Decimal instance representing the sign: 1 for positive, -1 for negative, and 0 for zero.
|
|
229
|
+
*/
|
|
230
|
+
sign(): Decimal;
|
|
231
|
+
/**
|
|
232
|
+
* Subtracts the provided value from the current Decimal instance.
|
|
233
|
+
*
|
|
234
|
+
* @param value The value to subtract.
|
|
235
|
+
* @returns A new Decimal instance representing the result of the subtraction.
|
|
236
|
+
*/
|
|
237
|
+
sub(value: DecimalType): Decimal;
|
|
238
|
+
/**
|
|
239
|
+
* Converts the current Decimal instance to a bigint, if it is an integer.
|
|
240
|
+
*
|
|
241
|
+
* Throws if the Decimal instance is not an integer.
|
|
242
|
+
*
|
|
243
|
+
* @returns A bigint representing the integer value of the Decimal instance.
|
|
244
|
+
*/
|
|
245
|
+
toBigInt(): bigint;
|
|
246
|
+
/**
|
|
247
|
+
* Converts the current Decimal instance to a fixed-point notation string.
|
|
248
|
+
*
|
|
249
|
+
* @param precision The number of decimal places to include in the result.
|
|
250
|
+
* @returns A string representing the Decimal instance in fixed-point notation.
|
|
251
|
+
*/
|
|
252
|
+
toFixed(precision: number): string;
|
|
253
|
+
/**
|
|
254
|
+
* Converts the current value to a fraction represented by a numerator and denominator.
|
|
255
|
+
*
|
|
256
|
+
* Simplifies the fraction to its lowest terms.
|
|
257
|
+
*
|
|
258
|
+
* @returns An object with numerator and denominator properties.
|
|
259
|
+
*/
|
|
260
|
+
toFraction(): {
|
|
261
|
+
numerator: bigint;
|
|
262
|
+
denominator: bigint;
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* Converts the current Decimal value to a JSON string.
|
|
266
|
+
*
|
|
267
|
+
* @returns A string representing the Decimal value in JSON format.
|
|
268
|
+
*/
|
|
269
|
+
toJSON(): string;
|
|
270
|
+
/**
|
|
271
|
+
* Converts the current value to a number.
|
|
272
|
+
*
|
|
273
|
+
* This may lose precision if the Decimal cannot be exactly represented as a number.
|
|
274
|
+
*
|
|
275
|
+
* @returns The number representation of the current Decimal value.
|
|
276
|
+
*/
|
|
277
|
+
toNumber(): number;
|
|
278
|
+
/**
|
|
279
|
+
* Converts the current value to a string.
|
|
280
|
+
*
|
|
281
|
+
* @returns A string representing the current Decimal value.
|
|
282
|
+
*/
|
|
283
|
+
toString(): string;
|
|
284
|
+
/**
|
|
285
|
+
* A static constant representing the decimal value -1.
|
|
286
|
+
*/
|
|
287
|
+
static minusOne: Decimal;
|
|
288
|
+
/**
|
|
289
|
+
* A static constant representing the decimal value 1.
|
|
290
|
+
*/
|
|
291
|
+
static one: Decimal;
|
|
292
|
+
/**
|
|
293
|
+
* A static constant representing the decimal value 0.
|
|
294
|
+
*/
|
|
295
|
+
static zero: Decimal;
|
|
296
|
+
/**
|
|
297
|
+
* Adds multiple values together.
|
|
298
|
+
*
|
|
299
|
+
* @param values An array of values to add.
|
|
300
|
+
* @returns A new Decimal instance representing the sum of the values.
|
|
301
|
+
*/
|
|
302
|
+
static add(...values: DecimalType[]): Decimal;
|
|
303
|
+
/**
|
|
304
|
+
* Divides one value by another.
|
|
305
|
+
*
|
|
306
|
+
* Throws if the resulting value cannot be represented with a fixed number of decimals (like 1/3).
|
|
307
|
+
*
|
|
308
|
+
* If you need to divide by such a value, use the optional `significantDigits` parameter to specify the number of significant digits to use in the result.
|
|
309
|
+
*
|
|
310
|
+
* ```ts
|
|
311
|
+
* Decimal.div(1, 3); // Throws
|
|
312
|
+
* Decimal.div(1, 3, 2); // Returns 0.33
|
|
313
|
+
* ```
|
|
314
|
+
* @param dividend The value to divide.
|
|
315
|
+
* @param divisor The value to divide by.
|
|
316
|
+
* @param significantDigits The number of significant digits to use in the result.
|
|
317
|
+
* @returns A new Decimal instance representing the quotient.
|
|
318
|
+
*/
|
|
319
|
+
static div(dividend: DecimalType, divisor: DecimalType, significantDigits?: number): Decimal;
|
|
320
|
+
/**
|
|
321
|
+
* Creates a Decimal instance from a string (in standard or scientific notation), a number or a bigint.
|
|
322
|
+
*
|
|
323
|
+
* @param value The value to convert.
|
|
324
|
+
* @returns A Decimal instance representing the provided value.
|
|
325
|
+
*/
|
|
326
|
+
static from(value: DecimalType): Decimal;
|
|
327
|
+
/**
|
|
328
|
+
* Creates a Decimal instance from a fraction.
|
|
329
|
+
*
|
|
330
|
+
* Throws if the fraction cannot be represented with a fixed number of decimals.
|
|
331
|
+
*
|
|
332
|
+
* @param numerator The numerator of the fraction.
|
|
333
|
+
* @param denominator The denominator of the fraction.
|
|
334
|
+
* @returns A Decimal instance representing the fraction.
|
|
335
|
+
*/
|
|
336
|
+
static fromFraction({ numerator, denominator }: {
|
|
337
|
+
numerator: bigint;
|
|
338
|
+
denominator: bigint;
|
|
339
|
+
}): Decimal;
|
|
340
|
+
/**
|
|
341
|
+
* Creates a Decimal instance from a bigint.
|
|
342
|
+
*
|
|
343
|
+
* @param value The bigint value to convert.
|
|
344
|
+
* @returns A Decimal instance representing the provided bigint value.
|
|
345
|
+
*/
|
|
346
|
+
static fromBigInt(value: bigint): Decimal;
|
|
347
|
+
/**
|
|
348
|
+
* Creates a Decimal instance from a number.
|
|
349
|
+
*
|
|
350
|
+
* @param value The number value to convert.
|
|
351
|
+
* @returns A Decimal instance representing the provided number.
|
|
352
|
+
*/
|
|
353
|
+
static fromNumber(value: number): Decimal;
|
|
354
|
+
/**
|
|
355
|
+
* Creates a Decimal instance from a string (in standard or scientific notation).
|
|
356
|
+
*
|
|
357
|
+
* @param string The string value to convert.
|
|
358
|
+
* @returns A Decimal instance representing the provided string.
|
|
359
|
+
*/
|
|
360
|
+
static fromString(string: string): Decimal;
|
|
361
|
+
/**
|
|
362
|
+
* Finds the maximum value among the provided values.
|
|
363
|
+
*
|
|
364
|
+
* @param first The first value to compare.
|
|
365
|
+
* @param values Additional values to compare.
|
|
366
|
+
* @returns A new Decimal instance representing the maximum value.
|
|
367
|
+
*/
|
|
368
|
+
static max(first: DecimalType, ...values: DecimalType[]): Decimal;
|
|
369
|
+
/**
|
|
370
|
+
* Finds the minimum value among the provided values.
|
|
371
|
+
*
|
|
372
|
+
* @param first The first value to compare.
|
|
373
|
+
* @param values Additional values to compare.
|
|
374
|
+
* @returns A new Decimal instance representing the minimum value.
|
|
375
|
+
*/
|
|
376
|
+
static min(first: DecimalType, ...values: DecimalType[]): Decimal;
|
|
377
|
+
/**
|
|
378
|
+
* Multiplies multiple values together.
|
|
379
|
+
*
|
|
380
|
+
* @param values An array of values to multiply.
|
|
381
|
+
* @returns A new Decimal instance representing the product of the values.
|
|
382
|
+
*/
|
|
383
|
+
static mul(...values: DecimalType[]): Decimal;
|
|
384
|
+
/**
|
|
385
|
+
* Subtracts one value from another.
|
|
386
|
+
*
|
|
387
|
+
* @param minuend The value to subtract from.
|
|
388
|
+
* @param subtrahend The value to subtract.
|
|
389
|
+
* @returns A new Decimal instance representing the result of the subtraction.
|
|
390
|
+
*/
|
|
391
|
+
static sub(minuend: DecimalType, subtrahend: DecimalType): Decimal;
|
|
392
|
+
/**
|
|
393
|
+
* Calculates the greatest common divisor (GCD) of two values.
|
|
394
|
+
*
|
|
395
|
+
* @param a The first value.
|
|
396
|
+
* @param b The second value.
|
|
397
|
+
* @returns A new Decimal instance representing the GCD of the two values.
|
|
398
|
+
*/
|
|
399
|
+
static gcd(a: DecimalType, b: DecimalType): Decimal;
|
|
400
|
+
}
|
package/dist/Decimal.js
ADDED
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
import assert from '@quentinadam/assert';
|
|
2
|
+
/**
|
|
3
|
+
* A class to represent arbitrary precision decimal numbers.
|
|
4
|
+
*/
|
|
5
|
+
export default class Decimal {
|
|
6
|
+
mantissa;
|
|
7
|
+
exponent;
|
|
8
|
+
/**
|
|
9
|
+
* Constructs a new Decimal instance, from a `mantissa` and an `exponent`.
|
|
10
|
+
*
|
|
11
|
+
* Conceptually, a Decimal instance represents the value `mantissa * 10 ^ exponent`.
|
|
12
|
+
*
|
|
13
|
+
* The constructor normalizes the mantissa and exponent, ensuring that the mantissa is as small as possible.
|
|
14
|
+
*
|
|
15
|
+
* If the mantissa is 0, the exponent is set to 0.
|
|
16
|
+
*
|
|
17
|
+
* @param mantissa The mantissa, represented as a bigint.
|
|
18
|
+
* @param exponent The exponent, representing the power of 10 by which the mantissa is multiplied. Defaults to 0.
|
|
19
|
+
* @throws Will throw an error if the exponent is not an integer.
|
|
20
|
+
*/
|
|
21
|
+
constructor(mantissa, exponent = 0) {
|
|
22
|
+
assert(Number.isInteger(exponent), `Exponent must be an integer, got ${exponent}`);
|
|
23
|
+
if (mantissa === 0n) {
|
|
24
|
+
this.mantissa = 0n;
|
|
25
|
+
this.exponent = 0;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
while (mantissa % 10n === 0n) {
|
|
29
|
+
mantissa /= 10n;
|
|
30
|
+
exponent += 1;
|
|
31
|
+
}
|
|
32
|
+
this.mantissa = mantissa;
|
|
33
|
+
this.exponent = exponent;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Custom inspection method for Deno which returns the string representation of the Decimal instance.
|
|
38
|
+
*
|
|
39
|
+
* @returns A string representing the Decimal value.
|
|
40
|
+
*/
|
|
41
|
+
[Symbol.for('Deno.customInspect')]() {
|
|
42
|
+
return this.toString();
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Returns the absolute value of the current Decimal instance.
|
|
46
|
+
*
|
|
47
|
+
* @returns A new Decimal instance representing the absolute value.
|
|
48
|
+
*/
|
|
49
|
+
abs() {
|
|
50
|
+
return this.gt0() ? this : this.neg();
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Adds the provided value to the current Decimal instance.
|
|
54
|
+
*
|
|
55
|
+
* @param value The value to add.
|
|
56
|
+
* @returns A new Decimal instance representing the sum.
|
|
57
|
+
*/
|
|
58
|
+
add(value) {
|
|
59
|
+
value = Decimal.from(value);
|
|
60
|
+
const { mantissa1, mantissa2, exponent } = normalize(this, value);
|
|
61
|
+
return new Decimal(mantissa1 + mantissa2, exponent);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Rounds the current value up towards positive infinity to the nearest multiple of the specified precision.
|
|
65
|
+
*
|
|
66
|
+
* @param precision The precision to round to. Defaults to `Decimal.one`, meaning it rounds to the nearest integer.
|
|
67
|
+
* @returns A new Decimal instance representing the rounded value.
|
|
68
|
+
*/
|
|
69
|
+
ceil(precision = Decimal.one) {
|
|
70
|
+
const remainder = this.mod(precision);
|
|
71
|
+
if (remainder.eq0()) {
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
return this.sub(remainder).add(precision);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Compares the current Decimal instance with the provided value.
|
|
78
|
+
*
|
|
79
|
+
* @param other The value to compare with.
|
|
80
|
+
* @returns 0 if both values are equal, 1 if the current instance is greater, and -1 if it is less.
|
|
81
|
+
*/
|
|
82
|
+
compare(other) {
|
|
83
|
+
return this.sub(other).sign().toNumber();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Divides the current Decimal instance by the provided value.
|
|
87
|
+
*
|
|
88
|
+
* Throws if the resulting value cannot be represented with a fixed number of decimals (like 1/3).
|
|
89
|
+
*
|
|
90
|
+
* If you need to divide by such a value, use the optional `significantDigits` parameter to specify the number of significant digits to use in the result.
|
|
91
|
+
*
|
|
92
|
+
* ```ts
|
|
93
|
+
* Decimal.from(1).div(3); // Throws
|
|
94
|
+
* Decimal.from(1).div(3, 2); // Returns 0.33
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* @param value The value to divide by.
|
|
98
|
+
* @param significantDigits The number of significant digits to use in the result.
|
|
99
|
+
* @returns A new Decimal instance representing the result of the division.
|
|
100
|
+
*/
|
|
101
|
+
div(value, significantDigits) {
|
|
102
|
+
value = Decimal.from(value);
|
|
103
|
+
assert(value.neq0(), 'Division by zero');
|
|
104
|
+
if (this.eq0()) {
|
|
105
|
+
return Decimal.zero;
|
|
106
|
+
}
|
|
107
|
+
if (this.lt0()) {
|
|
108
|
+
return this.neg().div(value, significantDigits).neg();
|
|
109
|
+
}
|
|
110
|
+
if (value.lt0()) {
|
|
111
|
+
return this.div(value.neg(), significantDigits).neg();
|
|
112
|
+
}
|
|
113
|
+
let { mantissa1, mantissa2 } = normalize(this, value);
|
|
114
|
+
if (significantDigits === undefined) {
|
|
115
|
+
return Decimal.fromFraction({ numerator: mantissa1, denominator: mantissa2 });
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
assert(Number.isInteger(significantDigits) && significantDigits > 0, `Significant digits must be a positive integer, got ${significantDigits}`);
|
|
119
|
+
let exponent = 0;
|
|
120
|
+
while (mantissa1 < mantissa2) {
|
|
121
|
+
mantissa1 *= 10n;
|
|
122
|
+
exponent -= 1;
|
|
123
|
+
}
|
|
124
|
+
while (mantissa2 < mantissa1) {
|
|
125
|
+
mantissa2 *= 10n;
|
|
126
|
+
exponent += 1;
|
|
127
|
+
}
|
|
128
|
+
for (let i = 0; i < significantDigits; i++) {
|
|
129
|
+
mantissa1 *= 10n;
|
|
130
|
+
exponent -= 1;
|
|
131
|
+
}
|
|
132
|
+
let quotient = mantissa1 / mantissa2;
|
|
133
|
+
const remainder = mantissa1 % mantissa2;
|
|
134
|
+
if (remainder * 2n >= mantissa2) {
|
|
135
|
+
quotient += 1n;
|
|
136
|
+
}
|
|
137
|
+
return new Decimal(quotient, exponent);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Multiplies the current Decimal instance by 10 raised to the provided integer exponent.
|
|
142
|
+
*
|
|
143
|
+
* @param exponent The integer exponent to raise 10 to.
|
|
144
|
+
* @returns A new Decimal instance representing the result.
|
|
145
|
+
*/
|
|
146
|
+
e(exponent) {
|
|
147
|
+
return this.mul(new Decimal(10n).pow(exponent));
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Checks if the current Decimal instance is equal to the provided value.
|
|
151
|
+
*
|
|
152
|
+
* @param value The value to compare with.
|
|
153
|
+
* @returns True if the values are equal, false otherwise.
|
|
154
|
+
*/
|
|
155
|
+
eq(value) {
|
|
156
|
+
value = Decimal.from(value);
|
|
157
|
+
const { mantissa1, mantissa2 } = normalize(this, value);
|
|
158
|
+
return mantissa1 === mantissa2;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Checks if the current Decimal instance is equal to zero.
|
|
162
|
+
*
|
|
163
|
+
* @returns True if the value is zero, false otherwise.
|
|
164
|
+
*/
|
|
165
|
+
eq0() {
|
|
166
|
+
return this.mantissa === 0n;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Rounds the current value down towards negative infinity to the nearest multiple of the specified precision.
|
|
170
|
+
*
|
|
171
|
+
* @param precision The precision to round to. Defaults to `Decimal.one`, meaning it rounds to the nearest integer.
|
|
172
|
+
* @returns A new Decimal instance representing the rounded value.
|
|
173
|
+
*/
|
|
174
|
+
floor(precision = Decimal.one) {
|
|
175
|
+
const remainder = this.mod(precision);
|
|
176
|
+
if (remainder.eq0()) {
|
|
177
|
+
return this;
|
|
178
|
+
}
|
|
179
|
+
return this.sub(remainder);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Checks if the current Decimal instance is greater than the provided value.
|
|
183
|
+
*
|
|
184
|
+
* @param value The value to compare with.
|
|
185
|
+
* @returns True if the current instance is greater, false otherwise.
|
|
186
|
+
*/
|
|
187
|
+
gt(value) {
|
|
188
|
+
value = Decimal.from(value);
|
|
189
|
+
const { mantissa1, mantissa2 } = normalize(this, value);
|
|
190
|
+
return mantissa1 > mantissa2;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Checks if the current Decimal instance is greater than zero.
|
|
194
|
+
*
|
|
195
|
+
* @returns True if the value is greater than zero, false otherwise.
|
|
196
|
+
*/
|
|
197
|
+
gt0() {
|
|
198
|
+
return this.mantissa > 0n;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Checks if the current Decimal instance is greater than or equal to the provided value.
|
|
202
|
+
*
|
|
203
|
+
* @param value The value to compare with.
|
|
204
|
+
* @returns True if the current instance is greater or equal, false otherwise.
|
|
205
|
+
*/
|
|
206
|
+
gte(value) {
|
|
207
|
+
value = Decimal.from(value);
|
|
208
|
+
const { mantissa1, mantissa2 } = normalize(this, value);
|
|
209
|
+
return mantissa1 >= mantissa2;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Checks if the current Decimal instance is greater than or equal to zero.
|
|
213
|
+
*
|
|
214
|
+
* @returns True if the value is greater than or equal to zero, false otherwise.
|
|
215
|
+
*/
|
|
216
|
+
gte0() {
|
|
217
|
+
return this.mantissa >= 0n;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Returns the multiplicative inverse of the current Decimal instance.
|
|
221
|
+
*
|
|
222
|
+
* Throws if the resulting value cannot be represented with a fixed number of decimals (like 1/3).
|
|
223
|
+
*
|
|
224
|
+
* If you need to invert such a value, use the optional `significantDigits` parameter to specify the number of significant digits to use in the result.
|
|
225
|
+
*
|
|
226
|
+
* ```ts
|
|
227
|
+
* Decimal.from(3).inv(); // Throws
|
|
228
|
+
* Decimal.from(3).inv(2); // Returns 0.33
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* @param significantDigits The number of significant digits to use in the result.
|
|
232
|
+
* @returns A new Decimal instance representing the inverse.
|
|
233
|
+
*/
|
|
234
|
+
inv(significantDigits) {
|
|
235
|
+
return Decimal.one.div(this, significantDigits);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Checks if the current Decimal instance is an integer.
|
|
239
|
+
*
|
|
240
|
+
* @returns True if the value is an integer, false otherwise.
|
|
241
|
+
*/
|
|
242
|
+
isInteger() {
|
|
243
|
+
return this.exponent >= 0;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Checks if the current Decimal instance is less than the provided value.
|
|
247
|
+
*
|
|
248
|
+
* @param value The value to compare with.
|
|
249
|
+
* @returns True if the current instance is less, false otherwise.
|
|
250
|
+
*/
|
|
251
|
+
lt(value) {
|
|
252
|
+
value = Decimal.from(value);
|
|
253
|
+
const { mantissa1, mantissa2 } = normalize(this, value);
|
|
254
|
+
return mantissa1 < mantissa2;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Checks if the current Decimal instance is less than zero.
|
|
258
|
+
*
|
|
259
|
+
* @returns True if the value is less than zero, false otherwise.
|
|
260
|
+
*/
|
|
261
|
+
lt0() {
|
|
262
|
+
return this.mantissa < 0n;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Checks if the current Decimal instance is less than or equal to the provided value.
|
|
266
|
+
*
|
|
267
|
+
* @param value The value to compare with.
|
|
268
|
+
* @returns True if the current instance is less or equal, false otherwise.
|
|
269
|
+
*/
|
|
270
|
+
lte(value) {
|
|
271
|
+
value = Decimal.from(value);
|
|
272
|
+
const { mantissa1, mantissa2 } = normalize(this, value);
|
|
273
|
+
return mantissa1 <= mantissa2;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Checks if the current Decimal instance is less than or equal to zero.
|
|
277
|
+
*
|
|
278
|
+
* @returns True if the value is less than or equal to zero, false otherwise.
|
|
279
|
+
*/
|
|
280
|
+
lte0() {
|
|
281
|
+
return this.mantissa <= 0n;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Returns the order of magnitude (defined as `floor(log10(abs(value)))`) of the current Decimal instance.
|
|
285
|
+
*
|
|
286
|
+
* @returns A number representing the order of magnitude.
|
|
287
|
+
*/
|
|
288
|
+
magnitude() {
|
|
289
|
+
if (this.lt0()) {
|
|
290
|
+
return this.neg().magnitude();
|
|
291
|
+
}
|
|
292
|
+
let mantissa = 1n;
|
|
293
|
+
let exponent = -1;
|
|
294
|
+
while (this.mantissa >= mantissa) {
|
|
295
|
+
mantissa *= 10n;
|
|
296
|
+
exponent += 1;
|
|
297
|
+
}
|
|
298
|
+
return exponent + this.exponent;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Returns the remainder when dividing the current Decimal instance by the provided value.
|
|
302
|
+
*
|
|
303
|
+
* @param value The value to divide by.
|
|
304
|
+
* @returns A new Decimal instance representing the remainder.
|
|
305
|
+
*/
|
|
306
|
+
mod(value) {
|
|
307
|
+
value = Decimal.from(value);
|
|
308
|
+
assert(value.neq0(), `Division by zero`);
|
|
309
|
+
if (value.lt0()) {
|
|
310
|
+
return this.mod(value.neg());
|
|
311
|
+
}
|
|
312
|
+
const { mantissa1, mantissa2, exponent } = normalize(this, value);
|
|
313
|
+
const result = mantissa1 % mantissa2;
|
|
314
|
+
return new Decimal(result < 0n ? result + mantissa2 : result, exponent);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Multiplies the current Decimal instance by the provided value.
|
|
318
|
+
*
|
|
319
|
+
* @param value The value to multiply by.
|
|
320
|
+
* @returns A new Decimal instance representing the product.
|
|
321
|
+
*/
|
|
322
|
+
mul(value) {
|
|
323
|
+
value = Decimal.from(value);
|
|
324
|
+
return new Decimal(this.mantissa * value.mantissa, this.exponent + value.exponent);
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Negates the current Decimal instance.
|
|
328
|
+
*
|
|
329
|
+
* @returns A new Decimal instance representing the negated value.
|
|
330
|
+
*/
|
|
331
|
+
neg() {
|
|
332
|
+
return new Decimal(-this.mantissa, this.exponent);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Checks if the current value is not equal to the provided value.
|
|
336
|
+
*
|
|
337
|
+
* @param value The value to compare against.
|
|
338
|
+
* @returns True if the values are not equal, false otherwise.
|
|
339
|
+
*/
|
|
340
|
+
neq(value) {
|
|
341
|
+
return !this.eq(value);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Checks if the current value is not equal to zero.
|
|
345
|
+
*
|
|
346
|
+
* @returns True if the value is not zero, false otherwise.
|
|
347
|
+
*/
|
|
348
|
+
neq0() {
|
|
349
|
+
return !this.eq0();
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Raises the current Decimal instance to the power of the provided integer exponent.
|
|
353
|
+
*
|
|
354
|
+
* @param value The integer exponent to raise to.
|
|
355
|
+
* @returns A new Decimal instance representing the result of the exponentiation.
|
|
356
|
+
*/
|
|
357
|
+
pow(value) {
|
|
358
|
+
assert(Number.isInteger(value), `Exponent must be an integer, got ${value}`);
|
|
359
|
+
if (value === 0) {
|
|
360
|
+
return Decimal.one;
|
|
361
|
+
}
|
|
362
|
+
else if (value === 1) {
|
|
363
|
+
return this;
|
|
364
|
+
}
|
|
365
|
+
else if (value < 0) {
|
|
366
|
+
return this.inv().pow(-value);
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
return new Decimal(this.mantissa ** BigInt(value), this.exponent * value);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Rounds the current value towards the nearest multiple of the specified precision.
|
|
374
|
+
*
|
|
375
|
+
* If the current value is exactly halfway between two multiples of the precision, it is rounded up towards positive infinity.
|
|
376
|
+
*
|
|
377
|
+
* @param precision The precision to round to. Defaults to `Decimal.one`, meaning it rounds to the nearest integer.
|
|
378
|
+
* @returns A new Decimal instance representing the rounded value.
|
|
379
|
+
*/
|
|
380
|
+
round(precision = Decimal.one) {
|
|
381
|
+
return this.add(new Decimal(5n, -1).mul(precision)).floor(precision);
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Returns the sign of the current value as a Decimal instance.
|
|
385
|
+
*
|
|
386
|
+
* @returns A Decimal instance representing the sign: 1 for positive, -1 for negative, and 0 for zero.
|
|
387
|
+
*/
|
|
388
|
+
sign() {
|
|
389
|
+
if (this.gt0()) {
|
|
390
|
+
return Decimal.one;
|
|
391
|
+
}
|
|
392
|
+
if (this.lt0()) {
|
|
393
|
+
return Decimal.minusOne;
|
|
394
|
+
}
|
|
395
|
+
return Decimal.zero;
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Subtracts the provided value from the current Decimal instance.
|
|
399
|
+
*
|
|
400
|
+
* @param value The value to subtract.
|
|
401
|
+
* @returns A new Decimal instance representing the result of the subtraction.
|
|
402
|
+
*/
|
|
403
|
+
sub(value) {
|
|
404
|
+
value = Decimal.from(value);
|
|
405
|
+
const { mantissa1, mantissa2, exponent } = normalize(this, value);
|
|
406
|
+
return new Decimal(mantissa1 - mantissa2, exponent);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Converts the current Decimal instance to a bigint, if it is an integer.
|
|
410
|
+
*
|
|
411
|
+
* Throws if the Decimal instance is not an integer.
|
|
412
|
+
*
|
|
413
|
+
* @returns A bigint representing the integer value of the Decimal instance.
|
|
414
|
+
*/
|
|
415
|
+
toBigInt() {
|
|
416
|
+
assert(this.isInteger(), `Decimal ${this} is not an integer`);
|
|
417
|
+
return this.mantissa * 10n ** BigInt(this.exponent);
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Converts the current Decimal instance to a fixed-point notation string.
|
|
421
|
+
*
|
|
422
|
+
* @param precision The number of decimal places to include in the result.
|
|
423
|
+
* @returns A string representing the Decimal instance in fixed-point notation.
|
|
424
|
+
*/
|
|
425
|
+
toFixed(precision) {
|
|
426
|
+
assert(Number.isInteger(precision) && precision >= 0, `Precision must be a non-negative integer, got ${precision}`);
|
|
427
|
+
if (this.lt0()) {
|
|
428
|
+
return '-' + this.neg().toFixed(precision);
|
|
429
|
+
}
|
|
430
|
+
const value = this.e(precision).round().e(-precision);
|
|
431
|
+
if (value.exponent >= 0) {
|
|
432
|
+
const result = value.mantissa.toString() + '0'.repeat(value.exponent);
|
|
433
|
+
return precision > 0 ? result + '.' + '0'.repeat(precision) : result;
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
const string = value.mantissa.toString().padStart(-value.exponent + 1, '0');
|
|
437
|
+
return string.slice(0, value.exponent) + '.' + string.slice(value.exponent).padEnd(precision, '0');
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Converts the current value to a fraction represented by a numerator and denominator.
|
|
442
|
+
*
|
|
443
|
+
* Simplifies the fraction to its lowest terms.
|
|
444
|
+
*
|
|
445
|
+
* @returns An object with numerator and denominator properties.
|
|
446
|
+
*/
|
|
447
|
+
toFraction() {
|
|
448
|
+
if (this.lt0()) {
|
|
449
|
+
const { numerator, denominator } = this.neg().toFraction();
|
|
450
|
+
return { numerator: -numerator, denominator };
|
|
451
|
+
}
|
|
452
|
+
if (this.exponent >= 0) {
|
|
453
|
+
return { numerator: this.mantissa * 10n ** BigInt(this.exponent), denominator: 1n };
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
const numerator = this.mantissa;
|
|
457
|
+
const denominator = 10n ** BigInt(-this.exponent);
|
|
458
|
+
const divisor = gcd(numerator, denominator);
|
|
459
|
+
return { numerator: numerator / divisor, denominator: denominator / divisor };
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* Converts the current Decimal value to a JSON string.
|
|
464
|
+
*
|
|
465
|
+
* @returns A string representing the Decimal value in JSON format.
|
|
466
|
+
*/
|
|
467
|
+
toJSON() {
|
|
468
|
+
return this.toString();
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Converts the current value to a number.
|
|
472
|
+
*
|
|
473
|
+
* This may lose precision if the Decimal cannot be exactly represented as a number.
|
|
474
|
+
*
|
|
475
|
+
* @returns The number representation of the current Decimal value.
|
|
476
|
+
*/
|
|
477
|
+
toNumber() {
|
|
478
|
+
return Number(this.toString());
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Converts the current value to a string.
|
|
482
|
+
*
|
|
483
|
+
* @returns A string representing the current Decimal value.
|
|
484
|
+
*/
|
|
485
|
+
toString() {
|
|
486
|
+
if (this.lt0()) {
|
|
487
|
+
return '-' + this.neg().toString();
|
|
488
|
+
}
|
|
489
|
+
if (this.exponent >= 0) {
|
|
490
|
+
return this.mantissa.toString() + '0'.repeat(this.exponent);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
const string = this.mantissa.toString().padStart(-this.exponent + 1, '0');
|
|
494
|
+
return string.slice(0, this.exponent) + '.' + string.slice(this.exponent);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* A static constant representing the decimal value -1.
|
|
499
|
+
*/
|
|
500
|
+
static minusOne = new Decimal(-1n);
|
|
501
|
+
/**
|
|
502
|
+
* A static constant representing the decimal value 1.
|
|
503
|
+
*/
|
|
504
|
+
static one = new Decimal(1n);
|
|
505
|
+
/**
|
|
506
|
+
* A static constant representing the decimal value 0.
|
|
507
|
+
*/
|
|
508
|
+
static zero = new Decimal(0n);
|
|
509
|
+
/**
|
|
510
|
+
* Adds multiple values together.
|
|
511
|
+
*
|
|
512
|
+
* @param values An array of values to add.
|
|
513
|
+
* @returns A new Decimal instance representing the sum of the values.
|
|
514
|
+
*/
|
|
515
|
+
static add(...values) {
|
|
516
|
+
return values.reduce((previous, current) => {
|
|
517
|
+
return previous.add(current);
|
|
518
|
+
}, Decimal.zero);
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Divides one value by another.
|
|
522
|
+
*
|
|
523
|
+
* Throws if the resulting value cannot be represented with a fixed number of decimals (like 1/3).
|
|
524
|
+
*
|
|
525
|
+
* If you need to divide by such a value, use the optional `significantDigits` parameter to specify the number of significant digits to use in the result.
|
|
526
|
+
*
|
|
527
|
+
* ```ts
|
|
528
|
+
* Decimal.div(1, 3); // Throws
|
|
529
|
+
* Decimal.div(1, 3, 2); // Returns 0.33
|
|
530
|
+
* ```
|
|
531
|
+
* @param dividend The value to divide.
|
|
532
|
+
* @param divisor The value to divide by.
|
|
533
|
+
* @param significantDigits The number of significant digits to use in the result.
|
|
534
|
+
* @returns A new Decimal instance representing the quotient.
|
|
535
|
+
*/
|
|
536
|
+
static div(dividend, divisor, significantDigits) {
|
|
537
|
+
return Decimal.from(dividend).div(divisor, significantDigits);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Creates a Decimal instance from a string (in standard or scientific notation), a number or a bigint.
|
|
541
|
+
*
|
|
542
|
+
* @param value The value to convert.
|
|
543
|
+
* @returns A Decimal instance representing the provided value.
|
|
544
|
+
*/
|
|
545
|
+
static from(value) {
|
|
546
|
+
if (typeof value === 'string') {
|
|
547
|
+
return this.fromString(value);
|
|
548
|
+
}
|
|
549
|
+
if (typeof value === 'number') {
|
|
550
|
+
return this.fromNumber(value);
|
|
551
|
+
}
|
|
552
|
+
if (typeof value === 'bigint') {
|
|
553
|
+
return this.fromBigInt(value);
|
|
554
|
+
}
|
|
555
|
+
return value;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Creates a Decimal instance from a fraction.
|
|
559
|
+
*
|
|
560
|
+
* Throws if the fraction cannot be represented with a fixed number of decimals.
|
|
561
|
+
*
|
|
562
|
+
* @param numerator The numerator of the fraction.
|
|
563
|
+
* @param denominator The denominator of the fraction.
|
|
564
|
+
* @returns A Decimal instance representing the fraction.
|
|
565
|
+
*/
|
|
566
|
+
static fromFraction({ numerator, denominator }) {
|
|
567
|
+
if (denominator < 0n) {
|
|
568
|
+
numerator = -numerator;
|
|
569
|
+
denominator = -denominator;
|
|
570
|
+
}
|
|
571
|
+
if (numerator < 0n) {
|
|
572
|
+
return this.fromFraction({ numerator: -numerator, denominator }).neg();
|
|
573
|
+
}
|
|
574
|
+
const divisor = gcd(numerator, denominator);
|
|
575
|
+
numerator /= divisor;
|
|
576
|
+
denominator /= divisor;
|
|
577
|
+
let value = denominator;
|
|
578
|
+
let factor = 1n;
|
|
579
|
+
let exponent = 0;
|
|
580
|
+
while (value > 1 && (value % 2n === 0n)) {
|
|
581
|
+
value /= 2n;
|
|
582
|
+
factor *= 5n;
|
|
583
|
+
exponent -= 1;
|
|
584
|
+
}
|
|
585
|
+
while (value > 1 && (value % 5n === 0n)) {
|
|
586
|
+
value /= 5n;
|
|
587
|
+
factor *= 2n;
|
|
588
|
+
exponent -= 1;
|
|
589
|
+
}
|
|
590
|
+
assert(value === 1n, `Fraction ${numerator}/${denominator} cannot be represented with a fixed number of decimals`);
|
|
591
|
+
return new Decimal(numerator * factor, exponent);
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Creates a Decimal instance from a bigint.
|
|
595
|
+
*
|
|
596
|
+
* @param value The bigint value to convert.
|
|
597
|
+
* @returns A Decimal instance representing the provided bigint value.
|
|
598
|
+
*/
|
|
599
|
+
static fromBigInt(value) {
|
|
600
|
+
return new Decimal(value);
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Creates a Decimal instance from a number.
|
|
604
|
+
*
|
|
605
|
+
* @param value The number value to convert.
|
|
606
|
+
* @returns A Decimal instance representing the provided number.
|
|
607
|
+
*/
|
|
608
|
+
static fromNumber(value) {
|
|
609
|
+
if (Number.isInteger(value)) {
|
|
610
|
+
return new Decimal(BigInt(value));
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
return this.fromString(value.toString());
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Creates a Decimal instance from a string (in standard or scientific notation).
|
|
618
|
+
*
|
|
619
|
+
* @param string The string value to convert.
|
|
620
|
+
* @returns A Decimal instance representing the provided string.
|
|
621
|
+
*/
|
|
622
|
+
static fromString(string) {
|
|
623
|
+
if (/^(-?[0-9]+|0x[0-9a-f]+|0o[0-7]+|0b[01]+)$/i.test(string)) {
|
|
624
|
+
return this.fromBigInt(BigInt(string));
|
|
625
|
+
}
|
|
626
|
+
const match = string.match(/^(-?\d+)(?:\.(\d+))?(?:e([+-]?\d+))?$/i);
|
|
627
|
+
assert(match !== null, `Could not parse Decimal from string ${string}`);
|
|
628
|
+
let exponent = 0;
|
|
629
|
+
if (match[3] !== undefined) {
|
|
630
|
+
exponent = Number(match[3]);
|
|
631
|
+
}
|
|
632
|
+
const mantissa = (() => {
|
|
633
|
+
if (match[2] !== undefined) {
|
|
634
|
+
exponent -= match[2].length;
|
|
635
|
+
return match[1] + match[2];
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
assert(match[1] !== undefined);
|
|
639
|
+
return match[1];
|
|
640
|
+
}
|
|
641
|
+
})();
|
|
642
|
+
return new Decimal(BigInt(mantissa), exponent);
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Finds the maximum value among the provided values.
|
|
646
|
+
*
|
|
647
|
+
* @param first The first value to compare.
|
|
648
|
+
* @param values Additional values to compare.
|
|
649
|
+
* @returns A new Decimal instance representing the maximum value.
|
|
650
|
+
*/
|
|
651
|
+
static max(first, ...values) {
|
|
652
|
+
return values.reduce((max, value) => {
|
|
653
|
+
return max.lt(value) ? this.from(value) : max;
|
|
654
|
+
}, this.from(first));
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Finds the minimum value among the provided values.
|
|
658
|
+
*
|
|
659
|
+
* @param first The first value to compare.
|
|
660
|
+
* @param values Additional values to compare.
|
|
661
|
+
* @returns A new Decimal instance representing the minimum value.
|
|
662
|
+
*/
|
|
663
|
+
static min(first, ...values) {
|
|
664
|
+
return values.reduce((min, value) => {
|
|
665
|
+
return min.gt(value) ? this.from(value) : min;
|
|
666
|
+
}, this.from(first));
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Multiplies multiple values together.
|
|
670
|
+
*
|
|
671
|
+
* @param values An array of values to multiply.
|
|
672
|
+
* @returns A new Decimal instance representing the product of the values.
|
|
673
|
+
*/
|
|
674
|
+
static mul(...values) {
|
|
675
|
+
return values.reduce((previous, current) => {
|
|
676
|
+
return previous.mul(current);
|
|
677
|
+
}, Decimal.one);
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Subtracts one value from another.
|
|
681
|
+
*
|
|
682
|
+
* @param minuend The value to subtract from.
|
|
683
|
+
* @param subtrahend The value to subtract.
|
|
684
|
+
* @returns A new Decimal instance representing the result of the subtraction.
|
|
685
|
+
*/
|
|
686
|
+
static sub(minuend, subtrahend) {
|
|
687
|
+
return Decimal.from(minuend).sub(subtrahend);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Calculates the greatest common divisor (GCD) of two values.
|
|
691
|
+
*
|
|
692
|
+
* @param a The first value.
|
|
693
|
+
* @param b The second value.
|
|
694
|
+
* @returns A new Decimal instance representing the GCD of the two values.
|
|
695
|
+
*/
|
|
696
|
+
static gcd(a, b) {
|
|
697
|
+
a = Decimal.from(a);
|
|
698
|
+
b = Decimal.from(b);
|
|
699
|
+
if (a.lt0()) {
|
|
700
|
+
a = a.neg();
|
|
701
|
+
}
|
|
702
|
+
if (b.lt0()) {
|
|
703
|
+
b = b.neg();
|
|
704
|
+
}
|
|
705
|
+
return ((a, b) => {
|
|
706
|
+
while (b.neq0()) {
|
|
707
|
+
const t = b;
|
|
708
|
+
b = a.mod(b);
|
|
709
|
+
a = t;
|
|
710
|
+
}
|
|
711
|
+
return a;
|
|
712
|
+
})(a, b);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
function gcd(a, b) {
|
|
716
|
+
if (a < 0n) {
|
|
717
|
+
a = -a;
|
|
718
|
+
}
|
|
719
|
+
if (b < 0n) {
|
|
720
|
+
b = -b;
|
|
721
|
+
}
|
|
722
|
+
while (b !== 0n) {
|
|
723
|
+
const t = b;
|
|
724
|
+
b = a % b;
|
|
725
|
+
a = t;
|
|
726
|
+
}
|
|
727
|
+
return a;
|
|
728
|
+
}
|
|
729
|
+
function normalize(value1, value2) {
|
|
730
|
+
const exponent = Math.min(value1.exponent, value2.exponent);
|
|
731
|
+
return {
|
|
732
|
+
mantissa1: value1.mantissa * 10n ** BigInt(value1.exponent - exponent),
|
|
733
|
+
mantissa2: value2.mantissa * 10n ** BigInt(value2.exponent - exponent),
|
|
734
|
+
exponent,
|
|
735
|
+
};
|
|
736
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quentinadam/decimal",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "A library for working with arbitrary precision decimal numbers",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Quentin Adam",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/quentinadam/deno-decimal.git"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"exports": "./dist/Decimal.js",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@quentinadam/assert": "^0.1.10"
|
|
19
|
+
}
|
|
20
|
+
}
|