Skip to content

bug : rayleigh/mgf returns wrong values due to misplaced parenthesis #15456

Description

@AdeshDeshmukh

Description

I encountered incorrect output from @stdlib/stats/base/dists/rayleigh/mgf while cross-checking the MGF implementations against their closed forms. The Rayleigh implementation multiplies the whole (1 + ...) expression by the √(π/2)·(1 + erf) factor, when that factor should only multiply the σt term.

The current code in lib/main.js (and identically in lib/factory.js and src/main.c) reads as follows:

sigmat = t * sigma;
out = 1.0 + (sigmat * exp( sigmat*sigmat / 2.0 ));
out *= SQRT_HALF_PI * ( erf( sigmat / SQRT2 ) + 1.0 );

The closed form for the Rayleigh MGF is M(t) = 1 + σt·√(π/2)·e^((σt)²/2)·(1 + erf(σt/√2)), so the trailing factor ends up being applied to the leading 1 as well. The quickest way to see the problem is that mgf(0, σ) returns √(π/2) ≈ 1.2533 instead of 1, and every moment-generating function must equal 1 at t = 0. The error also flips signs in places: mgf(-1, 4) currently returns -0.947, whereas the correct value is +0.053.
The JSDoc and README examples (mgf(1.0, 3.0) → ~678.508 and similar) match the buggy formula, so the incorrect values are baked into the documentation as well. I checked the neighboring mgf implementations (geometric, negative-binomial, Poisson, gamma, normal, and others), and this problem looks isolated to Rayleigh.

Proposed Approach

The fix is a small regrouping of the existing expression so that the √(π/2)·(1 + erf) factor multiplies only the σt term, applied in all three places that carry the formula:

sigmat = t * sigma;
out = 1.0 + ( sigmat * SQRT_HALF_PI * exp( sigmat*sigmat / 2.0 ) * ( erf( sigmat / SQRT2 ) + 1.0 ) );

Concretely, I propose updating lib/main.js, lib/factory.js, and src/main.c, along with the corresponding doc examples in README.md, docs/repl.txt, docs/types/index.d.ts, lib/index.js, and lib/native.js. The corrected example outputs, verified against stdlib's own erf implementation, are mgf(1.0, 3.0) → ~677.005, mgf(1.0, 2.0) → ~37.2, mgf(-1.0, 4.0) → ~0.053, mgf.factory(0.5)(1.0) → ~1.982, and mgf.factory(0.5)(0.5) → ~1.387. I have these changes ready locally and fully verified .

I’m happy to prepare a PR for this if the team is aligned , however please let me know if there’s another direction you'd prefer to take...! :)

Related Issues

Related to my earlier discussion #15298

Questions

I have no blocking questions. I would, however, appreciate guidance on whether the pull request should also add numeric fixtures to test.mgf.js and test.factory.js, since those tests currently only assert non-NaN output, which is how this slipped through unnoticed.

Demo

N/A

Reproduction

  • var mgf = require( '@stdlib/stats/base/dists/rayleigh/mgf' );
  • mgf( 0.0, 1.0 ); // returns ~1.253 instead of 1
  • mgf( 1.0, 3.0 ); // returns ~678.508 instead of ~677.005
  • mgf( -1.0, 4.0 ); // returns ~-0.947 instead of ~0.053

Expected Results

1
677.0046886610472
0.05339046834575567

Actual Results

1.2533141373155003
678.5079332431045
-0.9465301436239729

Version

0.4.1 (develop)

Environments

Node.js

Browser Version

N/A

Node.js / npm Version

Node v26.5.0 (the numbers were verified against stdlib's own erf, so the discrepancy lies in the formula rather than the environment).

Platform

macOS (darwin). This is a formula-level bug and is platform-independent.

Checklist

  • Read and understood the Code of Conduct.
  • Searched for existing issues and pull requests.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions