@@ -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 ( / [ e E ] / ) ;
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| */
8364function 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+
9886function 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
510502function 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
517506function printIdentityTable ( results : IdentityResult [ ] ) {
@@ -792,26 +781,23 @@ console.log('║ Summary & Recommendations
792781console . log ( '╚══════════════════════════════════════════════════════════════════════╝' ) ;
793782console . log ( '' ) ;
794783console . 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' ) ;
803793console . log ( '' ) ;
804794console . 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' ) ;
809797console . log ( '' ) ;
810798console . 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' ) ;
815801console . log ( '' ) ;
816802
817803// Restore defaults
0 commit comments