Description
I encountered incorrect output from @stdlib/stats/base/dists/kumaraswamy/kurtosis. While cross-checking the distribution moments against their closed forms, I noticed the implementation computes the standardized fourth central moment μ₄/σ⁴ and returns it directly, without subtracting 3 for excess kurtosis — even though the JSDoc and README both promise excess kurtosis.
The current code in lib/main.js (and identically in src/main.c) reads as follows:
out = ( m4 - ( 4.0*m3*m1 ) + ( 6.0*m2*mu2 ) - ( 3.0*mu2*mu2 ) );
out /= sigma2*sigma2;
return out;
The raw-moment machinery is sound: mₖ = b·B(1+k/a, b) and the central-moment expansion above reproduce the returned value bit-identically. The sole defect is the missing final − 3.0. The quickest way to see the problem is that kurtosis(1, 1) returns +1.8, but Kumaraswamy(1,1) is exactly the standard uniform distribution, whose excess kurtosis is unambiguously −1.2. Both beta/kurtosis(1, 1) and uniform/kurtosis(0, 1) in this same repo correctly return −1.2, so Kumaraswamy is the outlier — every output is systematically off by exactly +3.
The JSDoc and README examples (kurtosis(0.5, 1.0) → ~2.143 and similar) match the non-excess values, so the incorrect magnitudes are baked into the documentation as well. I checked the neighboring skewness implementation and the mean/variance helpers, and they are all correct — this looks isolated to kurtosis.
Proposed Approach
The fix is appending the missing excess adjustment after the division, in both the JavaScript and C implementations :
out = ( m4 - ( 4.0*m3*m1 ) + ( 6.0*m2*mu2 ) - ( 3.0*mu2*mu2 ) );
out /= sigma2*sigma2;
out -= 3.0;
return out;
Concretely, I propose updating lib/main.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 numerical integration of the package's own pdf as well as the analytic raw moments, are kurtosis(0.5, 1.0) → ~-0.857, kurtosis(4.0, 12.0) → ~-0.296, kurtosis(12.0, 2.0) → ~1.817, and kurtosis(1.0, 1.0) → ~-1.2. I would also add numeric fixtures to test/test.js (which currently carries a TODO: Add fixtures and asserts only non-NaN output, which is how this slipped through), including the Uniform/Beta cross-check at (1, 1). I have these changes ready locally and fully verified, and I am happy to open a pull request with them.
Related Issues
None
Questions
I have no blocking questions.
Demo
N/A
Reproduction
- var kurtosis = require( '@stdlib/stats/base/dists/kumaraswamy/kurtosis' );
- kurtosis( 1.0, 1.0 ); // returns ~1.8 instead of -1.2
- kurtosis( 0.5, 1.0 ); // returns ~2.143 instead of ~-0.857
- kurtosis( 4.0, 12.0 ); // returns ~2.704 instead of ~-0.296
Expected Results
- 1.1999999999999977
- 0.8571428571428541
- 0.29616663526157305
Actual Results
1.8000000000000023
2.1428571428571459
2.7038333647384269
Version
0.4.1 (develop)
Environments
Node.js
Browser Version
N/A
Node.js / npm Version
Node v26.5.0
Platform
macOS (darwin). This is a formula-level bug and is platform-independent.
Checklist
Description
I encountered incorrect output from
@stdlib/stats/base/dists/kumaraswamy/kurtosis. While cross-checking the distribution moments against their closed forms, I noticed the implementation computes the standardized fourth central momentμ₄/σ⁴and returns it directly, without subtracting3for excess kurtosis — even though the JSDoc and README both promise excess kurtosis.The current code in
lib/main.js(and identically insrc/main.c) reads as follows:The raw-moment machinery is sound: mₖ = b·B(1+k/a, b) and the central-moment expansion above reproduce the returned value bit-identically. The sole defect is the missing final − 3.0. The quickest way to see the problem is that kurtosis(1, 1) returns +1.8, but Kumaraswamy(1,1) is exactly the standard uniform distribution, whose excess kurtosis is unambiguously −1.2. Both beta/kurtosis(1, 1) and uniform/kurtosis(0, 1) in this same repo correctly return −1.2, so Kumaraswamy is the outlier — every output is systematically off by exactly +3.
The JSDoc and README examples (kurtosis(0.5, 1.0) → ~2.143 and similar) match the non-excess values, so the incorrect magnitudes are baked into the documentation as well. I checked the neighboring skewness implementation and the mean/variance helpers, and they are all correct — this looks isolated to kurtosis.
Proposed Approach
The fix is appending the missing excess adjustment after the division, in both the JavaScript and C implementations :
Concretely, I propose updating lib/main.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 numerical integration of the package's own pdf as well as the analytic raw moments, are kurtosis(0.5, 1.0) → ~-0.857, kurtosis(4.0, 12.0) → ~-0.296, kurtosis(12.0, 2.0) → ~1.817, and kurtosis(1.0, 1.0) → ~-1.2. I would also add numeric fixtures to test/test.js (which currently carries a TODO: Add fixtures and asserts only non-NaN output, which is how this slipped through), including the Uniform/Beta cross-check at (1, 1). I have these changes ready locally and fully verified, and I am happy to open a pull request with them.
Related Issues
None
Questions
I have no blocking questions.
Demo
N/A
Reproduction
Expected Results
Actual Results
Version
0.4.1 (develop)
Environments
Node.js
Browser Version
N/A
Node.js / npm Version
Node v26.5.0
Platform
macOS (darwin). This is a formula-level bug and is platform-independent.
Checklist