@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,161 @@
|
|
|
1
|
+
|
|
2
|
+
import { RoundingMode } from '../utils/precision';
|
|
3
|
+
import {
|
|
4
|
+
CacheConfig,
|
|
5
|
+
MathConstantsConfig,
|
|
6
|
+
FormatOptions,
|
|
7
|
+
DebugConfig
|
|
8
|
+
} from './common';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Basic configuration options for simple usage
|
|
12
|
+
*/
|
|
13
|
+
export interface BasicConfig {
|
|
14
|
+
/** Decimal precision for operations */
|
|
15
|
+
precision?: number;
|
|
16
|
+
/** Rounding mode for decimal operations */
|
|
17
|
+
roundingMode?: RoundingMode;
|
|
18
|
+
/** Whether to check for overflow */
|
|
19
|
+
checkOverflow?: boolean;
|
|
20
|
+
/** Maximum allowed computation steps */
|
|
21
|
+
maxSteps?: number;
|
|
22
|
+
/** Enable debug mode */
|
|
23
|
+
debug?: boolean;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Configuration for arithmetic operations
|
|
28
|
+
*/
|
|
29
|
+
export interface ArithmeticConfig {
|
|
30
|
+
/** Default precision for decimal operations */
|
|
31
|
+
defaultPrecision: number;
|
|
32
|
+
/** Default rounding mode */
|
|
33
|
+
defaultRoundingMode: RoundingMode;
|
|
34
|
+
/** Whether to check for overflow by default */
|
|
35
|
+
checkOverflow: boolean;
|
|
36
|
+
/** Maximum steps for iterative calculations */
|
|
37
|
+
maxComputationSteps: number;
|
|
38
|
+
/** Configure automatic precision adjustment */
|
|
39
|
+
autoPrecision: {
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
maxPrecision: number;
|
|
42
|
+
minPrecision: number;
|
|
43
|
+
};
|
|
44
|
+
/** Constants calculation configuration */
|
|
45
|
+
constants: MathConstantsConfig;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Configuration for data structures
|
|
50
|
+
*/
|
|
51
|
+
export interface DataStructuresConfig {
|
|
52
|
+
/** Array configuration */
|
|
53
|
+
array: {
|
|
54
|
+
initialCapacity: number;
|
|
55
|
+
growthFactor: number;
|
|
56
|
+
maxSize: number;
|
|
57
|
+
};
|
|
58
|
+
/** Tree configuration */
|
|
59
|
+
tree: {
|
|
60
|
+
maxDepth: number;
|
|
61
|
+
autoBalance: boolean;
|
|
62
|
+
nodeLimit: number;
|
|
63
|
+
};
|
|
64
|
+
/** Heap configuration */
|
|
65
|
+
heap: {
|
|
66
|
+
initialCapacity: number;
|
|
67
|
+
growthPolicy: 'double' | 'linear' | 'fibonacci';
|
|
68
|
+
validatePropertyOnOperation: boolean;
|
|
69
|
+
};
|
|
70
|
+
/** Cache configuration */
|
|
71
|
+
cache: CacheConfig & {
|
|
72
|
+
enabled: boolean;
|
|
73
|
+
persistToDisk: boolean;
|
|
74
|
+
compressionEnabled: boolean;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Configuration for number formatting
|
|
80
|
+
*/
|
|
81
|
+
export interface FormattingConfig extends FormatOptions {
|
|
82
|
+
/** Scientific notation configuration */
|
|
83
|
+
scientific: {
|
|
84
|
+
minExponent: number;
|
|
85
|
+
maxSignificantDigits: number;
|
|
86
|
+
exponentSeparator: string;
|
|
87
|
+
};
|
|
88
|
+
/** Engineering notation configuration */
|
|
89
|
+
engineering: {
|
|
90
|
+
useSIPrefixes: boolean;
|
|
91
|
+
customUnits?: Map<number, string>;
|
|
92
|
+
};
|
|
93
|
+
/** Localization settings */
|
|
94
|
+
localization: {
|
|
95
|
+
locale: string;
|
|
96
|
+
numberFormat?: Intl.NumberFormatOptions;
|
|
97
|
+
useLocaleGrouping: boolean;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Configuration for performance monitoring
|
|
103
|
+
*/
|
|
104
|
+
export interface PerformanceConfig {
|
|
105
|
+
/** Enable performance tracking */
|
|
106
|
+
enableTracking: boolean;
|
|
107
|
+
/** Sampling rate for metrics (0-1) */
|
|
108
|
+
samplingRate: number;
|
|
109
|
+
/** Performance thresholds */
|
|
110
|
+
thresholds: {
|
|
111
|
+
warnThresholdMs: number;
|
|
112
|
+
errorThresholdMs: number;
|
|
113
|
+
maxMemoryBytes: number;
|
|
114
|
+
};
|
|
115
|
+
/** Metrics collection configuration */
|
|
116
|
+
metrics: {
|
|
117
|
+
timing: boolean;
|
|
118
|
+
memory: boolean;
|
|
119
|
+
cache: boolean;
|
|
120
|
+
custom?: Map<string, (operation: any) => number>;
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Feature flags for optional functionality
|
|
126
|
+
*/
|
|
127
|
+
export interface FeatureFlags {
|
|
128
|
+
/** Enable experimental features */
|
|
129
|
+
experimentalFeatures: boolean;
|
|
130
|
+
/** Use WebAssembly implementations when available */
|
|
131
|
+
useWasm: boolean;
|
|
132
|
+
/** Enable worker thread support */
|
|
133
|
+
workerThreads: boolean;
|
|
134
|
+
/** Enable SharedArrayBuffer support */
|
|
135
|
+
sharedArrayBuffer: boolean;
|
|
136
|
+
/** Enable BigInt64Array support */
|
|
137
|
+
bigIntTypedArrays: boolean;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Complete configuration interface
|
|
142
|
+
*/
|
|
143
|
+
export interface FullConfig {
|
|
144
|
+
/** Arithmetic operation configuration */
|
|
145
|
+
arithmetic: ArithmeticConfig;
|
|
146
|
+
/** Data structure configuration */
|
|
147
|
+
dataStructures: DataStructuresConfig;
|
|
148
|
+
/** Formatting configuration */
|
|
149
|
+
formatting: FormattingConfig;
|
|
150
|
+
/** Performance configuration */
|
|
151
|
+
performance: PerformanceConfig;
|
|
152
|
+
/** Debug configuration */
|
|
153
|
+
debug: DebugConfig;
|
|
154
|
+
/** Feature flags */
|
|
155
|
+
features: FeatureFlags;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Combined configuration type that can be either basic or full
|
|
160
|
+
*/
|
|
161
|
+
export type HypernumConfig = BasicConfig | FullConfig;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting utilities for Hypernum library
|
|
3
|
+
* Provides functions for formatting large numbers and converting between different representations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ValidationError } from './validation';
|
|
7
|
+
|
|
8
|
+
// Types for formatting options
|
|
9
|
+
export interface FormatOptions {
|
|
10
|
+
notation?: 'standard' | 'scientific' | 'engineering' | 'compact';
|
|
11
|
+
precision?: number;
|
|
12
|
+
grouping?: boolean;
|
|
13
|
+
groupSize?: number;
|
|
14
|
+
decimalSeparator?: string;
|
|
15
|
+
groupSeparator?: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface ScientificNotation {
|
|
19
|
+
coefficient: string;
|
|
20
|
+
exponent: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ScientificNotation {
|
|
24
|
+
coefficient: string;
|
|
25
|
+
exponent: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Default formatting options
|
|
29
|
+
const DEFAULT_OPTIONS: Required<FormatOptions> = {
|
|
30
|
+
notation: 'standard',
|
|
31
|
+
precision: 0,
|
|
32
|
+
grouping: true,
|
|
33
|
+
groupSize: 3,
|
|
34
|
+
decimalSeparator: '.',
|
|
35
|
+
groupSeparator: ',',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Formats a BigInt value according to specified options
|
|
40
|
+
*/
|
|
41
|
+
export const formatBigInt = (value: bigint, options: FormatOptions = {}): string => {
|
|
42
|
+
const opts: Required<FormatOptions> = { ...DEFAULT_OPTIONS, ...options };
|
|
43
|
+
|
|
44
|
+
// Handle negative numbers
|
|
45
|
+
const isNegative = value < BigInt(0);
|
|
46
|
+
const absValue = isNegative ? -value : value;
|
|
47
|
+
|
|
48
|
+
let result: string;
|
|
49
|
+
switch (opts.notation) {
|
|
50
|
+
case 'scientific':
|
|
51
|
+
result = formatScientific(absValue, opts).coefficient + 'e' +
|
|
52
|
+
formatScientific(absValue, opts).exponent;
|
|
53
|
+
break;
|
|
54
|
+
case 'engineering':
|
|
55
|
+
result = formatEngineering(absValue, opts);
|
|
56
|
+
break;
|
|
57
|
+
case 'compact':
|
|
58
|
+
result = formatCompact(absValue, opts);
|
|
59
|
+
break;
|
|
60
|
+
default:
|
|
61
|
+
result = formatStandard(absValue, opts);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return isNegative ? '-' + result : result;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Formats a number in standard notation with grouping
|
|
69
|
+
*/
|
|
70
|
+
const formatStandard = (value: bigint, options: Required<FormatOptions>): string => {
|
|
71
|
+
let str = value.toString();
|
|
72
|
+
|
|
73
|
+
if (!options.grouping) {
|
|
74
|
+
return str;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Apply grouping from the right
|
|
78
|
+
const result: string[] = [];
|
|
79
|
+
let position = str.length;
|
|
80
|
+
|
|
81
|
+
while (position > 0) {
|
|
82
|
+
const start = Math.max(0, position - options.groupSize);
|
|
83
|
+
result.unshift(str.slice(start, position));
|
|
84
|
+
position = start;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result.join(options.groupSeparator);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Converts a number to scientific notation
|
|
92
|
+
*/
|
|
93
|
+
const formatScientific = (value: bigint, options: Required<FormatOptions>): ScientificNotation => {
|
|
94
|
+
if (value === BigInt(0)) {
|
|
95
|
+
return { coefficient: '0', exponent: 0 };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const str = value.toString();
|
|
99
|
+
const exponent = str.length - 1;
|
|
100
|
+
|
|
101
|
+
let coefficient = str[0] || '';
|
|
102
|
+
coefficient += options.decimalSeparator + str.slice(1, options.precision + 1);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
coefficient: coefficient,
|
|
106
|
+
exponent: exponent,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Formats a number in engineering notation (exponents divisible by 3)
|
|
112
|
+
*/
|
|
113
|
+
const formatEngineering = (value: bigint, options: Required<FormatOptions>): string => {
|
|
114
|
+
if (value === BigInt(0)) {
|
|
115
|
+
return '0';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const str = value.toString();
|
|
119
|
+
const len = str.length;
|
|
120
|
+
const exponent = Math.floor((len - 1) / 3) * 3;
|
|
121
|
+
|
|
122
|
+
let coefficient = '';
|
|
123
|
+
const digitsBeforePoint = len - exponent;
|
|
124
|
+
|
|
125
|
+
for (let i = 0; i < Math.min(len, digitsBeforePoint + options.precision); i++) {
|
|
126
|
+
if (i === digitsBeforePoint && i < len) {
|
|
127
|
+
coefficient += options.decimalSeparator;
|
|
128
|
+
}
|
|
129
|
+
coefficient += str[i];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return `${coefficient}e${exponent}`;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Formats a number in compact notation (K, M, B, T)
|
|
137
|
+
*/
|
|
138
|
+
const formatCompact = (value: bigint, options: Required<FormatOptions>): string => {
|
|
139
|
+
const suffixes = ['', 'K', 'M', 'B', 'T', 'Q'];
|
|
140
|
+
const str = value.toString();
|
|
141
|
+
const len = str.length;
|
|
142
|
+
|
|
143
|
+
if (len <= 3) {
|
|
144
|
+
return formatStandard(value, options);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const suffixIndex = Math.min(Math.floor((len - 1) / 3), suffixes.length - 1);
|
|
148
|
+
const suffix = suffixes[suffixIndex];
|
|
149
|
+
|
|
150
|
+
const scale = BigInt(10) ** BigInt(suffixIndex * 3);
|
|
151
|
+
const scaledValue = value / scale;
|
|
152
|
+
|
|
153
|
+
let result = scaledValue.toString();
|
|
154
|
+
if (options.precision > 0) {
|
|
155
|
+
const remainder = value % scale;
|
|
156
|
+
if (remainder > BigInt(0)) {
|
|
157
|
+
const decimalPart = remainder.toString().padStart(3, '0').slice(0, options.precision);
|
|
158
|
+
result += options.decimalSeparator + decimalPart;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return result + suffix;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Parses a formatted string back to BigInt
|
|
167
|
+
*/
|
|
168
|
+
export const parseBigIntString = (str: string, options: FormatOptions = {}): bigint => {
|
|
169
|
+
const opts: Required<FormatOptions> = { ...DEFAULT_OPTIONS, ...options };
|
|
170
|
+
|
|
171
|
+
// Remove grouping separators
|
|
172
|
+
let cleanStr = str.replace(new RegExp(`\\${opts.groupSeparator}`, 'g'), '');
|
|
173
|
+
|
|
174
|
+
// Handle scientific notation
|
|
175
|
+
if (cleanStr.toLowerCase().includes('e')) {
|
|
176
|
+
const [coefficient, exponent] = cleanStr.toLowerCase().split('e');
|
|
177
|
+
const base = BigInt(10);
|
|
178
|
+
const exp = BigInt(exponent || '0');
|
|
179
|
+
return BigInt(Math.floor(Number(coefficient))) * (base ** exp);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Handle suffixes
|
|
183
|
+
const suffixMap = new Map([
|
|
184
|
+
['k', BigInt(1000)],
|
|
185
|
+
['m', BigInt(1000000)],
|
|
186
|
+
['b', BigInt(1000000000)],
|
|
187
|
+
['t', BigInt(1000000000000)],
|
|
188
|
+
['q', BigInt(1000000000000000)],
|
|
189
|
+
]);
|
|
190
|
+
|
|
191
|
+
const suffix = cleanStr.slice(-1).toLowerCase();
|
|
192
|
+
const multiplier = suffixMap.get(suffix);
|
|
193
|
+
if (multiplier) {
|
|
194
|
+
cleanStr = cleanStr.slice(0, -1);
|
|
195
|
+
const value = BigInt(Math.floor(Number(cleanStr)));
|
|
196
|
+
return value * multiplier;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Handle regular numbers
|
|
200
|
+
return BigInt(cleanStr);
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Normalizes a string representation for comparison
|
|
205
|
+
*/
|
|
206
|
+
export const normalizeNumberString = (str: string): string => {
|
|
207
|
+
// Remove all spaces and separators
|
|
208
|
+
str = str.replace(/[\s,]/g, '');
|
|
209
|
+
|
|
210
|
+
// Handle scientific notation
|
|
211
|
+
if (str.toLowerCase().includes('e')) {
|
|
212
|
+
const [coefficient, exponent] = str.toLowerCase().split('e');
|
|
213
|
+
const exp = parseInt(exponent || '0');
|
|
214
|
+
const coef = parseFloat(coefficient || '0');
|
|
215
|
+
return (coef * Math.pow(10, exp)).toString();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return str;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Formats a number for display in a tree structure
|
|
223
|
+
*/
|
|
224
|
+
export const formatTreeValue = (value: bigint, depth: number = 0): string => {
|
|
225
|
+
const indent = ' '.repeat(depth);
|
|
226
|
+
return `${indent}${formatBigInt(value, { notation: 'compact' })}`;
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Formats a range of numbers for display
|
|
231
|
+
*/
|
|
232
|
+
export const formatRange = (start: bigint, end: bigint, options: FormatOptions = {}): string => {
|
|
233
|
+
return `[${formatBigInt(start, options)} ... ${formatBigInt(end, options)}]`;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Formats a percentage
|
|
238
|
+
*/
|
|
239
|
+
export const formatPercentage = (value: bigint, total: bigint, precision: number = 2): string => {
|
|
240
|
+
if (total === BigInt(0)) {
|
|
241
|
+
throw new ValidationError('Cannot calculate percentage with zero total');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const percentage = (Number(value) * 100) / Number(total);
|
|
245
|
+
return `${percentage.toFixed(precision)}%`;
|
|
246
|
+
};
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser utilities for Hypernum library
|
|
3
|
+
* Provides functions for parsing various number formats and notations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ValidationError } from './validation';
|
|
7
|
+
import { RoundingMode } from './precision';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Supported number format types
|
|
11
|
+
*/
|
|
12
|
+
export enum NumberFormat {
|
|
13
|
+
STANDARD = 'STANDARD', // Regular decimal notation
|
|
14
|
+
SCIENTIFIC = 'SCIENTIFIC', // Scientific notation (e.g., 1.23e4)
|
|
15
|
+
ENGINEERING = 'ENGINEERING', // Engineering notation (e.g., 1.23e6)
|
|
16
|
+
COMPACT = 'COMPACT', // Compact notation with suffixes (e.g., 1.23M)
|
|
17
|
+
FRACTION = 'FRACTION', // Fractional notation (e.g., 1/3)
|
|
18
|
+
PERCENTAGE = 'PERCENTAGE', // Percentage notation (e.g., 12.3%)
|
|
19
|
+
HEXADECIMAL = 'HEXADECIMAL', // Hex notation (e.g., 0xFF)
|
|
20
|
+
BINARY = 'BINARY', // Binary notation (e.g., 0b1010)
|
|
21
|
+
OCTAL = 'OCTAL' // Octal notation (e.g., 0o777)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options for parsing numbers
|
|
26
|
+
*/
|
|
27
|
+
export interface ParseOptions {
|
|
28
|
+
format?: NumberFormat;
|
|
29
|
+
base?: number;
|
|
30
|
+
allowFractions?: boolean;
|
|
31
|
+
rounding?: RoundingMode;
|
|
32
|
+
precision?: number;
|
|
33
|
+
strict?: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const DEFAULT_PARSE_OPTIONS: Required<ParseOptions> = {
|
|
37
|
+
format: NumberFormat.STANDARD,
|
|
38
|
+
base: 10,
|
|
39
|
+
allowFractions: false,
|
|
40
|
+
rounding: RoundingMode.HALF_EVEN,
|
|
41
|
+
precision: 0,
|
|
42
|
+
strict: true
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Parse any supported number format to BigInt
|
|
47
|
+
*/
|
|
48
|
+
export const parseNumber = (input: string, options: ParseOptions = {}): bigint => {
|
|
49
|
+
const opts: Required<ParseOptions> = { ...DEFAULT_PARSE_OPTIONS, ...options };
|
|
50
|
+
|
|
51
|
+
// Remove whitespace if not in strict mode
|
|
52
|
+
const str = opts.strict ? input : input.trim();
|
|
53
|
+
|
|
54
|
+
if (str === '') {
|
|
55
|
+
throw new ValidationError('Empty string cannot be parsed as a number');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
switch (opts.format) {
|
|
60
|
+
case NumberFormat.SCIENTIFIC:
|
|
61
|
+
case NumberFormat.ENGINEERING:
|
|
62
|
+
return parseScientificNotation(str);
|
|
63
|
+
case NumberFormat.COMPACT:
|
|
64
|
+
return parseCompactNotation(str);
|
|
65
|
+
case NumberFormat.FRACTION:
|
|
66
|
+
return parseFraction(str, opts.rounding, opts.precision);
|
|
67
|
+
case NumberFormat.PERCENTAGE:
|
|
68
|
+
return parsePercentage(str);
|
|
69
|
+
case NumberFormat.HEXADECIMAL:
|
|
70
|
+
return parseBaseNotation(str, 16);
|
|
71
|
+
case NumberFormat.BINARY:
|
|
72
|
+
return parseBaseNotation(str, 2);
|
|
73
|
+
case NumberFormat.OCTAL:
|
|
74
|
+
return parseBaseNotation(str, 8);
|
|
75
|
+
default:
|
|
76
|
+
return parseStandardNotation(str);
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (error instanceof ValidationError) {
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
throw new ValidationError(`Failed to parse number: ${input}`);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Parse standard decimal notation
|
|
88
|
+
*/
|
|
89
|
+
const parseStandardNotation = (str: string): bigint => {
|
|
90
|
+
// Remove commas and validate format
|
|
91
|
+
const cleanStr = str.replace(/,/g, '');
|
|
92
|
+
if (!/^-?\d+$/.test(cleanStr)) {
|
|
93
|
+
throw new ValidationError('Invalid standard notation format');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return BigInt(cleanStr);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Parse scientific notation (e.g., 1.23e4)
|
|
101
|
+
*/
|
|
102
|
+
const parseScientificNotation = (str: string): bigint => {
|
|
103
|
+
const match = str.match(/^(-?\d*\.?\d+)e([+-]?\d+)$/i);
|
|
104
|
+
if (!match) {
|
|
105
|
+
throw new ValidationError('Invalid scientific notation format');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const [, coefficient, exponent] = match;
|
|
109
|
+
if (!coefficient) {
|
|
110
|
+
throw new ValidationError('Invalid scientific notation format');
|
|
111
|
+
}
|
|
112
|
+
const [intPart, fracPart = ''] = coefficient.split('.');
|
|
113
|
+
const normalizedCoef = intPart + fracPart;
|
|
114
|
+
const adjustedExp = parseInt(exponent || '0') - fracPart.length;
|
|
115
|
+
|
|
116
|
+
if (adjustedExp >= 0) {
|
|
117
|
+
return BigInt(normalizedCoef) * (BigInt(10) ** BigInt(adjustedExp));
|
|
118
|
+
} else {
|
|
119
|
+
return BigInt(normalizedCoef) / (BigInt(10) ** BigInt(-adjustedExp));
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Parse compact notation with suffixes (e.g., 1.23M)
|
|
125
|
+
*/
|
|
126
|
+
const parseCompactNotation = (str: string): bigint => {
|
|
127
|
+
const match = str.match(/^(-?\d*\.?\d+)\s*([KMBTQ])$/i);
|
|
128
|
+
if (!match) {
|
|
129
|
+
throw new ValidationError('Invalid compact notation format');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const [, number, suffix] = match;
|
|
133
|
+
const value = parseFloat(number || '0');
|
|
134
|
+
|
|
135
|
+
const multipliers = {
|
|
136
|
+
K: 1000n,
|
|
137
|
+
M: 1000000n,
|
|
138
|
+
B: 1000000000n,
|
|
139
|
+
T: 1000000000000n,
|
|
140
|
+
Q: 1000000000000000n
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
if (!suffix) {
|
|
144
|
+
throw new ValidationError('Invalid compact notation format');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const multiplier = multipliers[suffix.toUpperCase() as keyof typeof multipliers];
|
|
148
|
+
return BigInt(Math.round(value * Number(multiplier)));
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Parse fraction notation (e.g., 1/3)
|
|
153
|
+
*/
|
|
154
|
+
const parseFraction = (
|
|
155
|
+
str: string,
|
|
156
|
+
rounding: RoundingMode = RoundingMode.HALF_EVEN,
|
|
157
|
+
precision: number = 0
|
|
158
|
+
): bigint => {
|
|
159
|
+
const [numerator, denominator] = str.split('/');
|
|
160
|
+
if (!numerator || !denominator) {
|
|
161
|
+
throw new ValidationError('Invalid fraction format');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const num = BigInt(numerator);
|
|
165
|
+
const den = BigInt(denominator);
|
|
166
|
+
|
|
167
|
+
if (den === 0n) {
|
|
168
|
+
throw new ValidationError('Division by zero in fraction');
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const scale = BigInt(10) ** BigInt(precision);
|
|
172
|
+
const scaledResult = (num * scale) / den;
|
|
173
|
+
|
|
174
|
+
// Apply rounding if needed
|
|
175
|
+
if (rounding === RoundingMode.FLOOR) {
|
|
176
|
+
return scaledResult;
|
|
177
|
+
} else if (rounding === RoundingMode.CEIL) {
|
|
178
|
+
return scaledResult + (num * scale % den === 0n ? 0n : 1n);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return scaledResult;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Parse percentage notation (e.g., 12.3%)
|
|
186
|
+
*/
|
|
187
|
+
const parsePercentage = (str: string): bigint => {
|
|
188
|
+
const match = str.match(/^(-?\d*\.?\d+)%$/);
|
|
189
|
+
if (!match) {
|
|
190
|
+
throw new ValidationError('Invalid percentage format');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const value = parseFloat(match[1] || '0');
|
|
194
|
+
return BigInt(Math.round(value * 100));
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Parse number in different bases (binary, octal, hex)
|
|
199
|
+
*/
|
|
200
|
+
const parseBaseNotation = (str: string, base: number): bigint => {
|
|
201
|
+
let cleanStr = str.toLowerCase();
|
|
202
|
+
|
|
203
|
+
// Remove prefix if present
|
|
204
|
+
const prefixes: Record<number, string> = {
|
|
205
|
+
2: '0b',
|
|
206
|
+
8: '0o',
|
|
207
|
+
16: '0x'
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const prefix = prefixes[base];
|
|
211
|
+
if (prefix && cleanStr.startsWith(prefix)) {
|
|
212
|
+
cleanStr = cleanStr.slice(2);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Validate characters based on base
|
|
216
|
+
const validChars = {
|
|
217
|
+
2: /^[01]+$/,
|
|
218
|
+
8: /^[0-7]+$/,
|
|
219
|
+
16: /^[0-9a-f]+$/
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
if (!validChars[base as keyof typeof validChars].test(cleanStr)) {
|
|
223
|
+
throw new ValidationError(`Invalid ${base}-base number format`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return BigInt(`0${prefixes[base]}${cleanStr}`);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Detect number format from string
|
|
231
|
+
*/
|
|
232
|
+
export const detectNumberFormat = (str: string): NumberFormat => {
|
|
233
|
+
const cleanStr = str.trim();
|
|
234
|
+
|
|
235
|
+
if (/^-?\d+$/.test(cleanStr)) return NumberFormat.STANDARD;
|
|
236
|
+
if (/^-?\d*\.?\d+e[+-]?\d+$/i.test(cleanStr)) return NumberFormat.SCIENTIFIC;
|
|
237
|
+
if (/^-?\d*\.?\d+[KMBTQ]$/i.test(cleanStr)) return NumberFormat.COMPACT;
|
|
238
|
+
if (/^-?\d+\/\d+$/.test(cleanStr)) return NumberFormat.FRACTION;
|
|
239
|
+
if (/^-?\d*\.?\d+%$/.test(cleanStr)) return NumberFormat.PERCENTAGE;
|
|
240
|
+
if (/^(0x|0X)[0-9a-fA-F]+$/.test(cleanStr)) return NumberFormat.HEXADECIMAL;
|
|
241
|
+
if (/^(0b|0B)[01]+$/.test(cleanStr)) return NumberFormat.BINARY;
|
|
242
|
+
if (/^(0o|0O)[0-7]+$/.test(cleanStr)) return NumberFormat.OCTAL;
|
|
243
|
+
|
|
244
|
+
throw new ValidationError('Unable to detect number format');
|
|
245
|
+
};
|