-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
266 lines (229 loc) · 8.3 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
import PackageJSON from "../package.json";
import { _Precision, precisionRange } from "./Precision";
import defaultOptions from "./defaultOptions";
import versionNumbers from "./versionNumbers";
import isValidPrecision from "./eval/isValidPrecision";
import validateOptions from "./eval/validateOptions";
import round from "./functions/round";
import add from "./functions/add";
import subtract from "./functions/subtract";
import multiply from "./functions/multiply";
import divide from "./functions/divide";
/**
* A FloatToolkit contains methods to round floats and perform accurate math operations with them.
* Its behavior can be configured to cover the program's needs.
*/
class FloatToolkit {
/**
* @param defaultPrecision The precision (number of decimals) to use if not specified in the function itself. Can be changed later. Default value if 10.
* @param options An optional configuration object.
*
* @example
* import FloatToolkit from "@float-toolkit/core";
* const ft = new FloatToolkit(10, { forceUseDefaultPrecision: true });
*/
constructor(defaultPrecision: FloatToolkit.Precision = 10, options: Partial<FloatToolkit.Options> = {}) {
this.defaultPrecision = defaultPrecision;
this.resetOptions(options);
}
/**
* @internal
*/
#precision: FloatToolkit.Precision = 10;
/**
* @internal
*/
#options: FloatToolkit.Options = defaultOptions;
/**
* An integer between 1 and 17.
* Defines the precision (number of decimals) to use by default, if the precision is not specified in the function itself.
*/
get defaultPrecision(): FloatToolkit.Precision {
return this.#precision;
}
set defaultPrecision(precision: FloatToolkit.Precision) {
if (!isValidPrecision(precision))
throw new TypeError(`defaultPrecision must be an integer between ${precisionRange.min} and ${precisionRange.max}.`);
this.#precision = precision;
}
/**
* The options object for this FloatToolkit.
*/
get options(): Readonly<FloatToolkit.Options> {
return Object.freeze(this.#options);
}
/**
* Changes the values in the options object for this FloatToolkit and returns the new object.
*
* @param options The configuration object that contains the new options to apply.
* @returns The new options object.
*
* @example
* ft.setOptions({ forceUseDefaultPrecision: true }); // Previous options with forceUseDefaultPrecision set to true.
*/
setOptions(options: Partial<FloatToolkit.Options>): Readonly<FloatToolkit.Options> {
validateOptions(options);
this.#options = { ...this.#options, ...options };
return this.options;
}
/**
* Resets the options object for this FloatToolkit to its default values and returns the new object.
*
* @param options An optional configuration object containing new options to apply after resetting.
* @returns The new options object.
*
* @example
* ft.resetOptions({ forceUseDefaultPrecision: true }); // Default options with forceUseDefaultPrecision set to true.
*/
resetOptions(options: Partial<FloatToolkit.Options> = {}): Readonly<FloatToolkit.Options> {
validateOptions(options);
this.#options = { ...defaultOptions, ...options };
return this.options;
}
/**
* @internal
*/
#choosePrecision(precisionParam?: FloatToolkit.Precision): FloatToolkit.Precision | undefined {
if (!precisionParam && this.options.forceUseDefaultPrecision) return this.defaultPrecision;
return precisionParam;
}
/**
* Rounds a number to the specified precision, or to the FloatToolkit's default precision.
*
* @param n The number to round.
* @param precision The precision to use. If not specified, the FloatToolkit's default precision is used instead.
* @returns The rounded number.
*
* @example
* ft.round(0.1 + 0.2); // 0.3 if the precision is set to 16 or lower.
*/
round(n: number, precision = this.defaultPrecision): number {
return round(n, precision);
}
/**
* Adds two or more numbers, and rounds the sum.
*
* **NOTE:** By default, this method does not use the FloatToolkit's default precision. Instead, it calculates the best precision to use based on the original
* numbers (dynamic precision). To always use the default precision, set the `forceUseDefaultPrecision` option to `true`.
*
* @param numbers The numbers to add.
* @param precision The precision to use instead of the one chosen by the function.
* @returns The rounded sum
*
* @example
* ft.add([0.1, 0.2]); // 0.3 if using dynamic precision, or if the precision is set to 16 or lower.
*/
add(numbers: number[], precision?: FloatToolkit.Precision): number {
precision = this.#choosePrecision(precision);
return add(numbers, precision);
}
/**
* Subtracts two or more numbers (starting with the second number, all of the numbers are subtracted from the first one), and rounds the difference.
*
* **NOTE:** By default, this method does not use the FloatToolkit's default precision. Instead, it calculates the best precision to use based on the original
* numbers (dynamic precision). To always use the default precision, set the `forceUseDefaultPrecision` option to `true`.
*
* @param numbers The numbers to subtract.
* @param precision The precision to use instead of the one chosen by the function.
* @returns The rounded difference
*
* @example
* ft.subtract([0.8, 0.1, 0.3]); // 0.4 if using dynamic precision, or if the precision is set to 15 or lower.
*/
subtract(numbers: number[], precision?: FloatToolkit.Precision): number {
precision = this.#choosePrecision(precision);
return subtract(numbers, precision);
}
/**
* Multiplies two or more numbers, and rounds the product.
*
* **NOTE:** By default, this method does not use the FloatToolkit's default precision. Instead, it calculates the best precision to use based on the original
* numbers (dynamic precision). To always use the default precision, set the `forceUseDefaultPrecision` option to `true`.
*
* @param numbers The numbers to multiply.
* @param precision The precision to use instead of the one chosen by the function.
* @returns The rounded product
*
* @example
* ft.multiply([0.1, 0.9]); // 0.09 if using dynamic precision, or if the precision is set to 16 or lower.
*/
multiply(numbers: number[], precision?: FloatToolkit.Precision): number {
precision = this.#choosePrecision(precision);
return multiply(numbers, precision);
}
/**
* Divides two or more numbers (starting with the second number, all of the numbers divide the first one), and rounds the result.
*
* @param numbers The numbers to divide.
* @param precision The precision to use instead of the one chosen by the function.
* @returns The rounded result
*
* @example
* ft.divide([0.09, 0.9]); // 0.1 if the precision is set to 16 or lower.
*/
divide(numbers: number[], precision = this.defaultPrecision): number {
return divide(numbers, precision);
}
}
namespace FloatToolkit {
/**
* An integer between 1 and 17, which can be used as a FloatToolkit's default precision.
*/
export type Precision = _Precision;
/**
* Options that can be set to a FloatToolkit to modify its behavior.
*/
export interface Options {
/**
* Always use the FloatToolkit's default precision instead of dynamic precision.
*/
forceUseDefaultPrecision: boolean;
}
/**
* @internal
*/
export type OptionLabel = keyof Options;
/**
* @internal
*/
export type FirstNumberExtractedArray = [number | undefined, number[]];
/**
* An object containing the package version.
*/
export interface Version {
/**
* The full version number (M.m.P)
*/
get full(): string;
/**
* The major version (first number)
*/
get major(): string;
/**
* The minor version (second number)
*/
get minor(): string;
/**
* The patch version (third number)
*/
get patch(): string;
}
/**
* Contains the package's major, minor and patch version numbers.
*/
export const VERSION: Version = {
get full() {
return PackageJSON.version;
},
get major() {
return versionNumbers[0]!;
},
get minor() {
return versionNumbers[1]!;
},
get patch() {
return versionNumbers[2]!;
},
};
}
export = FloatToolkit;