arbitrary-numbers 1.0.0
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/LICENSE +21 -0
- package/README.md +503 -0
- package/dist/index.cjs +1510 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1211 -0
- package/dist/index.d.ts +1211 -0
- package/dist/index.js +1484 -0
- package/dist/index.js.map +1 -0
- package/package.json +70 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A number stored in normalised scientific notation as `coefficient * 10^exponent`,
|
|
3
|
+
* where `1 <= |coefficient| < 10` (or `coefficient === 0`).
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* const n: NormalizedNumber = { coefficient: 1.5, exponent: 3 }; // 1500
|
|
7
|
+
* const z: NormalizedNumber = { coefficient: 0, exponent: 0 }; // 0
|
|
8
|
+
*/
|
|
9
|
+
interface NormalizedNumber {
|
|
10
|
+
/** The significand, always in `[1, 10)` or `0`. */
|
|
11
|
+
coefficient: number;
|
|
12
|
+
/** The power of 10 by which the coefficient is scaled. */
|
|
13
|
+
exponent: number;
|
|
14
|
+
}
|
|
15
|
+
/** The result of a three-way comparison: negative, zero, or positive. */
|
|
16
|
+
type Signum = -1 | 0 | 1;
|
|
17
|
+
/** Remainder after dividing an exponent by 3 - the within-tier offset. */
|
|
18
|
+
type Mod3 = 0 | 1 | 2;
|
|
19
|
+
/**
|
|
20
|
+
* Type of the {@link an} shorthand function.
|
|
21
|
+
*
|
|
22
|
+
* Callable as `an(coefficient, exponent?)` and also has a
|
|
23
|
+
* `.from(value)` static method for plain JS number conversion.
|
|
24
|
+
*/
|
|
25
|
+
interface AnFunction {
|
|
26
|
+
(coefficient: number, exponent?: number): ArbitraryNumber;
|
|
27
|
+
from(value: number): ArbitraryNumber;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A plugin that formats a normalised scientific notation number into a display string.
|
|
32
|
+
*
|
|
33
|
+
* Implement this interface and pass an instance to {@link ArbitraryNumber.toString}
|
|
34
|
+
* to customise how numbers are rendered.
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* const myPlugin: NotationPlugin = {
|
|
38
|
+
* format(coefficient, exponent, decimals) {
|
|
39
|
+
* return `${coefficient.toFixed(decimals)}e${exponent}`;
|
|
40
|
+
* },
|
|
41
|
+
* };
|
|
42
|
+
* number.toString(myPlugin); // "1.50e3"
|
|
43
|
+
*/
|
|
44
|
+
interface NotationPlugin {
|
|
45
|
+
/**
|
|
46
|
+
* Formats a normalised value as a display string.
|
|
47
|
+
*
|
|
48
|
+
* @param coefficient - The significand, always in `[1, 10)` or `0`.
|
|
49
|
+
* @param exponent - The power of 10.
|
|
50
|
+
* @param decimals - Number of decimal places to render.
|
|
51
|
+
* @returns The formatted string.
|
|
52
|
+
*/
|
|
53
|
+
format(coefficient: number, exponent: number, decimals: number): string;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Minimal interface for anything that can map a tier to a suffix string.
|
|
57
|
+
*
|
|
58
|
+
* Used as the `fallback` type on {@link UnitNotation} - only `getSuffix` is
|
|
59
|
+
* ever called, so a simple object literal is enough:
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* const myFallback: SuffixProvider = {
|
|
63
|
+
* getSuffix(tier) { return tier > 10 ? "big" : ""; },
|
|
64
|
+
* };
|
|
65
|
+
*/
|
|
66
|
+
interface SuffixProvider {
|
|
67
|
+
/**
|
|
68
|
+
* Returns the suffix label for the given tier, where `tier = floor(exponent / 3)`.
|
|
69
|
+
*
|
|
70
|
+
* @param tier - The exponent tier (`floor(exponent / 3)`).
|
|
71
|
+
* @returns The suffix string (e.g. `"K"`, `"a"`), or `""` for no suffix.
|
|
72
|
+
*/
|
|
73
|
+
getSuffix(tier: number): string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* A full suffix-based {@link NotationPlugin} - combines formatting and suffix lookup.
|
|
77
|
+
*
|
|
78
|
+
* Extend {@link SuffixNotationBase} rather than implementing this interface directly.
|
|
79
|
+
*/
|
|
80
|
+
interface SuffixNotationPlugin extends NotationPlugin, SuffixProvider {
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Options shared by all suffix-based notation plugins.
|
|
84
|
+
*/
|
|
85
|
+
interface SuffixNotationPluginOptions {
|
|
86
|
+
/**
|
|
87
|
+
* String placed between the formatted number and its suffix.
|
|
88
|
+
*
|
|
89
|
+
* Defaults to `""` for most plugins. {@link UnitNotation} overrides this to `" "`,
|
|
90
|
+
* so `new UnitNotation({ units })` produces `"1.50 K"` without an explicit separator.
|
|
91
|
+
*
|
|
92
|
+
* @example " " -> "1.50 K" | "" -> "1.50K"
|
|
93
|
+
*/
|
|
94
|
+
separator?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* A display label for one tier of magnitude, used by {@link UnitNotation}.
|
|
98
|
+
*
|
|
99
|
+
* Units are stored in a **tier-indexed array** - the array index is the tier number,
|
|
100
|
+
* where `tier = Math.floor(exponent / 3)`. Tier 1 = thousands, tier 2 = millions, etc.
|
|
101
|
+
* The exponent is therefore implicit: `exponent = tier * 3`.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* // In a tier-indexed array, index 2 represents 10^6 (millions):
|
|
105
|
+
* const units: UnitArray = [undefined, { symbol: "K" }, { symbol: "M" }];
|
|
106
|
+
*/
|
|
107
|
+
interface Unit {
|
|
108
|
+
/** Short symbol displayed after the number, e.g. `"M"`. */
|
|
109
|
+
symbol: string;
|
|
110
|
+
/** Optional full name, e.g. `"Million"`. Used for display purposes only. */
|
|
111
|
+
name?: string;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A tier-indexed array of units for use with {@link UnitNotation}.
|
|
115
|
+
*
|
|
116
|
+
* The array index equals the tier number (`Math.floor(exponent / 3)`).
|
|
117
|
+
* `undefined` at an index signals "no unit for this tier" - the fallback plugin
|
|
118
|
+
* (or plain fixed-point rendering) will be used instead.
|
|
119
|
+
*
|
|
120
|
+
* Sparse arrays are valid: unset indices are implicitly `undefined`.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* const myUnits: UnitArray = [
|
|
124
|
+
* undefined, // tier 0: < 1000, no suffix
|
|
125
|
+
* { symbol: "K" }, // tier 1: thousands
|
|
126
|
+
* { symbol: "M" }, // tier 2: millions
|
|
127
|
+
* ];
|
|
128
|
+
*/
|
|
129
|
+
type UnitArray = ReadonlyArray<Unit | undefined>;
|
|
130
|
+
/**
|
|
131
|
+
* Options for constructing an {@link AlphabetNotation} instance.
|
|
132
|
+
*/
|
|
133
|
+
interface AlphabetNotationOptions extends SuffixNotationPluginOptions {
|
|
134
|
+
/**
|
|
135
|
+
* The ordered symbol set used to build multi-character suffixes.
|
|
136
|
+
*
|
|
137
|
+
* The algorithm is base-N positional: tier 1 = `alphabet[0]`, tier N = `alphabet[N-1]`,
|
|
138
|
+
* tier N+1 = `alphabet[0]+alphabet[0]`, and so on - identical to Excel column naming
|
|
139
|
+
* when `alphabet` is `"ABCDEFGHIJKLMNOPQRSTUVWXYZ"`.
|
|
140
|
+
*
|
|
141
|
+
* @default `"abcdefghijklmnopqrstuvwxyz"`
|
|
142
|
+
*/
|
|
143
|
+
alphabet?: string;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Options for constructing a {@link UnitNotation} instance.
|
|
147
|
+
*/
|
|
148
|
+
interface UnitNotationOptions extends SuffixNotationPluginOptions {
|
|
149
|
+
/**
|
|
150
|
+
* Tier-indexed array of units. The array index equals the tier number
|
|
151
|
+
* (`Math.floor(exponent / 3)`). Use `undefined` at an index to signal
|
|
152
|
+
* "no unit for this tier" - the fallback plugin will be used instead.
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* // index 0 = tier 0 (< 1000, no suffix)
|
|
156
|
+
* // index 1 = tier 1 (thousands) -> "K"
|
|
157
|
+
* // index 2 = tier 2 (millions) -> "M"
|
|
158
|
+
*/
|
|
159
|
+
units: UnitArray;
|
|
160
|
+
/**
|
|
161
|
+
* Suffix provider used when no unit is defined for a tier.
|
|
162
|
+
*
|
|
163
|
+
* Only {@link SuffixProvider.getSuffix} is called - the number and separator are
|
|
164
|
+
* still formatted by this `UnitNotation` instance, keeping presentation consistent.
|
|
165
|
+
* A simple object literal with just `getSuffix` is sufficient; a full plugin is not required.
|
|
166
|
+
*
|
|
167
|
+
* When omitted, tiers with no unit are rendered as a plain fixed-point number (no suffix).
|
|
168
|
+
*
|
|
169
|
+
* @default undefined
|
|
170
|
+
*/
|
|
171
|
+
fallback?: SuffixProvider;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* An immutable number with effectively unlimited range, stored as `coefficient * 10^exponent`
|
|
176
|
+
* in normalised scientific notation.
|
|
177
|
+
*
|
|
178
|
+
* The coefficient is always in `[1, 10)` (or `0`). Addition short-circuits when the exponent
|
|
179
|
+
* difference between operands exceeds {@link PrecisionCutoff} - the smaller value is below
|
|
180
|
+
* the precision floor of the larger and is silently discarded.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* const a = new ArbitraryNumber(1.5, 3); // 1,500
|
|
184
|
+
* const b = new ArbitraryNumber(2.5, 3); // 2,500
|
|
185
|
+
* a.add(b).toString(); // "4.00e+3"
|
|
186
|
+
* a.mul(b).toString(); // "3.75e+6"
|
|
187
|
+
*/
|
|
188
|
+
declare class ArbitraryNumber implements NormalizedNumber {
|
|
189
|
+
/** The significand, always in `[1, 10)` or `0`. */
|
|
190
|
+
readonly coefficient: number;
|
|
191
|
+
/** The power of 10 by which the coefficient is scaled. */
|
|
192
|
+
readonly exponent: number;
|
|
193
|
+
/**
|
|
194
|
+
* Precision cutoff: exponent-difference threshold below which the smaller operand
|
|
195
|
+
* is negligible and silently skipped during addition/subtraction.
|
|
196
|
+
*
|
|
197
|
+
* When |exponent_diff| > PrecisionCutoff, the smaller operand contributes less than
|
|
198
|
+
* 10^-PrecisionCutoff of the result - below float64 coefficient precision for the default of 15.
|
|
199
|
+
*
|
|
200
|
+
* Default: 15 (matches float64 coefficient precision of ~15.95 significant digits).
|
|
201
|
+
* Game patterns: diffs 0-8 (exact), prestige 15-25 (loss <0.0001%), idle 20-50 (~0.1% loss).
|
|
202
|
+
*
|
|
203
|
+
* Override globally via assignment, or use {@link withPrecision} for a scoped block.
|
|
204
|
+
*/
|
|
205
|
+
static PrecisionCutoff: number;
|
|
206
|
+
/** The additive identity: `0`. */
|
|
207
|
+
static readonly Zero: ArbitraryNumber;
|
|
208
|
+
/** The multiplicative identity: `1`. */
|
|
209
|
+
static readonly One: ArbitraryNumber;
|
|
210
|
+
/** `10`. */
|
|
211
|
+
static readonly Ten: ArbitraryNumber;
|
|
212
|
+
/**
|
|
213
|
+
* Creates an `ArbitraryNumber` from a plain JavaScript `number`.
|
|
214
|
+
*
|
|
215
|
+
* Prefer this over `new ArbitraryNumber(value, 0)` when working with
|
|
216
|
+
* ordinary numeric literals - it reads clearly at the call site and
|
|
217
|
+
* validates the input.
|
|
218
|
+
*
|
|
219
|
+
* @example
|
|
220
|
+
* ArbitraryNumber.from(1500); // { coefficient: 1.5, exponent: 3 }
|
|
221
|
+
* ArbitraryNumber.from(0.005); // { coefficient: 5, exponent: -3 }
|
|
222
|
+
* ArbitraryNumber.from(0); // ArbitraryNumber.Zero
|
|
223
|
+
*
|
|
224
|
+
* @param value - Any finite number.
|
|
225
|
+
* @throws `"ArbitraryNumber.from: value must be finite"` for `NaN`, `Infinity`, or `-Infinity`.
|
|
226
|
+
*/
|
|
227
|
+
static from(value: number): ArbitraryNumber;
|
|
228
|
+
/**
|
|
229
|
+
* Constructs a new `ArbitraryNumber` and immediately normalises it so that
|
|
230
|
+
* `1 <= |coefficient| < 10` (or `coefficient === 0`).
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* new ArbitraryNumber(15, 3); // stored as { coefficient: 1.5, exponent: 4 }
|
|
234
|
+
*
|
|
235
|
+
* @param coefficient - The significand. Must be a finite number; will be normalised.
|
|
236
|
+
* @param exponent - The power of 10. Must be a finite number.
|
|
237
|
+
* @throws `"ArbitraryNumber: coefficient must be finite"` for `NaN`, `Infinity`, or `-Infinity`.
|
|
238
|
+
* @throws `"ArbitraryNumber: exponent must be finite"` for non-finite exponents.
|
|
239
|
+
*/
|
|
240
|
+
constructor(coefficient: number, exponent: number);
|
|
241
|
+
/**
|
|
242
|
+
* @internal Fast-path factory for already-normalised values.
|
|
243
|
+
*
|
|
244
|
+
* Uses Object.create() to bypass the constructor (zero normalisation cost).
|
|
245
|
+
* Only valid when |coefficient| is already in [1, 10) and exponent is correct.
|
|
246
|
+
* Do NOT use for unnormalised inputs - call new ArbitraryNumber(c, e) instead.
|
|
247
|
+
*/
|
|
248
|
+
private static createNormalized;
|
|
249
|
+
/**
|
|
250
|
+
* Normalises raw (coefficient, exponent) into a new ArbitraryNumber.
|
|
251
|
+
*
|
|
252
|
+
* INVARIANT: all ArbitraryNumber values must have coefficient in [1, 10).
|
|
253
|
+
* Algorithm: shift = floor(log10(|c|)); scale c by 10^-shift; adjust exponent.
|
|
254
|
+
* Cost: one Math.log10 call (~3-4 ns). This is the fundamental cost floor - logarithm
|
|
255
|
+
* is the only way to compute magnitude in JavaScript.
|
|
256
|
+
*/
|
|
257
|
+
private static normalizeFrom;
|
|
258
|
+
/**
|
|
259
|
+
* Returns `this + other`.
|
|
260
|
+
*
|
|
261
|
+
* When the exponent difference exceeds {@link PrecisionCutoff}, the smaller
|
|
262
|
+
* operand has no effect and the larger is returned as-is.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* new ArbitraryNumber(1.5, 3).add(new ArbitraryNumber(2.5, 3)); // 4*10^3
|
|
266
|
+
*/
|
|
267
|
+
add(other: ArbitraryNumber): ArbitraryNumber;
|
|
268
|
+
/**
|
|
269
|
+
* Returns `this - other`.
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* new ArbitraryNumber(3.5, 3).sub(new ArbitraryNumber(1.5, 3)); // 2*10^3
|
|
273
|
+
*/
|
|
274
|
+
sub(other: ArbitraryNumber): ArbitraryNumber;
|
|
275
|
+
/**
|
|
276
|
+
* Returns `this * other`.
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* new ArbitraryNumber(2, 3).mul(new ArbitraryNumber(3, 4)); // 6*10^7
|
|
280
|
+
*/
|
|
281
|
+
mul(other: ArbitraryNumber): ArbitraryNumber;
|
|
282
|
+
/**
|
|
283
|
+
* Returns `this / other`.
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* new ArbitraryNumber(6, 7).div(new ArbitraryNumber(3, 4)); // 2*10^3
|
|
287
|
+
*
|
|
288
|
+
* @throws `"Division by zero"` when `other` is zero.
|
|
289
|
+
*/
|
|
290
|
+
div(other: ArbitraryNumber): ArbitraryNumber;
|
|
291
|
+
/**
|
|
292
|
+
* Returns the arithmetic negation of this number (`-this`).
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* new ArbitraryNumber(1.5, 3).negate(); // -1.5*10^3
|
|
296
|
+
*/
|
|
297
|
+
negate(): ArbitraryNumber;
|
|
298
|
+
/**
|
|
299
|
+
* Returns the absolute value of this number (`|this|`).
|
|
300
|
+
*
|
|
301
|
+
* Returns `this` unchanged when the number is already non-negative.
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* new ArbitraryNumber(-1.5, 3).abs(); // 1.5*10^3
|
|
305
|
+
*/
|
|
306
|
+
abs(): ArbitraryNumber;
|
|
307
|
+
/**
|
|
308
|
+
* Returns `this^n`.
|
|
309
|
+
*
|
|
310
|
+
* Supports integer, fractional, and negative exponents.
|
|
311
|
+
* `x^0` always returns {@link One}, including `0^0` (by convention).
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* new ArbitraryNumber(2, 3).pow(2); // 4*10^6
|
|
315
|
+
* new ArbitraryNumber(2, 0).pow(-1); // 5*10^-1 (= 0.5)
|
|
316
|
+
*
|
|
317
|
+
* @param n - The exponent to raise this number to.
|
|
318
|
+
* @throws `"Zero cannot be raised to a negative power"` when this is zero and `n < 0`.
|
|
319
|
+
*/
|
|
320
|
+
pow(n: number): ArbitraryNumber;
|
|
321
|
+
/**
|
|
322
|
+
* Fused multiply-add: `(this * multiplier) + addend`.
|
|
323
|
+
*
|
|
324
|
+
* Faster than `.mul(multiplier).add(addend)` because it avoids allocating an
|
|
325
|
+
* intermediate ArbitraryNumber for the product. One normalisation pass total.
|
|
326
|
+
*
|
|
327
|
+
* Common pattern - prestige loop: `value = value.mulAdd(prestigeMultiplier, prestigeBoost)`
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* // Equivalent to value.mul(mult).add(boost) but ~35-50% faster
|
|
331
|
+
* const prestiged = currentValue.mulAdd(multiplier, boost);
|
|
332
|
+
*/
|
|
333
|
+
mulAdd(multiplier: ArbitraryNumber, addend: ArbitraryNumber): ArbitraryNumber;
|
|
334
|
+
/**
|
|
335
|
+
* Fused add-multiply: `(this + addend) * multiplier`.
|
|
336
|
+
*
|
|
337
|
+
* Faster than `.add(addend).mul(multiplier)` because it avoids allocating an
|
|
338
|
+
* intermediate ArbitraryNumber for the sum. One normalisation pass total.
|
|
339
|
+
*
|
|
340
|
+
* Common pattern - upgrade calculation: `newValue = baseValue.addMul(bonus, multiplier)`
|
|
341
|
+
*
|
|
342
|
+
* @example
|
|
343
|
+
* // Equivalent to base.add(bonus).mul(multiplier) but ~20-25% faster
|
|
344
|
+
* const upgraded = baseValue.addMul(bonus, multiplier);
|
|
345
|
+
*/
|
|
346
|
+
addMul(addend: ArbitraryNumber, multiplier: ArbitraryNumber): ArbitraryNumber;
|
|
347
|
+
/**
|
|
348
|
+
* Fused multiply-subtract: `(this * multiplier) - subtrahend`.
|
|
349
|
+
*
|
|
350
|
+
* Avoids one intermediate allocation vs `.mul(multiplier).sub(subtrahend)`.
|
|
351
|
+
*
|
|
352
|
+
* Common pattern - resource drain: `income.mulSub(rate, upkeepCost)`
|
|
353
|
+
*/
|
|
354
|
+
mulSub(multiplier: ArbitraryNumber, subtrahend: ArbitraryNumber): ArbitraryNumber;
|
|
355
|
+
/**
|
|
356
|
+
* Fused subtract-multiply: `(this - subtrahend) * multiplier`.
|
|
357
|
+
*
|
|
358
|
+
* Avoids one intermediate allocation vs `.sub(subtrahend).mul(multiplier)`.
|
|
359
|
+
*
|
|
360
|
+
* Common pattern - upgrade after penalty: `health.subMul(damage, multiplier)`
|
|
361
|
+
*/
|
|
362
|
+
subMul(subtrahend: ArbitraryNumber, multiplier: ArbitraryNumber): ArbitraryNumber;
|
|
363
|
+
/**
|
|
364
|
+
* Fused divide-add: `(this / divisor) + addend`.
|
|
365
|
+
*
|
|
366
|
+
* Avoids one intermediate allocation vs `.div(divisor).add(addend)`.
|
|
367
|
+
*
|
|
368
|
+
* Common pattern - efficiency bonus: `damage.divAdd(armor, flat)`
|
|
369
|
+
*
|
|
370
|
+
* @throws `"Division by zero"` when divisor is zero.
|
|
371
|
+
*/
|
|
372
|
+
divAdd(divisor: ArbitraryNumber, addend: ArbitraryNumber): ArbitraryNumber;
|
|
373
|
+
/**
|
|
374
|
+
* Efficiently sums an array of ArbitraryNumbers in a single normalisation pass.
|
|
375
|
+
*
|
|
376
|
+
* **Why it's fast:** standard chained `.add()` normalises after every element (N log10 calls).
|
|
377
|
+
* `sumArray` aligns all coefficients to the largest exponent (pivot), sums them,
|
|
378
|
+
* then normalises once - regardless of array size.
|
|
379
|
+
*
|
|
380
|
+
* For 50 elements: chained add ~ 50 log10 calls + 50 allocations;
|
|
381
|
+
* sumArray ~ 50 divisions + 1 log10 call + 1 allocation -> ~9* faster.
|
|
382
|
+
*
|
|
383
|
+
* Common pattern - income aggregation: `total = ArbitraryNumber.sumArray(incomeSourcesPerTick)`
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* const total = ArbitraryNumber.sumArray(incomeSources); // far faster than .reduce((a, b) => a.add(b))
|
|
387
|
+
*
|
|
388
|
+
* @param numbers - Array to sum. Empty array returns {@link Zero}. Single element returned as-is.
|
|
389
|
+
*/
|
|
390
|
+
static sumArray(numbers: ArbitraryNumber[]): ArbitraryNumber;
|
|
391
|
+
/**
|
|
392
|
+
* Compares this number to `other`.
|
|
393
|
+
*
|
|
394
|
+
* @returns `1` if `this > other`, `-1` if `this < other`, `0` if equal.
|
|
395
|
+
*
|
|
396
|
+
* @example
|
|
397
|
+
* new ArbitraryNumber(1, 4).compareTo(new ArbitraryNumber(9, 3)); // 1 (10000 > 9000)
|
|
398
|
+
* new ArbitraryNumber(-1, 4).compareTo(new ArbitraryNumber(1, 3)); // -1 (-10000 < 1000)
|
|
399
|
+
*/
|
|
400
|
+
compareTo(other: ArbitraryNumber): number;
|
|
401
|
+
/** Returns `true` if `this > other`. */
|
|
402
|
+
greaterThan(other: ArbitraryNumber): boolean;
|
|
403
|
+
/** Returns `true` if `this < other`. */
|
|
404
|
+
lessThan(other: ArbitraryNumber): boolean;
|
|
405
|
+
/** Returns `true` if `this >= other`. */
|
|
406
|
+
greaterThanOrEqual(other: ArbitraryNumber): boolean;
|
|
407
|
+
/** Returns `true` if `this <= other`. */
|
|
408
|
+
lessThanOrEqual(other: ArbitraryNumber): boolean;
|
|
409
|
+
/** Returns `true` if `this === other` in value. */
|
|
410
|
+
equals(other: ArbitraryNumber): boolean;
|
|
411
|
+
/**
|
|
412
|
+
* Returns the largest integer less than or equal to this number (floor toward -Infinity).
|
|
413
|
+
*
|
|
414
|
+
* Numbers with `exponent >= PrecisionCutoff` are already integers at that scale
|
|
415
|
+
* and are returned unchanged.
|
|
416
|
+
*
|
|
417
|
+
* @example
|
|
418
|
+
* new ArbitraryNumber(1.7, 0).floor(); // 1
|
|
419
|
+
* new ArbitraryNumber(-1.7, 0).floor(); // -2
|
|
420
|
+
*/
|
|
421
|
+
floor(): ArbitraryNumber;
|
|
422
|
+
/**
|
|
423
|
+
* Returns the smallest integer greater than or equal to this number (ceil toward +Infinity).
|
|
424
|
+
*
|
|
425
|
+
* Numbers with `exponent >= PrecisionCutoff` are already integers at that scale
|
|
426
|
+
* and are returned unchanged.
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* new ArbitraryNumber(1.2, 0).ceil(); // 2
|
|
430
|
+
* new ArbitraryNumber(-1.7, 0).ceil(); // -1
|
|
431
|
+
*/
|
|
432
|
+
ceil(): ArbitraryNumber;
|
|
433
|
+
/**
|
|
434
|
+
* Clamps `value` to the inclusive range `[min, max]`.
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* ArbitraryNumber.clamp(new ArbitraryNumber(5, 2), new ArbitraryNumber(1, 3), new ArbitraryNumber(2, 3)); // 1*10^3 (500 clamped to [1000, 2000])
|
|
438
|
+
*
|
|
439
|
+
* @param value - The value to clamp.
|
|
440
|
+
* @param min - Lower bound (inclusive).
|
|
441
|
+
* @param max - Upper bound (inclusive).
|
|
442
|
+
*/
|
|
443
|
+
static clamp(value: ArbitraryNumber, min: ArbitraryNumber, max: ArbitraryNumber): ArbitraryNumber;
|
|
444
|
+
/**
|
|
445
|
+
* Returns the smaller of `a` and `b`.
|
|
446
|
+
* @example ArbitraryNumber.min(a, b)
|
|
447
|
+
*/
|
|
448
|
+
static min(a: ArbitraryNumber, b: ArbitraryNumber): ArbitraryNumber;
|
|
449
|
+
/**
|
|
450
|
+
* Returns the larger of `a` and `b`.
|
|
451
|
+
* @example ArbitraryNumber.max(a, b)
|
|
452
|
+
*/
|
|
453
|
+
static max(a: ArbitraryNumber, b: ArbitraryNumber): ArbitraryNumber;
|
|
454
|
+
/**
|
|
455
|
+
* Linear interpolation: `a + (b - a) * t` where `t in [0, 1]` is a plain number.
|
|
456
|
+
*
|
|
457
|
+
* Used for smooth animations and tweening in game UIs.
|
|
458
|
+
* `t = 0` returns `a`; `t = 1` returns `b`.
|
|
459
|
+
*
|
|
460
|
+
* @param t - Interpolation factor as a plain `number`. Values outside [0, 1] are allowed (extrapolation).
|
|
461
|
+
* @example
|
|
462
|
+
* ArbitraryNumber.lerp(an(100), an(200), 0.5); // 150
|
|
463
|
+
*/
|
|
464
|
+
static lerp(a: ArbitraryNumber, b: ArbitraryNumber, t: number): ArbitraryNumber;
|
|
465
|
+
/**
|
|
466
|
+
* Runs `fn` with `PrecisionCutoff` temporarily set to `cutoff`, then restores the previous value.
|
|
467
|
+
*
|
|
468
|
+
* Useful when one section of code needs different precision than the rest.
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* // Run financial calculation with higher precision
|
|
472
|
+
* const result = ArbitraryNumber.withPrecision(50, () => a.add(b));
|
|
473
|
+
*/
|
|
474
|
+
static withPrecision<T>(cutoff: number, fn: () => T): T;
|
|
475
|
+
/**
|
|
476
|
+
* Returns `log10(this)` as a plain JavaScript `number`.
|
|
477
|
+
*
|
|
478
|
+
* Because the number is stored as `c * 10^e`, this is computed exactly as
|
|
479
|
+
* `log10(c) + e` - no precision loss from the exponent.
|
|
480
|
+
*
|
|
481
|
+
* @example
|
|
482
|
+
* new ArbitraryNumber(1, 6).log10(); // 6
|
|
483
|
+
* new ArbitraryNumber(1.5, 3).log10(); // log10(1.5) + 3 ~ 3.176
|
|
484
|
+
*
|
|
485
|
+
* @throws `"Logarithm of zero is undefined"` when this is zero.
|
|
486
|
+
* @throws `"Logarithm of a negative number is undefined"` when this is negative.
|
|
487
|
+
*/
|
|
488
|
+
log10(): number;
|
|
489
|
+
/**
|
|
490
|
+
* Returns √this.
|
|
491
|
+
*
|
|
492
|
+
* Computed as pure coefficient math - no `Math.log10` call. Cost: one `Math.sqrt`.
|
|
493
|
+
* For even exponents: `sqrt(c) * 10^(e/2)`.
|
|
494
|
+
* For odd exponents: `sqrt(c * 10) * 10^((e-1)/2)`.
|
|
495
|
+
*
|
|
496
|
+
* @throws `"Square root of negative number"` when this is negative.
|
|
497
|
+
* @example
|
|
498
|
+
* new ArbitraryNumber(4, 0).sqrt(); // 2
|
|
499
|
+
* new ArbitraryNumber(1, 4).sqrt(); // 1*10^2 (= 100)
|
|
500
|
+
*/
|
|
501
|
+
sqrt(): ArbitraryNumber;
|
|
502
|
+
/**
|
|
503
|
+
* Returns the nearest integer value (rounds half-up).
|
|
504
|
+
*
|
|
505
|
+
* Numbers with `exponent >= PrecisionCutoff` are already integers at that scale
|
|
506
|
+
* and are returned unchanged.
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* new ArbitraryNumber(1.5, 0).round(); // 2
|
|
510
|
+
* new ArbitraryNumber(1.4, 0).round(); // 1
|
|
511
|
+
* new ArbitraryNumber(-1.5, 0).round(); // -1 (half-up toward positive infinity)
|
|
512
|
+
*/
|
|
513
|
+
round(): ArbitraryNumber;
|
|
514
|
+
/**
|
|
515
|
+
* Returns `1` if positive, `-1` if negative, `0` if zero.
|
|
516
|
+
*
|
|
517
|
+
* @example
|
|
518
|
+
* new ArbitraryNumber(1.5, 3).sign(); // 1
|
|
519
|
+
* new ArbitraryNumber(-1.5, 3).sign(); // -1
|
|
520
|
+
* ArbitraryNumber.Zero.sign(); // 0
|
|
521
|
+
*/
|
|
522
|
+
sign(): Signum;
|
|
523
|
+
/**
|
|
524
|
+
* Converts to a plain JavaScript `number`.
|
|
525
|
+
*
|
|
526
|
+
* Precision is limited to float64 (~15 significant digits).
|
|
527
|
+
* Returns `Infinity` for exponents beyond the float64 range (>=308).
|
|
528
|
+
* Returns `0` for exponents below the float64 range (<=-324).
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* new ArbitraryNumber(1.5, 3).toNumber(); // 1500
|
|
532
|
+
* new ArbitraryNumber(1, 400).toNumber(); // Infinity
|
|
533
|
+
*/
|
|
534
|
+
toNumber(): number;
|
|
535
|
+
/** Returns `true` when this number is zero. */
|
|
536
|
+
isZero(): boolean;
|
|
537
|
+
/** Returns `true` when this number is strictly positive. */
|
|
538
|
+
isPositive(): boolean;
|
|
539
|
+
/** Returns `true` when this number is strictly negative. */
|
|
540
|
+
isNegative(): boolean;
|
|
541
|
+
/**
|
|
542
|
+
* Returns `true` when this number has no fractional part.
|
|
543
|
+
* Numbers with `exponent >= PrecisionCutoff` are always considered integers.
|
|
544
|
+
*/
|
|
545
|
+
isInteger(): boolean;
|
|
546
|
+
/**
|
|
547
|
+
* Formats this number as a string using the given notation plugin.
|
|
548
|
+
*
|
|
549
|
+
* Defaults to {@link scientificNotation} when no plugin is provided.
|
|
550
|
+
* `decimals` controls the number of decimal places passed to the plugin and defaults to `2`.
|
|
551
|
+
*
|
|
552
|
+
* @example
|
|
553
|
+
* new ArbitraryNumber(1.5, 3).toString(); // "1.50e+3"
|
|
554
|
+
* new ArbitraryNumber(1.5, 3).toString(unitNotation); // "1.50 K"
|
|
555
|
+
* new ArbitraryNumber(1.5, 3).toString(unitNotation, 4); // "1.5000 K"
|
|
556
|
+
*
|
|
557
|
+
* @param notation - The formatting plugin to use.
|
|
558
|
+
* @param decimals - Number of decimal places to render. Defaults to `2`.
|
|
559
|
+
*/
|
|
560
|
+
toString(notation?: NotationPlugin, decimals?: number): string;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Base class for all errors thrown by the arbitrary-numbers library.
|
|
565
|
+
*
|
|
566
|
+
* Catch this to handle any error from the library regardless of type.
|
|
567
|
+
*/
|
|
568
|
+
declare class ArbitraryNumberError extends Error {
|
|
569
|
+
constructor(message: string);
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Thrown when invalid input is provided to a constructor or factory method.
|
|
573
|
+
*
|
|
574
|
+
* @example
|
|
575
|
+
* try {
|
|
576
|
+
* ArbitraryNumber.from(Infinity);
|
|
577
|
+
* } catch (e) {
|
|
578
|
+
* if (e instanceof ArbitraryNumberInputError) {
|
|
579
|
+
* console.log(e.value); // Infinity
|
|
580
|
+
* }
|
|
581
|
+
* }
|
|
582
|
+
*/
|
|
583
|
+
declare class ArbitraryNumberInputError extends ArbitraryNumberError {
|
|
584
|
+
/** The invalid value that caused the error. */
|
|
585
|
+
readonly value: number | string;
|
|
586
|
+
constructor(message: string, value: number | string);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Thrown when a mathematical operation is undefined for the given operands.
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* try {
|
|
593
|
+
* an(10).div(an(0));
|
|
594
|
+
* } catch (e) {
|
|
595
|
+
* if (e instanceof ArbitraryNumberDomainError) {
|
|
596
|
+
* console.log(e.context); // { dividend: 10 }
|
|
597
|
+
* }
|
|
598
|
+
* }
|
|
599
|
+
*/
|
|
600
|
+
declare class ArbitraryNumberDomainError extends ArbitraryNumberError {
|
|
601
|
+
/** The operands involved in the failed operation, as plain numbers. */
|
|
602
|
+
readonly context: Record<string, number>;
|
|
603
|
+
constructor(message: string, context: Record<string, number>);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
declare const an: AnFunction;
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Fluent builder for multi-step `ArbitraryNumber` expressions.
|
|
610
|
+
*
|
|
611
|
+
* Each method mutates the accumulated value in-place and returns `this`,
|
|
612
|
+
* enabling a readable left-to-right pipeline with no expression-tree
|
|
613
|
+
* overhead. Every step delegates directly to the underlying
|
|
614
|
+
* `ArbitraryNumber` method - fused variants (`mulAdd`, `mulSub`, etc.)
|
|
615
|
+
* are available here too.
|
|
616
|
+
*
|
|
617
|
+
* @example
|
|
618
|
+
* // Damage formula: ((base - armour) * mult) + flatBonus
|
|
619
|
+
* const result = chain(base)
|
|
620
|
+
* .subMul(armour, multiplier)
|
|
621
|
+
* .add(flatBonus)
|
|
622
|
+
* .done();
|
|
623
|
+
*
|
|
624
|
+
* @remarks
|
|
625
|
+
* No deferred execution - each call runs immediately. Overhead vs direct
|
|
626
|
+
* method chaining is a single extra method call + `return this` per step
|
|
627
|
+
* (~1-2 ns). Use fused ops for hot inner loops; the builder is optimised
|
|
628
|
+
* for readability in complex multi-step formulas.
|
|
629
|
+
*/
|
|
630
|
+
declare class AnChain {
|
|
631
|
+
private value;
|
|
632
|
+
private constructor();
|
|
633
|
+
/** Creates an `AnChain` from an `ArbitraryNumber` or a plain `number`. */
|
|
634
|
+
static from(value: ArbitraryNumber | number): AnChain;
|
|
635
|
+
/** Adds `other` to the accumulated value. */
|
|
636
|
+
add(other: ArbitraryNumber): this;
|
|
637
|
+
/** Subtracts `other` from the accumulated value. */
|
|
638
|
+
sub(other: ArbitraryNumber): this;
|
|
639
|
+
/** Multiplies the accumulated value by `other`. */
|
|
640
|
+
mul(other: ArbitraryNumber): this;
|
|
641
|
+
/** Divides the accumulated value by `other`. */
|
|
642
|
+
div(other: ArbitraryNumber): this;
|
|
643
|
+
/** Raises the accumulated value to `exp`. */
|
|
644
|
+
pow(exp: number): this;
|
|
645
|
+
/** `(this * mult) + add` */
|
|
646
|
+
mulAdd(mult: ArbitraryNumber, add: ArbitraryNumber): this;
|
|
647
|
+
/** `(this + add) * mult` */
|
|
648
|
+
addMul(add: ArbitraryNumber, mult: ArbitraryNumber): this;
|
|
649
|
+
/** `(this * mult) - sub` */
|
|
650
|
+
mulSub(mult: ArbitraryNumber, sub: ArbitraryNumber): this;
|
|
651
|
+
/** `(this - sub) * mult` */
|
|
652
|
+
subMul(sub: ArbitraryNumber, mult: ArbitraryNumber): this;
|
|
653
|
+
/** `(this / div) + add` */
|
|
654
|
+
divAdd(div: ArbitraryNumber, add: ArbitraryNumber): this;
|
|
655
|
+
/** Absolute value. */
|
|
656
|
+
abs(): this;
|
|
657
|
+
/** Negates the accumulated value. */
|
|
658
|
+
neg(): this;
|
|
659
|
+
/** Square root of the accumulated value. */
|
|
660
|
+
sqrt(): this;
|
|
661
|
+
/** Rounds down to the nearest integer. */
|
|
662
|
+
floor(): this;
|
|
663
|
+
/** Rounds up to the nearest integer. */
|
|
664
|
+
ceil(): this;
|
|
665
|
+
/** Rounds to the nearest integer. */
|
|
666
|
+
round(): this;
|
|
667
|
+
/** Returns the accumulated `ArbitraryNumber` result. */
|
|
668
|
+
done(): ArbitraryNumber;
|
|
669
|
+
}
|
|
670
|
+
/**
|
|
671
|
+
* Creates an {@link AnChain} builder starting from `value`.
|
|
672
|
+
*
|
|
673
|
+
* Mirrors the `an` factory shorthand.
|
|
674
|
+
*
|
|
675
|
+
* @example
|
|
676
|
+
* import { chain, an } from 'arbitrary-numbers';
|
|
677
|
+
*
|
|
678
|
+
* const result = chain(an(1.5, 6))
|
|
679
|
+
* .mulAdd(multiplier, bonus)
|
|
680
|
+
* .floor()
|
|
681
|
+
* .done();
|
|
682
|
+
*/
|
|
683
|
+
declare function chain(value: ArbitraryNumber | number): AnChain;
|
|
684
|
+
|
|
685
|
+
type FormulaStep = (value: ArbitraryNumber) => ArbitraryNumber;
|
|
686
|
+
/**
|
|
687
|
+
* A reusable, named pipeline of `ArbitraryNumber` operations.
|
|
688
|
+
*
|
|
689
|
+
* Unlike {@link AnChain}, which executes each step immediately against an
|
|
690
|
+
* accumulated value, `AnFormula` stores the operations as a list of closures
|
|
691
|
+
* and runs them only when {@link apply} is called. The same formula can be
|
|
692
|
+
* applied to any number of values without re-defining the pipeline.
|
|
693
|
+
*
|
|
694
|
+
* Each builder method returns a **new** `AnFormula` - the original is
|
|
695
|
+
* unchanged. This makes branching and composition safe:
|
|
696
|
+
*
|
|
697
|
+
* @example
|
|
698
|
+
* const base = formula().mul(an(2));
|
|
699
|
+
* const withFloor = base.floor(); // new formula - base is unchanged
|
|
700
|
+
* const withCeil = base.ceil(); // another branch from base
|
|
701
|
+
*
|
|
702
|
+
* @example
|
|
703
|
+
* // Define once, apply to many values
|
|
704
|
+
* const armorReduction = formula("Armor Reduction")
|
|
705
|
+
* .subMul(armor, an(0.75))
|
|
706
|
+
* .floor();
|
|
707
|
+
*
|
|
708
|
+
* const physDamage = armorReduction.apply(physBase);
|
|
709
|
+
* const magDamage = armorReduction.apply(magBase);
|
|
710
|
+
*
|
|
711
|
+
* @example
|
|
712
|
+
* // Compose formulas
|
|
713
|
+
* const critBonus = formula("Crit Bonus").mul(critMult).ceil();
|
|
714
|
+
* const full = armorReduction.then(critBonus);
|
|
715
|
+
* const result = full.apply(baseDamage);
|
|
716
|
+
*/
|
|
717
|
+
declare class AnFormula {
|
|
718
|
+
private readonly _name?;
|
|
719
|
+
private readonly steps;
|
|
720
|
+
/**
|
|
721
|
+
* Prefer the {@link formula} factory function over calling this directly.
|
|
722
|
+
*/
|
|
723
|
+
constructor(name?: string, steps?: ReadonlyArray<FormulaStep>);
|
|
724
|
+
/** The name passed to {@link formula}, if any. */
|
|
725
|
+
get name(): string | undefined;
|
|
726
|
+
/**
|
|
727
|
+
* Returns a copy of this formula with a new name, leaving the original unchanged.
|
|
728
|
+
*
|
|
729
|
+
* @param name - The new name.
|
|
730
|
+
* @example
|
|
731
|
+
* const base = formula().mul(an(2));
|
|
732
|
+
* const named = base.named("Double");
|
|
733
|
+
* named.name // "Double"
|
|
734
|
+
* base.name // undefined
|
|
735
|
+
*/
|
|
736
|
+
named(name: string): AnFormula;
|
|
737
|
+
private step;
|
|
738
|
+
/** Appends `+ other` to the pipeline. */
|
|
739
|
+
add(other: ArbitraryNumber): AnFormula;
|
|
740
|
+
/** Appends `- other` to the pipeline. */
|
|
741
|
+
sub(other: ArbitraryNumber): AnFormula;
|
|
742
|
+
/** Appends `* other` to the pipeline. */
|
|
743
|
+
mul(other: ArbitraryNumber): AnFormula;
|
|
744
|
+
/** Appends `/ other` to the pipeline. */
|
|
745
|
+
div(other: ArbitraryNumber): AnFormula;
|
|
746
|
+
/** Appends `^ exp` to the pipeline. */
|
|
747
|
+
pow(exp: number): AnFormula;
|
|
748
|
+
/** Appends `(value * mult) + add` to the pipeline. */
|
|
749
|
+
mulAdd(mult: ArbitraryNumber, add: ArbitraryNumber): AnFormula;
|
|
750
|
+
/** Appends `(value + add) * mult` to the pipeline. */
|
|
751
|
+
addMul(add: ArbitraryNumber, mult: ArbitraryNumber): AnFormula;
|
|
752
|
+
/** Appends `(value * mult) - sub` to the pipeline. */
|
|
753
|
+
mulSub(mult: ArbitraryNumber, sub: ArbitraryNumber): AnFormula;
|
|
754
|
+
/** Appends `(value - sub) * mult` to the pipeline. */
|
|
755
|
+
subMul(sub: ArbitraryNumber, mult: ArbitraryNumber): AnFormula;
|
|
756
|
+
/** Appends `(value / div) + add` to the pipeline. */
|
|
757
|
+
divAdd(div: ArbitraryNumber, add: ArbitraryNumber): AnFormula;
|
|
758
|
+
/** Appends `abs()` to the pipeline. */
|
|
759
|
+
abs(): AnFormula;
|
|
760
|
+
/** Appends `neg()` to the pipeline. */
|
|
761
|
+
neg(): AnFormula;
|
|
762
|
+
/** Appends `sqrt()` to the pipeline. */
|
|
763
|
+
sqrt(): AnFormula;
|
|
764
|
+
/** Appends `floor()` to the pipeline. */
|
|
765
|
+
floor(): AnFormula;
|
|
766
|
+
/** Appends `ceil()` to the pipeline. */
|
|
767
|
+
ceil(): AnFormula;
|
|
768
|
+
/** Appends `round()` to the pipeline. */
|
|
769
|
+
round(): AnFormula;
|
|
770
|
+
/**
|
|
771
|
+
* Returns a new formula that first applies `this`, then applies `next`.
|
|
772
|
+
*
|
|
773
|
+
* Neither operand is mutated.
|
|
774
|
+
*
|
|
775
|
+
* @param next - The formula to apply after `this`.
|
|
776
|
+
* @example
|
|
777
|
+
* const full = armorReduction.then(critBonus);
|
|
778
|
+
* const result = full.apply(baseDamage);
|
|
779
|
+
*/
|
|
780
|
+
then(next: AnFormula): AnFormula;
|
|
781
|
+
/**
|
|
782
|
+
* Runs this formula's pipeline against `value` and returns the result.
|
|
783
|
+
*
|
|
784
|
+
* The formula itself is unchanged - call `apply` as many times as needed.
|
|
785
|
+
*
|
|
786
|
+
* @param value - The starting value. Plain `number` is coerced via `ArbitraryNumber.from`.
|
|
787
|
+
* @throws `"ArbitraryNumber.from: value must be finite"` when a plain `number` is non-finite.
|
|
788
|
+
* @example
|
|
789
|
+
* const damage = damageFormula.apply(baseDamage);
|
|
790
|
+
* const scaled = damageFormula.apply(boostedBase);
|
|
791
|
+
*/
|
|
792
|
+
apply(value: ArbitraryNumber | number): ArbitraryNumber;
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Creates an {@link AnFormula} pipeline, optionally named.
|
|
796
|
+
*
|
|
797
|
+
* Build the pipeline by chaining methods - each returns a new `AnFormula`
|
|
798
|
+
* so the original is always safe to branch or reuse. Call {@link AnFormula.apply}
|
|
799
|
+
* to run the pipeline against a value.
|
|
800
|
+
*
|
|
801
|
+
* @param name - Optional label, available via {@link AnFormula.name} for debugging.
|
|
802
|
+
* @example
|
|
803
|
+
* import { formula, an } from 'arbitrary-numbers';
|
|
804
|
+
*
|
|
805
|
+
* const armorReduction = formula("Armor Reduction")
|
|
806
|
+
* .subMul(armor, an(0.75)) // (base - armor) * 0.75
|
|
807
|
+
* .floor();
|
|
808
|
+
*
|
|
809
|
+
* const critBonus = formula("Crit Bonus").mul(critMult).ceil();
|
|
810
|
+
*
|
|
811
|
+
* // Reuse across many values
|
|
812
|
+
* const physDmg = armorReduction.apply(physBase);
|
|
813
|
+
* const magDmg = armorReduction.apply(magBase);
|
|
814
|
+
*
|
|
815
|
+
* // Compose
|
|
816
|
+
* const full = armorReduction.then(critBonus);
|
|
817
|
+
* const result = full.apply(baseDamage);
|
|
818
|
+
*/
|
|
819
|
+
declare function formula(name?: string): AnFormula;
|
|
820
|
+
|
|
821
|
+
/**
|
|
822
|
+
* Formats numbers using standard scientific notation: `"1.50e+3"`, `"1.50e-5"`.
|
|
823
|
+
*
|
|
824
|
+
* Numbers with `exponent === 0` are formatted without an exponent part: `"1.50"`.
|
|
825
|
+
* This is the default plugin used by {@link ArbitraryNumber.toString}.
|
|
826
|
+
*
|
|
827
|
+
* @example
|
|
828
|
+
* const n = new ArbitraryNumber(1.5, 3);
|
|
829
|
+
* n.toString(); // "1.50e+3" (default decimals = 2)
|
|
830
|
+
* n.toString(scientificNotation, 6); // "1.500000e+3"
|
|
831
|
+
*/
|
|
832
|
+
declare class ScientificNotation implements NotationPlugin {
|
|
833
|
+
/**
|
|
834
|
+
* Formats a normalised value as `"<coefficient>e±<exponent>"`.
|
|
835
|
+
*
|
|
836
|
+
* @param coefficient - The significand in `[1, 10)` or `0`.
|
|
837
|
+
* @param exponent - The power of 10.
|
|
838
|
+
* @param decimals - Number of decimal places in the output.
|
|
839
|
+
* @returns The formatted string.
|
|
840
|
+
*/
|
|
841
|
+
format(coefficient: number, exponent: number, decimals: number): string;
|
|
842
|
+
}
|
|
843
|
+
/** Pre-built {@link ScientificNotation} instance. The default notation used by {@link ArbitraryNumber.toString}. */
|
|
844
|
+
declare const scientificNotation: ScientificNotation;
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* Abstract base class for suffix-based notation plugins (e.g. `"1.50 K"`, `"3.20a"`).
|
|
848
|
+
*
|
|
849
|
+
* Subclasses implement {@link getSuffix} to map a tier to a display label.
|
|
850
|
+
* All coefficient/remainder math is handled here.
|
|
851
|
+
*
|
|
852
|
+
* @example
|
|
853
|
+
* class EmojiNotation extends SuffixNotationBase {
|
|
854
|
+
* private static readonly TIERS = ["", "🔥", "💥", "🌟", "🚀"];
|
|
855
|
+
* getSuffix(tier: number): string {
|
|
856
|
+
* return EmojiNotation.TIERS[tier] ?? `e+${tier * 3}`;
|
|
857
|
+
* }
|
|
858
|
+
* }
|
|
859
|
+
*/
|
|
860
|
+
declare abstract class SuffixNotationBase implements SuffixNotationPlugin {
|
|
861
|
+
/** Lookup for remainder values 0, 1, 2 (exponent mod 3). */
|
|
862
|
+
protected readonly displayScale: readonly [1, 10, 100];
|
|
863
|
+
protected readonly separator: string;
|
|
864
|
+
/**
|
|
865
|
+
* @param options - Plugin options. `separator` defaults to `""`.
|
|
866
|
+
*/
|
|
867
|
+
constructor(options?: SuffixNotationPluginOptions);
|
|
868
|
+
/**
|
|
869
|
+
* Returns the suffix label for the given tier, where `tier = floor(exponent / 3)`.
|
|
870
|
+
*
|
|
871
|
+
* Tier 0 corresponds to values below 10^3 - return `""` to render with no suffix.
|
|
872
|
+
* Tier 1 = 10^3, tier 2 = 10^6, and so on.
|
|
873
|
+
*
|
|
874
|
+
* @param tier - The exponent tier (`floor(exponent / 3)`), >= 0.
|
|
875
|
+
* @returns The suffix string (e.g. `"K"`, `"a"`), or `""` for no suffix.
|
|
876
|
+
*/
|
|
877
|
+
abstract getSuffix(tier: number): string;
|
|
878
|
+
/**
|
|
879
|
+
* Formats the number by combining the scaled coefficient with the suffix returned
|
|
880
|
+
* by {@link getSuffix}. When `getSuffix` returns an empty string, the separator is
|
|
881
|
+
* omitted and only the plain value is returned.
|
|
882
|
+
*
|
|
883
|
+
* @param coefficient - The significand in `[1, 10)` or `0`.
|
|
884
|
+
* @param exponent - The power of 10.
|
|
885
|
+
* @param decimals - Number of decimal places in the output.
|
|
886
|
+
* @returns The formatted string.
|
|
887
|
+
*/
|
|
888
|
+
format(coefficient: number, exponent: number, decimals: number): string;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Converts a tier number to a multi-character suffix using an ordered symbol set.
|
|
893
|
+
*
|
|
894
|
+
* This is the raw algorithm behind {@link AlphabetNotation}, exposed as a standalone
|
|
895
|
+
* function for cases where you need suffix generation without the full notation plugin
|
|
896
|
+
* (e.g. column headers, label generators, custom renderers).
|
|
897
|
+
*
|
|
898
|
+
* The algorithm is base-N positional with no leading-symbol ambiguity:
|
|
899
|
+
* - Tier 0 -> `""` (no suffix)
|
|
900
|
+
* - Tier 1 -> `alphabet[0]`
|
|
901
|
+
* - Tier N -> `alphabet[N-1]` (last single-character suffix)
|
|
902
|
+
* - Tier N+1 -> `alphabet[0]+alphabet[0]` (first two-character suffix)
|
|
903
|
+
*
|
|
904
|
+
* This matches Excel column naming when `alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"`.
|
|
905
|
+
*
|
|
906
|
+
* @param tier - The tier number (`Math.floor(exponent / 3)` in notation context). Must be >= 0.
|
|
907
|
+
* @param alphabet - The ordered symbol set. Defaults to `"abcdefghijklmnopqrstuvwxyz"`.
|
|
908
|
+
* @returns The suffix string, or `""` for tier 0.
|
|
909
|
+
*
|
|
910
|
+
* @example
|
|
911
|
+
* alphabetSuffix(0, "abc") // ""
|
|
912
|
+
* alphabetSuffix(1, "abc") // "a"
|
|
913
|
+
* alphabetSuffix(3, "abc") // "c"
|
|
914
|
+
* alphabetSuffix(4, "abc") // "aa"
|
|
915
|
+
* alphabetSuffix(6, "abc") // "ac"
|
|
916
|
+
* alphabetSuffix(7, "abc") // "ba"
|
|
917
|
+
*
|
|
918
|
+
* // Excel columns
|
|
919
|
+
* alphabetSuffix(1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") // "A"
|
|
920
|
+
* alphabetSuffix(26, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") // "Z"
|
|
921
|
+
* alphabetSuffix(27, "ABCDEFGHIJKLMNOPQRSTUVWXYZ") // "AA"
|
|
922
|
+
*/
|
|
923
|
+
declare function alphabetSuffix(tier: number, alphabet?: string): string;
|
|
924
|
+
/**
|
|
925
|
+
* Formats numbers using multi-character suffixes derived from a configurable symbol set
|
|
926
|
+
* (e.g. `"1.50a"`, `"3.20b"`, `"1.00aa"`).
|
|
927
|
+
*
|
|
928
|
+
* The suffix sequence is generated by {@link alphabetSuffix}: tier 1 -> first symbol,
|
|
929
|
+
* tier N -> last symbol, tier N+1 -> first two-symbol combination, and so on.
|
|
930
|
+
*
|
|
931
|
+
* Pass a custom `alphabet` to produce any suffix sequence - lowercase letters (default),
|
|
932
|
+
* uppercase (Excel-style columns), Greek letters, emoji, or any ordered set of strings.
|
|
933
|
+
*
|
|
934
|
+
* @example
|
|
935
|
+
* // Default: lowercase a-z
|
|
936
|
+
* letterNotation.format(1.5, 3, 2); // "1.50a"
|
|
937
|
+
* letterNotation.format(1.5, 78, 2); // "1.50z"
|
|
938
|
+
* letterNotation.format(1.5, 81, 2); // "1.50aa"
|
|
939
|
+
*
|
|
940
|
+
* @example
|
|
941
|
+
* // Excel-style columns
|
|
942
|
+
* const excelNotation = new AlphabetNotation({ alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" });
|
|
943
|
+
* excelNotation.format(1.5, 3, 2); // "1.50A"
|
|
944
|
+
* excelNotation.format(1.5, 78, 2); // "1.50Z"
|
|
945
|
+
* excelNotation.format(1.5, 81, 2); // "1.50AA"
|
|
946
|
+
*/
|
|
947
|
+
declare class AlphabetNotation extends SuffixNotationBase {
|
|
948
|
+
private readonly defaultSuffix;
|
|
949
|
+
private readonly alphabet;
|
|
950
|
+
private readonly suffixCache;
|
|
951
|
+
/**
|
|
952
|
+
* @param options - Plugin options. `alphabet` defaults to `"abcdefghijklmnopqrstuvwxyz"`.
|
|
953
|
+
* `separator` defaults to `""` (no space between the number and suffix).
|
|
954
|
+
*/
|
|
955
|
+
constructor(options?: AlphabetNotationOptions);
|
|
956
|
+
/**
|
|
957
|
+
* Returns the suffix label for the given tier.
|
|
958
|
+
*
|
|
959
|
+
* Tier 0 returns `""` - no suffix for values below 10^3.
|
|
960
|
+
* Tier 1 -> first alphabet symbol, tier N -> last, tier N+1 -> first two-symbol combination.
|
|
961
|
+
*
|
|
962
|
+
* Results are cached after the first call per tier.
|
|
963
|
+
*
|
|
964
|
+
* @param tier - The exponent tier (`floor(exponent / 3)`), >= 0.
|
|
965
|
+
* @returns The suffix string, or `""` for tier 0.
|
|
966
|
+
*/
|
|
967
|
+
getSuffix(tier: number): string;
|
|
968
|
+
}
|
|
969
|
+
/** Pre-built {@link AlphabetNotation} instance using lowercase `a-z` with no separator. */
|
|
970
|
+
declare const letterNotation: AlphabetNotation;
|
|
971
|
+
|
|
972
|
+
/**
|
|
973
|
+
* Formats numbers using a tier-indexed array of named units
|
|
974
|
+
* (e.g. `"1.50 K"`, `"3.20 M"`, `"1.00 B"`).
|
|
975
|
+
*
|
|
976
|
+
* The `units` array is indexed by tier (`Math.floor(exponent / 3)`), so lookup
|
|
977
|
+
* is O(1) - no search required. A `undefined` entry means "no unit for this tier";
|
|
978
|
+
* the fallback plugin handles it.
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* const notation = new UnitNotation({ units: CLASSIC_UNITS, separator: " " });
|
|
982
|
+
* notation.format(1.5, 6, 2); // "1.50 M"
|
|
983
|
+
*
|
|
984
|
+
* @example
|
|
985
|
+
* // Pre-built instance with space separator and letterNotation fallback:
|
|
986
|
+
* number.toString(unitNotation); // "1.50 K"
|
|
987
|
+
*/
|
|
988
|
+
declare class UnitNotation extends SuffixNotationBase {
|
|
989
|
+
protected readonly fallback?: SuffixProvider;
|
|
990
|
+
protected readonly units: UnitArray;
|
|
991
|
+
/**
|
|
992
|
+
* @param options - Tier-indexed unit array, optional suffix fallback plugin, and separator.
|
|
993
|
+
* `separator` defaults to `" "` (a space between number and unit symbol).
|
|
994
|
+
*/
|
|
995
|
+
constructor(options: UnitNotationOptions);
|
|
996
|
+
/**
|
|
997
|
+
* Returns the suffix for the given tier: the own unit symbol if defined,
|
|
998
|
+
* otherwise the fallback's suffix, otherwise `""`.
|
|
999
|
+
*
|
|
1000
|
+
* @param tier - The exponent tier (`Math.floor(exponent / 3)`).
|
|
1001
|
+
* @returns The suffix string, or `""` if neither own units nor fallback cover this tier.
|
|
1002
|
+
*/
|
|
1003
|
+
getSuffix(tier: number): string;
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Pre-built {@link UnitNotation} instance using {@link CLASSIC_UNITS} (K, M, B, T…)
|
|
1007
|
+
* with a space separator and {@link letterNotation} as fallback for very large numbers.
|
|
1008
|
+
*/
|
|
1009
|
+
declare const unitNotation: UnitNotation;
|
|
1010
|
+
|
|
1011
|
+
/**
|
|
1012
|
+
* Full tier-indexed unit list from Thousand (tier 1, 10^3) to Centillion (tier 101, 10^303).
|
|
1013
|
+
*
|
|
1014
|
+
* Array index = tier = `Math.floor(exponent / 3)`. Tiers 34-100 are `undefined` -
|
|
1015
|
+
* numbers in that range fall through to whatever fallback is configured on the
|
|
1016
|
+
* {@link UnitNotation} instance (letterNotation for the pre-built `unitNotation`).
|
|
1017
|
+
*
|
|
1018
|
+
* @example
|
|
1019
|
+
* const notation = new UnitNotation({ units: CLASSIC_UNITS, separator: " " });
|
|
1020
|
+
* notation.format(1.5, 3, 2); // "1.50 K"
|
|
1021
|
+
* notation.format(1.5, 6, 2); // "1.50 M"
|
|
1022
|
+
*/
|
|
1023
|
+
declare const CLASSIC_UNITS: UnitArray;
|
|
1024
|
+
/**
|
|
1025
|
+
* Compact tier-indexed unit list from Thousand (tier 1, 10^3) to Nonillion (tier 10, 10^30).
|
|
1026
|
+
*
|
|
1027
|
+
* Intended for tight UI spaces. Tiers beyond 10 (exponent > 32) fall back to whatever
|
|
1028
|
+
* fallback plugin is configured on the {@link UnitNotation} instance.
|
|
1029
|
+
*
|
|
1030
|
+
* @example
|
|
1031
|
+
* const notation = new UnitNotation({ units: COMPACT_UNITS, fallback: letterNotation, separator: " " });
|
|
1032
|
+
* notation.format(1.5, 3, 2); // "1.50 k"
|
|
1033
|
+
* notation.format(1.5, 6, 2); // "1.50 M"
|
|
1034
|
+
*/
|
|
1035
|
+
declare const COMPACT_UNITS: UnitArray;
|
|
1036
|
+
|
|
1037
|
+
/**
|
|
1038
|
+
* Type-guard helpers for {@link ArbitraryNumber} and {@link NormalizedNumber}.
|
|
1039
|
+
*
|
|
1040
|
+
* @example
|
|
1041
|
+
* if (ArbitraryNumberGuard.isArbitraryNumber(value)) {
|
|
1042
|
+
* value.add(ArbitraryNumber.One);
|
|
1043
|
+
* }
|
|
1044
|
+
*/
|
|
1045
|
+
declare class ArbitraryNumberGuard {
|
|
1046
|
+
/**
|
|
1047
|
+
* Returns `true` if `obj` is an instance of {@link ArbitraryNumber}.
|
|
1048
|
+
*
|
|
1049
|
+
* @param obj - The value to test.
|
|
1050
|
+
* @returns `true` when `obj instanceof ArbitraryNumber`.
|
|
1051
|
+
*/
|
|
1052
|
+
static isArbitraryNumber(obj: unknown): obj is ArbitraryNumber;
|
|
1053
|
+
/**
|
|
1054
|
+
* Returns `true` if `obj` has the shape of a {@link NormalizedNumber}
|
|
1055
|
+
* (i.e. has numeric `coefficient` and `exponent` properties).
|
|
1056
|
+
*
|
|
1057
|
+
* Note: both `ArbitraryNumber` instances and plain objects with the right
|
|
1058
|
+
* shape will pass this check. Use {@link isArbitraryNumber} when you need
|
|
1059
|
+
* to distinguish between the two.
|
|
1060
|
+
*
|
|
1061
|
+
* @param obj - The value to test.
|
|
1062
|
+
* @returns `true` when `obj` has `typeof coefficient === "number"` and
|
|
1063
|
+
* `typeof exponent === "number"`.
|
|
1064
|
+
*/
|
|
1065
|
+
static isNormalizedNumber(obj: unknown): obj is NormalizedNumber;
|
|
1066
|
+
/**
|
|
1067
|
+
* Returns `true` if `obj` is an {@link ArbitraryNumber} with a value of zero.
|
|
1068
|
+
*
|
|
1069
|
+
* @param obj - The value to test.
|
|
1070
|
+
* @returns `true` when `obj` is an `ArbitraryNumber` and its `coefficient` is `0`.
|
|
1071
|
+
*/
|
|
1072
|
+
static isZero(obj: unknown): boolean;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
/**
|
|
1076
|
+
* A value that can be either a plain `number` or an `ArbitraryNumber`.
|
|
1077
|
+
*/
|
|
1078
|
+
type ArbitraryNumberish = ArbitraryNumber | number;
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* Convenience helpers for mixed `number | ArbitraryNumber` inputs.
|
|
1082
|
+
*
|
|
1083
|
+
* Each method accepts either type and coerces plain `number` values via
|
|
1084
|
+
* {@link ArbitraryNumber.from} before delegating to the corresponding instance method.
|
|
1085
|
+
*
|
|
1086
|
+
* Prefer `ArbitraryNumber` instance methods directly on hot paths - this class is
|
|
1087
|
+
* intended for system boundaries (event handlers, serialisation, UI callbacks) where
|
|
1088
|
+
* the input type is unknown.
|
|
1089
|
+
*
|
|
1090
|
+
* @example
|
|
1091
|
+
* import { ArbitraryNumberOps as ops } from "arbitrary-numbers";
|
|
1092
|
+
* ops.add(1500, 2500) // ArbitraryNumber (4000)
|
|
1093
|
+
* ops.mul(an(2, 0), 5) // ArbitraryNumber (10)
|
|
1094
|
+
* ops.from(1_500_000) // ArbitraryNumber { coefficient: 1.5, exponent: 6 }
|
|
1095
|
+
*/
|
|
1096
|
+
declare class ArbitraryNumberOps {
|
|
1097
|
+
/**
|
|
1098
|
+
* Converts `value` to an `ArbitraryNumber`, returning it unchanged if it already is one.
|
|
1099
|
+
*
|
|
1100
|
+
* @param value - A plain `number` or an existing `ArbitraryNumber`.
|
|
1101
|
+
* @returns The corresponding `ArbitraryNumber`.
|
|
1102
|
+
*/
|
|
1103
|
+
static from(value: ArbitraryNumberish): ArbitraryNumber;
|
|
1104
|
+
/**
|
|
1105
|
+
* Returns `left + right`, coercing both operands as needed.
|
|
1106
|
+
*
|
|
1107
|
+
* @param left - The augend.
|
|
1108
|
+
* @param right - The addend.
|
|
1109
|
+
* @example
|
|
1110
|
+
* ops.add(1500, 2500) // ArbitraryNumber (4000)
|
|
1111
|
+
*/
|
|
1112
|
+
static add(left: ArbitraryNumberish, right: ArbitraryNumberish): ArbitraryNumber;
|
|
1113
|
+
/**
|
|
1114
|
+
* Returns `left - right`, coercing both operands as needed.
|
|
1115
|
+
*
|
|
1116
|
+
* @param left - The minuend.
|
|
1117
|
+
* @param right - The subtrahend.
|
|
1118
|
+
* @example
|
|
1119
|
+
* ops.sub(5000, 1500) // ArbitraryNumber (3500)
|
|
1120
|
+
*/
|
|
1121
|
+
static sub(left: ArbitraryNumberish, right: ArbitraryNumberish): ArbitraryNumber;
|
|
1122
|
+
/**
|
|
1123
|
+
* Returns `left * right`, coercing both operands as needed.
|
|
1124
|
+
*
|
|
1125
|
+
* @param left - The multiplicand.
|
|
1126
|
+
* @param right - The multiplier.
|
|
1127
|
+
* @example
|
|
1128
|
+
* ops.mul(an(1, 3), 5) // ArbitraryNumber (5000)
|
|
1129
|
+
*/
|
|
1130
|
+
static mul(left: ArbitraryNumberish, right: ArbitraryNumberish): ArbitraryNumber;
|
|
1131
|
+
/**
|
|
1132
|
+
* Returns `left / right`, coercing both operands as needed.
|
|
1133
|
+
*
|
|
1134
|
+
* @param left - The dividend.
|
|
1135
|
+
* @param right - The divisor.
|
|
1136
|
+
* @throws `"Division by zero"` when `right` is zero.
|
|
1137
|
+
* @example
|
|
1138
|
+
* ops.div(an(1, 6), 1000) // ArbitraryNumber (1000)
|
|
1139
|
+
*/
|
|
1140
|
+
static div(left: ArbitraryNumberish, right: ArbitraryNumberish): ArbitraryNumber;
|
|
1141
|
+
/**
|
|
1142
|
+
* Compares `left` to `right`.
|
|
1143
|
+
*
|
|
1144
|
+
* @param left - The left operand.
|
|
1145
|
+
* @param right - The right operand.
|
|
1146
|
+
* @returns `1` if `left > right`, `-1` if `left < right`, `0` if equal.
|
|
1147
|
+
* @example
|
|
1148
|
+
* ops.compare(5000, 1500) // 1
|
|
1149
|
+
*/
|
|
1150
|
+
static compare(left: ArbitraryNumberish, right: ArbitraryNumberish): number;
|
|
1151
|
+
/**
|
|
1152
|
+
* Clamps `value` to the inclusive range `[min, max]`, coercing all inputs as needed.
|
|
1153
|
+
*
|
|
1154
|
+
* @param value - The value to clamp.
|
|
1155
|
+
* @param min - The lower bound (inclusive).
|
|
1156
|
+
* @param max - The upper bound (inclusive).
|
|
1157
|
+
* @example
|
|
1158
|
+
* ops.clamp(500, 1000, 2000) // ArbitraryNumber (1000) - below min, returns min
|
|
1159
|
+
*/
|
|
1160
|
+
static clamp(value: ArbitraryNumberish, min: ArbitraryNumberish, max: ArbitraryNumberish): ArbitraryNumber;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* Domain-level helpers for common game and simulation patterns.
|
|
1165
|
+
*
|
|
1166
|
+
* These sit above the core arithmetic layer - each method accepts
|
|
1167
|
+
* mixed input (`number | ArbitraryNumber`) via
|
|
1168
|
+
* {@link ArbitraryNumberOps.from} so they work at system boundaries
|
|
1169
|
+
* where you may receive raw numbers.
|
|
1170
|
+
*
|
|
1171
|
+
* For hot-path code, use `ArbitraryNumber` methods directly.
|
|
1172
|
+
*/
|
|
1173
|
+
declare class ArbitraryNumberHelpers {
|
|
1174
|
+
private static coerce;
|
|
1175
|
+
/**
|
|
1176
|
+
* Returns `true` when `value >= threshold`.
|
|
1177
|
+
*
|
|
1178
|
+
* @param value - The value to test.
|
|
1179
|
+
* @param threshold - The minimum required value.
|
|
1180
|
+
* @returns `true` when `value >= threshold`.
|
|
1181
|
+
* @example
|
|
1182
|
+
* ArbitraryNumberHelpers.meetsOrExceeds(gold, upgradeCost)
|
|
1183
|
+
*/
|
|
1184
|
+
static meetsOrExceeds(value: ArbitraryNumberish, threshold: ArbitraryNumberish): boolean;
|
|
1185
|
+
/**
|
|
1186
|
+
* Returns the largest whole multiple count of `step` that fits into `total`.
|
|
1187
|
+
*
|
|
1188
|
+
* Equivalent to `floor(total / step)`.
|
|
1189
|
+
*
|
|
1190
|
+
* @param total - The total available amount.
|
|
1191
|
+
* @param step - The cost or size of one unit. Must be greater than zero.
|
|
1192
|
+
* @returns The number of whole units that fit, as an `ArbitraryNumber`.
|
|
1193
|
+
* @throws `"step must be greater than zero"` when `step <= 0`.
|
|
1194
|
+
* @example
|
|
1195
|
+
* const canBuy = ArbitraryNumberHelpers.wholeMultipleCount(gold, upgradeCost);
|
|
1196
|
+
*/
|
|
1197
|
+
static wholeMultipleCount(total: ArbitraryNumberish, step: ArbitraryNumberish): ArbitraryNumber;
|
|
1198
|
+
/**
|
|
1199
|
+
* Returns `value - delta`, clamped to a minimum of `floor` (default `0`).
|
|
1200
|
+
*
|
|
1201
|
+
* @param value - The starting value.
|
|
1202
|
+
* @param delta - The amount to subtract.
|
|
1203
|
+
* @param floor - The minimum result. Defaults to `ArbitraryNumber.Zero`.
|
|
1204
|
+
* @returns `max(value - delta, floor)`.
|
|
1205
|
+
* @example
|
|
1206
|
+
* health = ArbitraryNumberHelpers.subtractWithFloor(health, damage);
|
|
1207
|
+
*/
|
|
1208
|
+
static subtractWithFloor(value: ArbitraryNumberish, delta: ArbitraryNumberish, floor?: ArbitraryNumberish): ArbitraryNumber;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
export { AlphabetNotation, type AlphabetNotationOptions, AnChain, AnFormula, type AnFunction, ArbitraryNumber, ArbitraryNumberDomainError, ArbitraryNumberError, ArbitraryNumberGuard, ArbitraryNumberHelpers, ArbitraryNumberInputError, ArbitraryNumberOps, type ArbitraryNumberish, CLASSIC_UNITS, COMPACT_UNITS, type Mod3, type NormalizedNumber, type NotationPlugin, ScientificNotation, type Signum, SuffixNotationBase, type SuffixNotationPlugin, type SuffixNotationPluginOptions, type SuffixProvider, type Unit, type UnitArray, UnitNotation, type UnitNotationOptions, alphabetSuffix, an, chain, formula, ArbitraryNumberGuard as guard, ArbitraryNumberHelpers as helpers, letterNotation, ArbitraryNumberOps as ops, scientificNotation, unitNotation };
|