@obinexusmk2/hypernum 0.1.0 → 0.1.1

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.
Files changed (140) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +355 -256
  3. package/dist/index.cjs +4 -8
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +4 -7
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.umd.js +2 -2
  9. package/dist/index.umd.js.map +1 -1
  10. package/dist/types/{config → src/config}/config-loader.d.ts +0 -0
  11. package/dist/types/src/config/config-loader.d.ts.map +1 -0
  12. package/dist/types/{config → src/config}/config-parser.d.ts +0 -0
  13. package/dist/types/src/config/config-parser.d.ts.map +1 -0
  14. package/dist/types/{config → src/config}/config-resolver.d.ts +0 -0
  15. package/dist/types/src/config/config-resolver.d.ts.map +1 -0
  16. package/dist/types/{config → src/config}/config-source.d.ts +0 -0
  17. package/dist/types/src/config/config-source.d.ts.map +1 -0
  18. package/dist/types/{config → src/config}/index.d.ts +0 -0
  19. package/dist/types/src/config/index.d.ts.map +1 -0
  20. package/dist/types/{core → src/core}/common.d.ts +0 -0
  21. package/dist/types/src/core/common.d.ts.map +1 -0
  22. package/dist/types/{core → src/core}/config.d.ts +0 -0
  23. package/dist/types/src/core/config.d.ts.map +1 -0
  24. package/dist/types/{core → src/core}/constants.d.ts +0 -0
  25. package/dist/types/src/core/constants.d.ts.map +1 -0
  26. package/dist/types/{core → src/core}/errors.d.ts +0 -0
  27. package/dist/types/src/core/errors.d.ts.map +1 -0
  28. package/dist/types/{core → src/core}/hypernum.d.ts +0 -0
  29. package/dist/types/src/core/hypernum.d.ts.map +1 -0
  30. package/dist/types/{core → src/core}/index.d.ts +0 -0
  31. package/dist/types/src/core/index.d.ts.map +1 -0
  32. package/dist/types/{index.d.ts → src/index.d.ts} +1 -1
  33. package/dist/types/src/index.d.ts.map +1 -0
  34. package/dist/types/{operations → src/operations}/arithmetic.d.ts +0 -0
  35. package/dist/types/src/operations/arithmetic.d.ts.map +1 -0
  36. package/dist/types/{operations → src/operations}/bitwise.d.ts +0 -0
  37. package/dist/types/src/operations/bitwise.d.ts.map +1 -0
  38. package/dist/types/{operations → src/operations}/comparison.d.ts +0 -0
  39. package/dist/types/src/operations/comparison.d.ts.map +1 -0
  40. package/dist/types/{operations → src/operations}/conversion.d.ts +0 -0
  41. package/dist/types/src/operations/conversion.d.ts.map +1 -0
  42. package/dist/types/{operations → src/operations}/factorial.d.ts +0 -0
  43. package/dist/types/src/operations/factorial.d.ts.map +1 -0
  44. package/dist/types/{operations → src/operations}/index.d.ts +0 -0
  45. package/dist/types/src/operations/index.d.ts.map +1 -0
  46. package/dist/types/{operations → src/operations}/power.d.ts +0 -0
  47. package/dist/types/src/operations/power.d.ts.map +1 -0
  48. package/dist/types/{storage → src/storage}/Heap.d.ts +0 -0
  49. package/dist/types/src/storage/Heap.d.ts.map +1 -0
  50. package/dist/types/{storage → src/storage}/index.d.ts +0 -0
  51. package/dist/types/src/storage/index.d.ts.map +1 -0
  52. package/dist/types/{structures → src/structures}/ackermann.d.ts +0 -0
  53. package/dist/types/src/structures/ackermann.d.ts.map +1 -0
  54. package/dist/types/{structures → src/structures}/big-array.d.ts +0 -0
  55. package/dist/types/src/structures/big-array.d.ts.map +1 -0
  56. package/dist/types/{structures → src/structures}/index.d.ts +0 -0
  57. package/dist/types/src/structures/index.d.ts.map +1 -0
  58. package/dist/types/{structures → src/structures}/number-tree.d.ts +0 -0
  59. package/dist/types/src/structures/number-tree.d.ts.map +1 -0
  60. package/dist/types/{structures → src/structures}/power-tower.d.ts +0 -0
  61. package/dist/types/src/structures/power-tower.d.ts.map +1 -0
  62. package/dist/types/{utils → src/utils}/formatting.d.ts +0 -0
  63. package/dist/types/src/utils/formatting.d.ts.map +1 -0
  64. package/dist/types/{utils → src/utils}/index.d.ts +0 -0
  65. package/dist/types/src/utils/index.d.ts.map +1 -0
  66. package/dist/types/{utils → src/utils}/parser.d.ts +0 -0
  67. package/dist/types/src/utils/parser.d.ts.map +1 -0
  68. package/dist/types/{utils → src/utils}/precision.d.ts +0 -0
  69. package/dist/types/src/utils/precision.d.ts.map +1 -0
  70. package/dist/types/{utils → src/utils}/validation.d.ts +0 -0
  71. package/dist/types/src/utils/validation.d.ts.map +1 -0
  72. package/package.json +169 -164
  73. package/rollup.config.js +163 -161
  74. package/src/cli/hypernum.js +272 -0
  75. package/src/config/config-loader.ts +0 -0
  76. package/src/config/config-parser.ts +160 -160
  77. package/src/config/config-resolver.ts +0 -0
  78. package/src/config/config-source.ts +0 -0
  79. package/src/config/index.ts +0 -0
  80. package/src/core/common.ts +184 -184
  81. package/src/core/config.ts +392 -392
  82. package/src/core/constants.ts +101 -101
  83. package/src/core/errors.ts +202 -202
  84. package/src/core/hypernum.ts +240 -240
  85. package/src/core/index.ts +4 -4
  86. package/src/index.ts +179 -182
  87. package/src/operations/arithmetic.ts +332 -332
  88. package/src/operations/bitwise.ts +366 -366
  89. package/src/operations/comparison.ts +271 -271
  90. package/src/operations/conversion.ts +399 -399
  91. package/src/operations/factorial.ts +278 -278
  92. package/src/operations/index.ts +4 -4
  93. package/src/operations/power.ts +315 -315
  94. package/src/storage/Heap.ts +237 -237
  95. package/src/storage/index.ts +0 -0
  96. package/src/structures/ackermann.ts +232 -232
  97. package/src/structures/big-array.ts +305 -305
  98. package/src/structures/index.ts +3 -3
  99. package/src/structures/number-tree.ts +403 -403
  100. package/src/structures/power-tower.ts +277 -277
  101. package/src/types/common.d.ts +356 -356
  102. package/src/types/core.d.ts +160 -160
  103. package/src/types/index.d.ts +1 -1
  104. package/src/utils/formatting.ts +245 -245
  105. package/src/utils/index.ts +4 -4
  106. package/src/utils/parser.ts +244 -244
  107. package/src/utils/precision.ts +216 -216
  108. package/src/utils/validation.ts +182 -182
  109. package/tsconfig.json +83 -83
  110. package/dist/types/config/config-loader.d.ts.map +0 -1
  111. package/dist/types/config/config-parser.d.ts.map +0 -1
  112. package/dist/types/config/config-resolver.d.ts.map +0 -1
  113. package/dist/types/config/config-source.d.ts.map +0 -1
  114. package/dist/types/config/index.d.ts.map +0 -1
  115. package/dist/types/core/common.d.ts.map +0 -1
  116. package/dist/types/core/config.d.ts.map +0 -1
  117. package/dist/types/core/constants.d.ts.map +0 -1
  118. package/dist/types/core/errors.d.ts.map +0 -1
  119. package/dist/types/core/hypernum.d.ts.map +0 -1
  120. package/dist/types/core/index.d.ts.map +0 -1
  121. package/dist/types/index.d.ts.map +0 -1
  122. package/dist/types/operations/arithmetic.d.ts.map +0 -1
  123. package/dist/types/operations/bitwise.d.ts.map +0 -1
  124. package/dist/types/operations/comparison.d.ts.map +0 -1
  125. package/dist/types/operations/conversion.d.ts.map +0 -1
  126. package/dist/types/operations/factorial.d.ts.map +0 -1
  127. package/dist/types/operations/index.d.ts.map +0 -1
  128. package/dist/types/operations/power.d.ts.map +0 -1
  129. package/dist/types/storage/Heap.d.ts.map +0 -1
  130. package/dist/types/storage/index.d.ts.map +0 -1
  131. package/dist/types/structures/ackermann.d.ts.map +0 -1
  132. package/dist/types/structures/big-array.d.ts.map +0 -1
  133. package/dist/types/structures/index.d.ts.map +0 -1
  134. package/dist/types/structures/number-tree.d.ts.map +0 -1
  135. package/dist/types/structures/power-tower.d.ts.map +0 -1
  136. package/dist/types/utils/formatting.d.ts.map +0 -1
  137. package/dist/types/utils/index.d.ts.map +0 -1
  138. package/dist/types/utils/parser.d.ts.map +0 -1
  139. package/dist/types/utils/precision.d.ts.map +0 -1
  140. package/dist/types/utils/validation.d.ts.map +0 -1
@@ -1,400 +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
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
400
  };