Skip to content

Commit 505dc0d

Browse files
committed
fix: rewrite Wald mode formula in numerically stable rationalized form
Multiplying numerator and denominator by the conjugate avoids catastrophic cancellation in sqrt(4*lambda^2 + 9*mu^2) - 3*mu when lambda << mu, dropping max ULP error against the Julia fixtures from ~874 to ~298. Tighten the test tolerance accordingly.
1 parent 0150602 commit 505dc0d

4 files changed

Lines changed: 4 additions & 8 deletions

File tree

lib/node_modules/@stdlib/stats/base/dists/wald/mode/lib/main.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ var sqrt = require( '@stdlib/math/base/special/sqrt' );
5454
* // returns NaN
5555
*/
5656
function mode( mu, lambda ) {
57-
var numerator;
5857
if (
5958
isnan( mu ) ||
6059
isnan( lambda ) ||
@@ -63,8 +62,7 @@ function mode( mu, lambda ) {
6362
) {
6463
return NaN;
6564
}
66-
numerator = sqrt( 4.0*lambda*lambda + 9.0*mu*mu ) - 3.0*mu;
67-
return ( mu*numerator ) / ( 2.0*lambda );
65+
return ( 2.0*mu*lambda ) / ( sqrt( 4.0*lambda*lambda + 9.0*mu*mu ) + 3.0*mu );
6866
}
6967

7068

lib/node_modules/@stdlib/stats/base/dists/wald/mode/src/main.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
* // returns ~0.325
3333
*/
3434
double stdlib_base_dists_wald_mode( const double mu, const double lambda ) {
35-
double numerator;
3635
if (
3736
stdlib_base_is_nan( mu ) ||
3837
stdlib_base_is_nan( lambda ) ||
@@ -41,6 +40,5 @@ double stdlib_base_dists_wald_mode( const double mu, const double lambda ) {
4140
) {
4241
return 0.0/0.0; // NaN
4342
}
44-
numerator = stdlib_base_sqrt( 4.0*lambda*lambda + 9.0*mu*mu ) - 3.0*mu;
45-
return mu * numerator / ( 2.0*lambda );
43+
return ( 2.0*mu*lambda ) / ( stdlib_base_sqrt( 4.0*lambda*lambda + 9.0*mu*mu ) + 3.0*mu );
4644
}

lib/node_modules/@stdlib/stats/base/dists/wald/mode/test/test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ tape( 'the function returns the mode of a Wald distribution', function test( t )
117117
if ( y === expected[i] ) {
118118
t.strictEqual( y, expected[i], 'mu:'+mu[i]+', lambda: '+lambda[i]+', y: '+y+', expected: '+expected[i] );
119119
} else {
120-
t.ok( isAlmostSameValue( y, expected[i], 1000 ), 'within tolerance. mu: '+mu[i]+'. lambda: '+lambda[i]+'. y: '+y+'. E: '+expected[ i ]+'.' );
120+
t.ok( isAlmostSameValue( y, expected[i], 500 ), 'within tolerance. mu: '+mu[i]+'. lambda: '+lambda[i]+'. y: '+y+'. E: '+expected[ i ]+'.' );
121121
}
122122
}
123123
t.end();

lib/node_modules/@stdlib/stats/base/dists/wald/mode/test/test.native.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ tape( 'the function returns the mode of a Wald distribution', opts, function tes
126126
if ( y === expected[i] ) {
127127
t.strictEqual( y, expected[i], 'mu:'+mu[i]+', lambda: '+lambda[i]+', y: '+y+', expected: '+expected[i] );
128128
} else {
129-
t.ok( isAlmostSameValue( y, expected[i], 1000 ), 'within tolerance. mu: '+mu[i]+'. lambda: '+lambda[i]+'. y: '+y+'. E: '+expected[ i ]+'.' );
129+
t.ok( isAlmostSameValue( y, expected[i], 500 ), 'within tolerance. mu: '+mu[i]+'. lambda: '+lambda[i]+'. y: '+y+'. E: '+expected[ i ]+'.' );
130130
}
131131
}
132132
t.end();

0 commit comments

Comments
 (0)