Skip to content

bug: kumaraswamy/kurtosis returns non-excess kurtosis (missing −3) #15461

Description

@AdeshDeshmukh

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

  • 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