@obinexusmk2/hypernum 0.1.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 +256 -0
- package/dist/index.cjs +3425 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1449 -0
- package/dist/index.js +3284 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.js +8 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/types/config/config-loader.d.ts +56 -0
- package/dist/types/config/config-loader.d.ts.map +1 -0
- package/dist/types/config/config-parser.d.ts +28 -0
- package/dist/types/config/config-parser.d.ts.map +1 -0
- package/dist/types/config/config-resolver.d.ts +21 -0
- package/dist/types/config/config-resolver.d.ts.map +1 -0
- package/dist/types/config/config-source.d.ts +27 -0
- package/dist/types/config/config-source.d.ts.map +1 -0
- package/dist/types/config/index.d.ts +68 -0
- package/dist/types/config/index.d.ts.map +1 -0
- package/dist/types/core/common.d.ts +169 -0
- package/dist/types/core/common.d.ts.map +1 -0
- package/dist/types/core/config.d.ts +197 -0
- package/dist/types/core/config.d.ts.map +1 -0
- package/dist/types/core/constants.d.ts +88 -0
- package/dist/types/core/constants.d.ts.map +1 -0
- package/dist/types/core/errors.d.ts +97 -0
- package/dist/types/core/errors.d.ts.map +1 -0
- package/dist/types/core/hypernum.d.ts +60 -0
- package/dist/types/core/hypernum.d.ts.map +1 -0
- package/dist/types/core/index.d.ts +6 -0
- package/dist/types/core/index.d.ts.map +1 -0
- package/dist/types/index.d.ts +33 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/operations/arithmetic.d.ts +72 -0
- package/dist/types/operations/arithmetic.d.ts.map +1 -0
- package/dist/types/operations/bitwise.d.ts +98 -0
- package/dist/types/operations/bitwise.d.ts.map +1 -0
- package/dist/types/operations/comparison.d.ts +94 -0
- package/dist/types/operations/comparison.d.ts.map +1 -0
- package/dist/types/operations/conversion.d.ts +79 -0
- package/dist/types/operations/conversion.d.ts.map +1 -0
- package/dist/types/operations/factorial.d.ts +58 -0
- package/dist/types/operations/factorial.d.ts.map +1 -0
- package/dist/types/operations/index.d.ts +6 -0
- package/dist/types/operations/index.d.ts.map +1 -0
- package/dist/types/operations/power.d.ts +49 -0
- package/dist/types/operations/power.d.ts.map +1 -0
- package/dist/types/storage/Heap.d.ts +95 -0
- package/dist/types/storage/Heap.d.ts.map +1 -0
- package/dist/types/storage/index.d.ts +2 -0
- package/dist/types/storage/index.d.ts.map +1 -0
- package/dist/types/structures/ackermann.d.ts +74 -0
- package/dist/types/structures/ackermann.d.ts.map +1 -0
- package/dist/types/structures/big-array.d.ts +102 -0
- package/dist/types/structures/big-array.d.ts.map +1 -0
- package/dist/types/structures/index.d.ts +5 -0
- package/dist/types/structures/index.d.ts.map +1 -0
- package/dist/types/structures/number-tree.d.ts +114 -0
- package/dist/types/structures/number-tree.d.ts.map +1 -0
- package/dist/types/structures/power-tower.d.ts +74 -0
- package/dist/types/structures/power-tower.d.ts.map +1 -0
- package/dist/types/utils/formatting.d.ts +45 -0
- package/dist/types/utils/formatting.d.ts.map +1 -0
- package/dist/types/utils/index.d.ts +5 -0
- package/dist/types/utils/index.d.ts.map +1 -0
- package/dist/types/utils/parser.d.ts +39 -0
- package/dist/types/utils/parser.d.ts.map +1 -0
- package/dist/types/utils/precision.d.ts +57 -0
- package/dist/types/utils/precision.d.ts.map +1 -0
- package/dist/types/utils/validation.d.ts +28 -0
- package/dist/types/utils/validation.d.ts.map +1 -0
- package/package.json +164 -0
- package/rollup.config.js +162 -0
- package/src/config/config-loader.ts +226 -0
- package/src/config/config-parser.ts +161 -0
- package/src/config/config-resolver.ts +52 -0
- package/src/config/config-source.ts +32 -0
- package/src/config/index.ts +159 -0
- package/src/core/common.ts +185 -0
- package/src/core/config.ts +393 -0
- package/src/core/constants.ts +102 -0
- package/src/core/errors.ts +203 -0
- package/src/core/hypernum.ts +241 -0
- package/src/core/index.ts +5 -0
- package/src/index.ts +183 -0
- package/src/operations/arithmetic.ts +333 -0
- package/src/operations/bitwise.ts +367 -0
- package/src/operations/comparison.ts +272 -0
- package/src/operations/conversion.ts +400 -0
- package/src/operations/factorial.ts +279 -0
- package/src/operations/index.ts +5 -0
- package/src/operations/power.ts +316 -0
- package/src/storage/Heap.ts +238 -0
- package/src/storage/index.ts +1 -0
- package/src/structures/ackermann.ts +233 -0
- package/src/structures/big-array.ts +306 -0
- package/src/structures/index.ts +4 -0
- package/src/structures/number-tree.ts +404 -0
- package/src/structures/power-tower.ts +278 -0
- package/src/types/common.d.ts +357 -0
- package/src/types/core.d.ts +161 -0
- package/src/types/index.d.ts +2 -0
- package/src/utils/formatting.ts +246 -0
- package/src/utils/index.ts +4 -0
- package/src/utils/parser.ts +245 -0
- package/src/utils/precision.ts +217 -0
- package/src/utils/validation.ts +183 -0
- package/tsconfig.json +84 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Comparison operations module for Hypernum library
|
|
3
|
+
* Provides functions for comparing large numbers with precision support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
toBigInt,
|
|
8
|
+
ValidationError,
|
|
9
|
+
|
|
10
|
+
} from '../utils/validation';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
RoundingMode,
|
|
14
|
+
normalizePrecision,
|
|
15
|
+
} from '../utils/precision';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Options for comparison operations
|
|
19
|
+
*/
|
|
20
|
+
export interface ComparisonOptions {
|
|
21
|
+
precision?: number;
|
|
22
|
+
roundingMode?: RoundingMode;
|
|
23
|
+
tolerance?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DEFAULT_OPTIONS: Required<ComparisonOptions> = {
|
|
27
|
+
precision: 0,
|
|
28
|
+
roundingMode: RoundingMode.HALF_EVEN,
|
|
29
|
+
tolerance: 0
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Result type for comparison operations
|
|
34
|
+
* -1: first value is less than second value
|
|
35
|
+
* 0: values are equal
|
|
36
|
+
* 1: first value is greater than second value
|
|
37
|
+
*/
|
|
38
|
+
export type ComparisonResult = -1 | 0 | 1;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Compares two numbers with optional precision
|
|
42
|
+
*/
|
|
43
|
+
export function compare(
|
|
44
|
+
a: bigint | string | number,
|
|
45
|
+
b: bigint | string | number,
|
|
46
|
+
options: ComparisonOptions = {}
|
|
47
|
+
): ComparisonResult {
|
|
48
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
49
|
+
const bigA = toBigInt(a);
|
|
50
|
+
const bigB = toBigInt(b);
|
|
51
|
+
|
|
52
|
+
if (opts.precision === 0 && opts.tolerance === 0) {
|
|
53
|
+
if (bigA < bigB) return -1;
|
|
54
|
+
if (bigA > bigB) return 1;
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const [scaledA, scaledB] = normalizePrecision(bigA, bigB, opts.precision, opts.precision);
|
|
59
|
+
|
|
60
|
+
if (opts.tolerance > 0) {
|
|
61
|
+
const diff = scaledA - scaledB;
|
|
62
|
+
const toleranceValue = BigInt(10) ** BigInt(opts.tolerance);
|
|
63
|
+
|
|
64
|
+
if (diff < -toleranceValue) return -1;
|
|
65
|
+
if (diff > toleranceValue) return 1;
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (scaledA < scaledB) return -1;
|
|
70
|
+
if (scaledA > scaledB) return 1;
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Checks if two numbers are equal
|
|
76
|
+
*/
|
|
77
|
+
export function equals(
|
|
78
|
+
a: bigint | string | number,
|
|
79
|
+
b: bigint | string | number,
|
|
80
|
+
options: ComparisonOptions = {}
|
|
81
|
+
): boolean {
|
|
82
|
+
return compare(a, b, options) === 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Checks if first number is less than second
|
|
87
|
+
*/
|
|
88
|
+
export function lessThan(
|
|
89
|
+
a: bigint | string | number,
|
|
90
|
+
b: bigint | string | number,
|
|
91
|
+
options: ComparisonOptions = {}
|
|
92
|
+
): boolean {
|
|
93
|
+
return compare(a, b, options) === -1;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Checks if first number is less than or equal to second
|
|
98
|
+
*/
|
|
99
|
+
export function lessThanOrEqual(
|
|
100
|
+
a: bigint | string | number,
|
|
101
|
+
b: bigint | string | number,
|
|
102
|
+
options: ComparisonOptions = {}
|
|
103
|
+
): boolean {
|
|
104
|
+
const result = compare(a, b, options);
|
|
105
|
+
return result === -1 || result === 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Checks if first number is greater than second
|
|
110
|
+
*/
|
|
111
|
+
export function greaterThan(
|
|
112
|
+
a: bigint | string | number,
|
|
113
|
+
b: bigint | string | number,
|
|
114
|
+
options: ComparisonOptions = {}
|
|
115
|
+
): boolean {
|
|
116
|
+
return compare(a, b, options) === 1;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Checks if first number is greater than or equal to second
|
|
121
|
+
*/
|
|
122
|
+
export function greaterThanOrEqual(
|
|
123
|
+
a: bigint | string | number,
|
|
124
|
+
b: bigint | string | number,
|
|
125
|
+
options: ComparisonOptions = {}
|
|
126
|
+
): boolean {
|
|
127
|
+
const result = compare(a, b, options);
|
|
128
|
+
return result === 1 || result === 0;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Checks if a number is between two others (inclusive)
|
|
133
|
+
*/
|
|
134
|
+
export function between(
|
|
135
|
+
value: bigint | string | number,
|
|
136
|
+
min: bigint | string | number,
|
|
137
|
+
max: bigint | string | number,
|
|
138
|
+
options: ComparisonOptions = {}
|
|
139
|
+
): boolean {
|
|
140
|
+
return greaterThanOrEqual(value, min, options) && lessThanOrEqual(value, max, options);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Finds the maximum value in an array of numbers
|
|
145
|
+
*/
|
|
146
|
+
export function max(
|
|
147
|
+
values: Array<bigint | string | number>,
|
|
148
|
+
options: ComparisonOptions = {}
|
|
149
|
+
): bigint {
|
|
150
|
+
if (values.length === 0) {
|
|
151
|
+
throw new ValidationError('Cannot find maximum of empty array');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return values.reduce<bigint>((max, current) => {
|
|
155
|
+
const bigMax = toBigInt(max);
|
|
156
|
+
const bigCurrent = toBigInt(current);
|
|
157
|
+
return greaterThan(bigCurrent, bigMax, options) ? bigCurrent : bigMax;
|
|
158
|
+
}, toBigInt(values[0]));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Finds the minimum value in an array of numbers
|
|
163
|
+
*/
|
|
164
|
+
export function min(
|
|
165
|
+
values: Array<bigint | string | number>,
|
|
166
|
+
options: ComparisonOptions = {}
|
|
167
|
+
): bigint {
|
|
168
|
+
if (values.length === 0) {
|
|
169
|
+
throw new ValidationError('Cannot find minimum of empty array');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return values.reduce<bigint>((min, current) => {
|
|
173
|
+
const bigMin = toBigInt(min);
|
|
174
|
+
const bigCurrent = toBigInt(current);
|
|
175
|
+
return lessThan(bigCurrent, bigMin, options) ? bigCurrent : bigMin;
|
|
176
|
+
}, toBigInt(values[0]));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Clamps a value between minimum and maximum bounds
|
|
181
|
+
*/
|
|
182
|
+
export function clamp(
|
|
183
|
+
value: bigint | string | number,
|
|
184
|
+
min: bigint | string | number,
|
|
185
|
+
max: bigint | string | number,
|
|
186
|
+
options: ComparisonOptions = {}
|
|
187
|
+
): bigint {
|
|
188
|
+
const bigValue = toBigInt(value);
|
|
189
|
+
const bigMin = toBigInt(min);
|
|
190
|
+
const bigMax = toBigInt(max);
|
|
191
|
+
|
|
192
|
+
if (lessThan(bigMax, bigMin, options)) {
|
|
193
|
+
throw new ValidationError('Maximum bound must be greater than or equal to minimum bound');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (lessThan(bigValue, bigMin, options)) return bigMin;
|
|
197
|
+
if (greaterThan(bigValue, bigMax, options)) return bigMax;
|
|
198
|
+
return bigValue;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Checks if all values in array are equal within tolerance
|
|
203
|
+
*/
|
|
204
|
+
export function allEqual(
|
|
205
|
+
values: Array<bigint | string | number>,
|
|
206
|
+
options: ComparisonOptions = {}
|
|
207
|
+
): boolean {
|
|
208
|
+
if (values.length <= 1) return true;
|
|
209
|
+
|
|
210
|
+
const first = toBigInt(values[0]);
|
|
211
|
+
return values.every(value => equals(value, first, options));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Checks if values are in ascending order
|
|
216
|
+
*/
|
|
217
|
+
export function isAscending(
|
|
218
|
+
values: Array<bigint | string | number>,
|
|
219
|
+
options: ComparisonOptions = {}
|
|
220
|
+
): boolean {
|
|
221
|
+
if (values.length <= 1) return true;
|
|
222
|
+
|
|
223
|
+
for (let i = 1; i < values.length; i++) {
|
|
224
|
+
if (values[i] === undefined || values[i - 1] === undefined || !greaterThanOrEqual(values[i]!, values[i - 1]!, options)) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Checks if values are in descending order
|
|
233
|
+
*/
|
|
234
|
+
export function isDescending(
|
|
235
|
+
values: Array<bigint | string | number>,
|
|
236
|
+
options: ComparisonOptions = {}
|
|
237
|
+
): boolean {
|
|
238
|
+
if (values.length <= 1) return true;
|
|
239
|
+
|
|
240
|
+
for (let i = 1; i < values.length; i++) {
|
|
241
|
+
if (values[i] === undefined || values[i - 1] === undefined || !lessThanOrEqual(values[i]!, values[i - 1]!, options)) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Creates a comparator function for sorting
|
|
250
|
+
*/
|
|
251
|
+
export function createComparator(
|
|
252
|
+
options: ComparisonOptions = {}
|
|
253
|
+
): (a: bigint | string | number, b: bigint | string | number) => number {
|
|
254
|
+
return (a, b) => compare(a, b, options);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export default {
|
|
258
|
+
compare,
|
|
259
|
+
equals,
|
|
260
|
+
lessThan,
|
|
261
|
+
lessThanOrEqual,
|
|
262
|
+
greaterThan,
|
|
263
|
+
greaterThanOrEqual,
|
|
264
|
+
between,
|
|
265
|
+
max,
|
|
266
|
+
min,
|
|
267
|
+
clamp,
|
|
268
|
+
allEqual,
|
|
269
|
+
isAscending,
|
|
270
|
+
isDescending,
|
|
271
|
+
createComparator
|
|
272
|
+
};
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversion operations module for Hypernum library
|
|
3
|
+
* Provides functions for converting numbers between different formats and bases
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
toBigInt,
|
|
8
|
+
ValidationError,
|
|
9
|
+
} from '../utils/validation';
|
|
10
|
+
|
|
11
|
+
import {
|
|
12
|
+
RoundingMode,
|
|
13
|
+
|
|
14
|
+
} from '../utils/precision';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Options for conversion operations
|
|
18
|
+
*/
|
|
19
|
+
export interface ConversionOptions {
|
|
20
|
+
/** Precision for decimal operations */
|
|
21
|
+
precision?: number;
|
|
22
|
+
/** Rounding mode for decimal operations */
|
|
23
|
+
roundingMode?: RoundingMode;
|
|
24
|
+
/** Whether to use uppercase for hex/base-N output */
|
|
25
|
+
uppercase?: boolean;
|
|
26
|
+
/** Whether to add prefix for base-N output (0x, 0b, etc.) */
|
|
27
|
+
prefix?: boolean;
|
|
28
|
+
/** Minimum number of digits (pad with zeros) */
|
|
29
|
+
minDigits?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const DEFAULT_OPTIONS: Required<ConversionOptions> = {
|
|
33
|
+
precision: 0,
|
|
34
|
+
roundingMode: RoundingMode.HALF_EVEN,
|
|
35
|
+
uppercase: false,
|
|
36
|
+
prefix: false,
|
|
37
|
+
minDigits: 1
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Converts number to binary string representation
|
|
42
|
+
*/
|
|
43
|
+
export function toBinary(
|
|
44
|
+
value: bigint | string | number,
|
|
45
|
+
options: ConversionOptions = {}
|
|
46
|
+
): string {
|
|
47
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
48
|
+
const bigValue = toBigInt(value);
|
|
49
|
+
|
|
50
|
+
let binary = bigValue.toString(2);
|
|
51
|
+
|
|
52
|
+
// Pad with zeros if needed
|
|
53
|
+
while (binary.length < opts.minDigits) {
|
|
54
|
+
binary = '0' + binary;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return opts.prefix ? '0b' + binary : binary;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Converts number to octal string representation
|
|
62
|
+
*/
|
|
63
|
+
export function toOctal(
|
|
64
|
+
value: bigint | string | number,
|
|
65
|
+
options: ConversionOptions = {}
|
|
66
|
+
): string {
|
|
67
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
68
|
+
const bigValue = toBigInt(value);
|
|
69
|
+
|
|
70
|
+
let octal = bigValue.toString(8);
|
|
71
|
+
|
|
72
|
+
while (octal.length < opts.minDigits) {
|
|
73
|
+
octal = '0' + octal;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return opts.prefix ? '0o' + octal : octal;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Converts number to hexadecimal string representation
|
|
81
|
+
*/
|
|
82
|
+
export function toHexadecimal(
|
|
83
|
+
value: bigint | string | number,
|
|
84
|
+
options: ConversionOptions = {}
|
|
85
|
+
): string {
|
|
86
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
87
|
+
const bigValue = toBigInt(value);
|
|
88
|
+
|
|
89
|
+
let hex = bigValue.toString(16);
|
|
90
|
+
|
|
91
|
+
if (opts.uppercase) {
|
|
92
|
+
hex = hex.toUpperCase();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
while (hex.length < opts.minDigits) {
|
|
96
|
+
hex = '0' + hex;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return opts.prefix ? '0x' + hex : hex;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Converts number to string in specified base
|
|
104
|
+
*/
|
|
105
|
+
export function toBase(
|
|
106
|
+
value: bigint | string | number,
|
|
107
|
+
base: number,
|
|
108
|
+
options: ConversionOptions = {}
|
|
109
|
+
): string {
|
|
110
|
+
if (base < 2 || base > 36) {
|
|
111
|
+
throw new ValidationError('Base must be between 2 and 36');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
115
|
+
const bigValue = toBigInt(value);
|
|
116
|
+
|
|
117
|
+
let result = bigValue.toString(base);
|
|
118
|
+
|
|
119
|
+
if (opts.uppercase) {
|
|
120
|
+
result = result.toUpperCase();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
while (result.length < opts.minDigits) {
|
|
124
|
+
result = '0' + result;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Converts string from specified base to bigint
|
|
132
|
+
*/
|
|
133
|
+
export function fromBase(
|
|
134
|
+
value: string,
|
|
135
|
+
base: number
|
|
136
|
+
): bigint {
|
|
137
|
+
if (base < 2 || base > 36) {
|
|
138
|
+
throw new ValidationError('Base must be between 2 and 36');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Remove base prefixes if present
|
|
142
|
+
const cleanValue = value.toLowerCase()
|
|
143
|
+
.replace(/^0x/, '') // hex
|
|
144
|
+
.replace(/^0b/, '') // binary
|
|
145
|
+
.replace(/^0o/, ''); // octal
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
return BigInt(`${base}n${cleanValue}`);
|
|
149
|
+
} catch (error) {
|
|
150
|
+
throw new ValidationError(`Invalid number format for base ${base}: ${value}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Converts decimal string to fraction representation
|
|
156
|
+
*/
|
|
157
|
+
export function toFraction(
|
|
158
|
+
value: string,
|
|
159
|
+
): [bigint, bigint] {
|
|
160
|
+
|
|
161
|
+
// Split into integer and decimal parts
|
|
162
|
+
const [intPart, decPart = ''] = value.split('.');
|
|
163
|
+
|
|
164
|
+
if (!decPart) {
|
|
165
|
+
return [toBigInt(intPart), 1n];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Convert decimal to fraction
|
|
169
|
+
const numerator = toBigInt(intPart + decPart);
|
|
170
|
+
const denominator = 10n ** BigInt(decPart.length);
|
|
171
|
+
|
|
172
|
+
// Simplify fraction
|
|
173
|
+
const gcd = calculateGCD(numerator, denominator);
|
|
174
|
+
|
|
175
|
+
return [numerator / gcd, denominator / gcd];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Converts fraction to decimal string with specified precision
|
|
180
|
+
*/
|
|
181
|
+
export function fromFraction(
|
|
182
|
+
numerator: bigint | string | number,
|
|
183
|
+
denominator: bigint | string | number,
|
|
184
|
+
options: ConversionOptions = {}
|
|
185
|
+
): string {
|
|
186
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
187
|
+
const bigNumerator = toBigInt(numerator);
|
|
188
|
+
const bigDenominator = toBigInt(denominator);
|
|
189
|
+
|
|
190
|
+
if (bigDenominator === 0n) {
|
|
191
|
+
throw new ValidationError('Denominator cannot be zero');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const quotient = bigNumerator / bigDenominator;
|
|
195
|
+
const remainder = bigNumerator % bigDenominator;
|
|
196
|
+
|
|
197
|
+
if (remainder === 0n || opts.precision === 0) {
|
|
198
|
+
return quotient.toString();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Calculate decimal part
|
|
202
|
+
const scaleFactor = 10n ** BigInt(opts.precision);
|
|
203
|
+
const scaledRemainder = (remainder * scaleFactor) / bigDenominator;
|
|
204
|
+
|
|
205
|
+
return `${quotient}.${scaledRemainder.toString().padStart(opts.precision, '0')}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Converts scientific notation to decimal string
|
|
210
|
+
*/
|
|
211
|
+
export function fromScientific(
|
|
212
|
+
value: string,
|
|
213
|
+
): string {
|
|
214
|
+
|
|
215
|
+
// Parse scientific notation format
|
|
216
|
+
const match = value.match(/^(-?\d+\.?\d*)[eE]([+-]?\d+)$/);
|
|
217
|
+
if (!match) {
|
|
218
|
+
throw new ValidationError('Invalid scientific notation format');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const [, significand, exponent] = match;
|
|
222
|
+
const exp = parseInt(exponent || '0', 10);
|
|
223
|
+
|
|
224
|
+
// Convert to regular decimal
|
|
225
|
+
if (exp >= 0) {
|
|
226
|
+
if (significand === undefined) {
|
|
227
|
+
throw new ValidationError('Invalid scientific notation format');
|
|
228
|
+
}
|
|
229
|
+
return (BigInt(significand.replace('.', '')) * (10n ** BigInt(exp))).toString();
|
|
230
|
+
} else {
|
|
231
|
+
const absExp = Math.abs(exp);
|
|
232
|
+
if (significand === undefined) {
|
|
233
|
+
throw new ValidationError('Invalid scientific notation format');
|
|
234
|
+
}
|
|
235
|
+
const scaledValue = BigInt(significand.replace('.', ''));
|
|
236
|
+
return (scaledValue / (10n ** BigInt(absExp))).toString();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Converts decimal to scientific notation
|
|
242
|
+
*/
|
|
243
|
+
export function toScientific(
|
|
244
|
+
value: bigint | string | number,
|
|
245
|
+
options: ConversionOptions = {}
|
|
246
|
+
): string {
|
|
247
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
248
|
+
const bigValue = toBigInt(value);
|
|
249
|
+
|
|
250
|
+
if (bigValue === 0n) {
|
|
251
|
+
return '0e0';
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const str = bigValue.toString();
|
|
255
|
+
const firstDigit = str[0] === '-' ? str[1] : str[0];
|
|
256
|
+
const exponent = str.length - (str[0] === '-' ? 2 : 1);
|
|
257
|
+
|
|
258
|
+
let result = firstDigit;
|
|
259
|
+
if (str.length > 1) {
|
|
260
|
+
const restDigits = str.slice(str[0] === '-' ? 2 : 1);
|
|
261
|
+
if (opts.precision > 0) {
|
|
262
|
+
result += '.' + restDigits.slice(0, opts.precision);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (str[0] === '-') {
|
|
267
|
+
result = '-' + result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return `${result}e${exponent}`;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Calculates Greatest Common Divisor (helper function)
|
|
275
|
+
*/
|
|
276
|
+
function calculateGCD(a: bigint, b: bigint): bigint {
|
|
277
|
+
a = a < 0n ? -a : a;
|
|
278
|
+
b = b < 0n ? -b : b;
|
|
279
|
+
|
|
280
|
+
while (b !== 0n) {
|
|
281
|
+
const temp = b;
|
|
282
|
+
b = a % b;
|
|
283
|
+
a = temp;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return a;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Converts Roman numeral to number
|
|
292
|
+
*/
|
|
293
|
+
export function fromRoman(value: string): bigint {
|
|
294
|
+
const romanValues = new Map<string, number>([
|
|
295
|
+
['I', 1],
|
|
296
|
+
['V', 5],
|
|
297
|
+
['X', 10],
|
|
298
|
+
['L', 50],
|
|
299
|
+
['C', 100],
|
|
300
|
+
['D', 500],
|
|
301
|
+
['M', 1000]
|
|
302
|
+
]);
|
|
303
|
+
|
|
304
|
+
let result = 0;
|
|
305
|
+
let prevValue = 0;
|
|
306
|
+
|
|
307
|
+
// Process from right to left
|
|
308
|
+
for (let i = value.length - 1; i >= 0; i--) {
|
|
309
|
+
const char = value[i]?.toUpperCase() ?? '';
|
|
310
|
+
const current = romanValues.get(char);
|
|
311
|
+
|
|
312
|
+
if (current === undefined) {
|
|
313
|
+
throw new ValidationError(`Invalid Roman numeral character: ${char}`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (current >= prevValue) {
|
|
317
|
+
result += current;
|
|
318
|
+
} else {
|
|
319
|
+
result -= current;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
prevValue = current;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return BigInt(result);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Converts number to Roman numeral
|
|
330
|
+
*/
|
|
331
|
+
export function toRoman(
|
|
332
|
+
value: bigint | string | number,
|
|
333
|
+
options: ConversionOptions = {}
|
|
334
|
+
): string {
|
|
335
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
336
|
+
const num = Number(toBigInt(value));
|
|
337
|
+
|
|
338
|
+
if (num <= 0 || num > 3999) {
|
|
339
|
+
throw new ValidationError('Number must be between 1 and 3999 for Roman numerals');
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Define symbol pairs with proper typing
|
|
343
|
+
type RomanPair = [string, string];
|
|
344
|
+
type RomanSingle = [string];
|
|
345
|
+
type RomanSymbol = RomanPair | RomanSingle;
|
|
346
|
+
|
|
347
|
+
const romanSymbols: RomanSymbol[] = [
|
|
348
|
+
['I', 'V'], // ones
|
|
349
|
+
['X', 'L'], // tens
|
|
350
|
+
['C', 'D'], // hundreds
|
|
351
|
+
['M'] // thousands
|
|
352
|
+
];
|
|
353
|
+
|
|
354
|
+
let result = '';
|
|
355
|
+
let position = 0;
|
|
356
|
+
let remaining = num;
|
|
357
|
+
|
|
358
|
+
while (remaining > 0) {
|
|
359
|
+
const digit = remaining % 10;
|
|
360
|
+
const symbols = romanSymbols[position];
|
|
361
|
+
|
|
362
|
+
if (!symbols) {
|
|
363
|
+
break; // Safety check for position overflow
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const unit = symbols[0];
|
|
367
|
+
const five = symbols[1] ?? '';
|
|
368
|
+
const next = position < 3 ? romanSymbols[position + 1]?.[0] ?? '' : '';
|
|
369
|
+
|
|
370
|
+
let digitStr = '';
|
|
371
|
+
if (digit === 9 && next) {
|
|
372
|
+
digitStr = unit + next;
|
|
373
|
+
} else if (digit >= 5 && five) {
|
|
374
|
+
digitStr = five + unit.repeat(digit - 5);
|
|
375
|
+
} else if (digit === 4 && five) {
|
|
376
|
+
digitStr = unit + five;
|
|
377
|
+
} else {
|
|
378
|
+
digitStr = unit.repeat(digit);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
result = digitStr + result;
|
|
382
|
+
remaining = Math.floor(remaining / 10);
|
|
383
|
+
position++;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return opts.uppercase ? result : result.toLowerCase();
|
|
387
|
+
}
|
|
388
|
+
export default {
|
|
389
|
+
toBinary,
|
|
390
|
+
toOctal,
|
|
391
|
+
toHexadecimal,
|
|
392
|
+
toBase,
|
|
393
|
+
fromBase,
|
|
394
|
+
toFraction,
|
|
395
|
+
fromFraction,
|
|
396
|
+
fromScientific,
|
|
397
|
+
toScientific,
|
|
398
|
+
fromRoman,
|
|
399
|
+
toRoman
|
|
400
|
+
};
|