Skip to content

Commit 5630693

Browse files
committed
test
1 parent 256572d commit 5630693

1 file changed

Lines changed: 31 additions & 45 deletions

File tree

test/big-decimal/comprehensive-benchmark.ts

Lines changed: 31 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -60,25 +60,6 @@ function bench(
6060
return { name, bdMs, djMs, speedup: djMs / bdMs };
6161
}
6262

63-
function sigDigits(s: string): string {
64-
if (s.startsWith('-') || s.startsWith('+')) s = s.slice(1);
65-
const eIdx = s.search(/[eE]/);
66-
if (eIdx !== -1) s = s.slice(0, eIdx);
67-
s = s.replace('.', '');
68-
s = s.replace(/^0+/, '');
69-
return s;
70-
}
71-
72-
function matchingDigits(a: string, b: string): number {
73-
const da = sigDigits(a);
74-
const db = sigDigits(b);
75-
const len = Math.min(da.length, db.length);
76-
for (let i = 0; i < len; i++) {
77-
if (da[i] !== db[i]) return i;
78-
}
79-
return len;
80-
}
81-
8263
/** Compute relative error: |approx - exact| / |exact| */
8364
function relativeError(approx: string, exact: string): number {
8465
// Use BigDecimal at high precision for the comparison
@@ -95,6 +76,13 @@ function relativeError(approx: string, exact: string): number {
9576
return err;
9677
}
9778

79+
/** Derive the number of correct significant digits from relative error. */
80+
function correctDigits(relErr: number): number {
81+
if (relErr === 0) return Infinity;
82+
if (!isFinite(relErr)) return 0;
83+
return Math.max(0, Math.floor(-Math.log10(relErr)));
84+
}
85+
9886
function withPrecision<T>(prec: number, fn: () => T): T {
9987
const savedBD = BigDecimal.precision;
10088
const savedDJ = Decimal.precision;
@@ -144,8 +132,10 @@ function printAccuracyTable(results: AccuracyResult[]) {
144132
` ${'─'.repeat(25)} ${'─'.repeat(5)} ${'─'.repeat(10)} ${'─'.repeat(10)} ${'─'.repeat(12)} ${'─'.repeat(12)}`
145133
);
146134
for (const r of results) {
147-
const bdDig = r.bdDigits === r.precision ? `${r.bdDigits} ✓` : `${r.bdDigits}`;
148-
const djDig = r.djDigits === r.precision ? `${r.djDigits} ✓` : `${r.djDigits}`;
135+
const bdDig = r.bdDigits === Infinity ? '∞ (exact)' :
136+
r.bdDigits >= r.precision ? `${r.bdDigits} ✓` : `${r.bdDigits}`;
137+
const djDig = r.djDigits === Infinity ? '∞ (exact)' :
138+
r.djDigits >= r.precision ? `${r.djDigits} ✓` : `${r.djDigits}`;
149139
const bdErr = r.bdRelErr === 0 ? '0' : r.bdRelErr.toExponential(2);
150140
const djErr = r.djRelErr === 0 ? '0' : r.djRelErr.toExponential(2);
151141
console.log(
@@ -475,13 +465,15 @@ for (const prec of [50, 100, 500]) {
475465
const dj = test.djFn(prec);
476466
const ref = REFS[test.refKey];
477467

468+
const bdRelErr = relativeError(bd, ref);
469+
const djRelErr = relativeError(dj, ref);
478470
results.push({
479471
name: test.name,
480472
precision: prec,
481-
bdDigits: matchingDigits(bd, ref),
482-
djDigits: matchingDigits(dj, ref),
483-
bdRelErr: relativeError(bd, ref),
484-
djRelErr: relativeError(dj, ref),
473+
bdDigits: correctDigits(bdRelErr),
474+
djDigits: correctDigits(djRelErr),
475+
bdRelErr,
476+
djRelErr,
485477
});
486478
}
487479

@@ -508,10 +500,7 @@ interface IdentityResult {
508500
}
509501

510502
function identityDigits(approx: string, exact: string): number {
511-
const err = relativeError(approx, exact);
512-
if (err === 0) return Infinity;
513-
if (!isFinite(err)) return 0;
514-
return Math.max(0, Math.floor(-Math.log10(err)));
503+
return correctDigits(relativeError(approx, exact));
515504
}
516505

517506
function printIdentityTable(results: IdentityResult[]) {
@@ -792,26 +781,23 @@ console.log('║ Summary & Recommendations
792781
console.log('╚══════════════════════════════════════════════════════════════════════╝');
793782
console.log('');
794783
console.log(' Performance:');
795-
console.log(' ✓ mul: 6-7x faster (bigint native multiply vs decimal string ops)');
796-
console.log(' ✓ div: 1.6-3.3x faster, scaling advantage grows with precision');
797-
console.log(' ✓ sqrt: 7-71x faster, dramatic advantage at high precision');
798-
console.log(' ✓ exp: 7-52x faster, excellent scaling');
799-
console.log(' ✓ ln: 3-19x faster');
800-
console.log(' ✓ sin/cos: 1.4-3x faster');
801-
console.log(' ✓ atan: 48-1000x+ faster (Decimal.js is pathologically slow)');
802-
console.log(' ⚠ add/sub: ~2x slower (BigDecimal normalizes on every op)');
784+
console.log(' ✓ mul: 3-8x faster (bigint native multiply vs decimal string ops)');
785+
console.log(' ✓ div: 1.6-3.2x faster, scaling advantage grows with precision');
786+
console.log(' ✓ sqrt: 6-43x faster, dramatic advantage at high precision');
787+
console.log(' ✓ exp: 7-42x faster, excellent scaling');
788+
console.log(' ✓ ln: 3-15x faster');
789+
console.log(' ✓ sin/cos: 3-4x faster');
790+
console.log(' ✓ atan: 48-410x faster (Decimal.js is pathologically slow)');
791+
console.log(' ✓ add/sub: ~parity to 4x faster');
792+
console.log(' ✓ eq: 3-7x faster');
803793
console.log('');
804794
console.log(' Accuracy:');
805-
console.log(' ✓ Division, sqrt: full precision match');
806-
console.log(' ✓ Most transcendentals: matches or exceeds Decimal.js');
807-
console.log(' ⚠ exp(1) at prec=50: 47/50 digits (3 guard digits lost)');
808-
console.log(' ⚠ sin²+cos²=1: ~prec-2 digits (exact mul reveals rounding)');
795+
console.log(' ✓ All operations: full precision match with Decimal.js');
796+
console.log(' ✓ Identity checks (sin²+cos²=1, exp·exp⁻¹=1, etc.): full precision');
809797
console.log('');
810798
console.log(' Potential improvements:');
811-
console.log(' 1. add/sub: skip normalization for intermediate results');
812-
console.log(' 2. exp: increase guard digits from 15 to 20 for small precision');
813-
console.log(' 3. ln: investigate AGM-based algorithm for O(n·M(n)) scaling');
814-
console.log(' 4. sin/cos: the speedup diminishes at high prec — check scaling');
799+
console.log(' 1. ln: investigate AGM-based algorithm for O(n·M(n)) scaling');
800+
console.log(' 2. Binary splitting for exp/sin/cos Taylor series');
815801
console.log('');
816802

817803
// Restore defaults

0 commit comments

Comments
 (0)