Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@ limitations under the License.

The [quantile function][quantile-function] for a [discrete uniform][discrete-uniform-distribution] random variable is

<!-- <equation class="equation" label="eq:discrete_uniform_quantile_function" align="center" raw="Q(p) = a + \lfloor p \cdot ( b - a + 1 ) \rfloor" alt="Quantile function for a discrete uniform distribution."> -->
<!-- <equation class="equation" label="eq:discrete_uniform_quantile_function" align="center" raw="Q(p) = a - 1 + \lceil p \cdot ( b - a + 1 ) \rceil" alt="Quantile function for a discrete uniform distribution."> -->

```math
Q(p) = a + \lfloor p \cdot ( b - a + 1 ) \rfloor
Q(p) = a - 1 + \lceil p \cdot ( b - a + 1 ) \rceil
```

<!-- <div class="equation" align="center" data-raw-text="Q(p) = a + \lfloor p \cdot ( b - a + 1 ) \rfloor" data-equation="eq:discrete_uniform_quantile_function">
<!-- <div class="equation" align="center" data-raw-text="Q(p) = a - 1 + \lceil p \cdot ( b - a + 1 ) \rceil" data-equation="eq:discrete_uniform_quantile_function">
<img src="https://cdn.jsdelivr.net/gh/stdlib-js/stdlib@591cf9d5c3a0cd3c1ceec961e5c49d73a68374cb/lib/node_modules/@stdlib/stats/base/dists/discrete-uniform/quantile/docs/img/equation_discrete_uniform_quantile_function.svg" alt="Quantile function for a discrete uniform distribution.">
<br>
</div> -->

<!-- </equation> -->

for `0 <= p <= 1`, where `a` is the minimum support and `b` is the maximum support. The parameters must satisfy `a <= b`.
for `0 < p <= 1`, where `a` is the minimum support and `b` is the maximum support, and `Q(0) = a`. This is the smallest `x` in the support for which the cumulative distribution function is at least `p`. The parameters must satisfy `a <= b`.

</section>

Expand Down Expand Up @@ -109,7 +109,7 @@ Returns a function for evaluating the quantile function of a [discrete uniform][
```javascript
var myquantile = quantile.factory( 0, 4 );
var y = myquantile( 0.8 );
// returns 4
// returns 3

y = myquantile( 0.3 );
// returns 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
--------
> var myQuantile = {{alias}}.factory( 0, 4 );
> var y = myQuantile( 0.8 )
4
3

See Also
--------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ interface Quantile {
*
* var myQuantile = quantile.factory( 0, 4 );
* y = myQuantile( 0.8 );
* // returns 4
* // returns 3
*/
declare var quantile: Quantile;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
var constantFunction = require( '@stdlib/utils/constant-function' );
var isInteger = require( '@stdlib/math/base/assert/is-integer' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var floor = require( '@stdlib/math/base/special/floor' );
var ceil = require( '@stdlib/math/base/special/ceil' );


// MAIN //
Expand Down Expand Up @@ -69,10 +69,18 @@ function factory( a, b ) {
* // returns <number>
*/
function quantile( p ) {
var k;
if ( isnan( p ) || p < 0.0 || p > 1.0 ) {
return NaN;
}
return a + floor( p * n );
if ( p === 0.0 ) {
return a;
}
k = ceil( p * n );
if ( ( k-1 ) / n >= p ) {
k -= 1;
}
return a + k - 1;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*
* var myQuantile = quantile.factory( 0, 4 );
* y = myQuantile( 0.8 );
* // returns 4
* // returns 3
*/

// MODULES //
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,24 @@

var isInteger = require( '@stdlib/math/base/assert/is-integer' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var floor = require( '@stdlib/math/base/special/floor' );
var ceil = require( '@stdlib/math/base/special/ceil' );


// MAIN //

/**
* Evaluates the quantile function for a discrete uniform distribution with minimum support `a` and maximum support `b` at a probability `p`.
*
* ## Method
*
* The quantile is the smallest \\(x\\) in the support with \\(F(x) \geq p\\). As \\(F(x) = (x-a+1)/n\\), where \\(n = b-a+1\\), this is
*
* ```tex
* Q(p) = a - 1 + \lceil p n \rceil
* ```
*
* for \\(p > 0\\), and \\(Q(0) = a\\). Because \\(pn\\) can round up past an integer (e.g., \\(0.3 \cdot 10 = 3.0000000000000004\\)), the function steps \\(k = \lceil pn \rceil\\) back by one when \\((k-1)/n \geq p\\), which is the same comparison the CDF makes.
*
* @param {Probability} p - input value
* @param {integer} a - minimum support
* @param {integer} b - maximum support
Expand Down Expand Up @@ -73,6 +83,7 @@ var floor = require( '@stdlib/math/base/special/floor' );
*/
function quantile( p, a, b ) {
var n;
var k;
if (
isnan( p ) ||
isnan( a ) ||
Expand All @@ -85,8 +96,15 @@ function quantile( p, a, b ) {
) {
return NaN;
}
if ( p === 0.0 ) {
return a;
}
n = b - a + 1;
return a + floor( p * n );
k = ceil( p * n );
if ( ( k-1 ) / n >= p ) {
k -= 1;
}
return a + k - 1;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"dependencies": [
"@stdlib/math/base/napi/ternary",
"@stdlib/math/base/assert/is-nan",
"@stdlib/math/base/special/floor"
"@stdlib/math/base/special/ceil"
]
},
{
Expand All @@ -57,7 +57,7 @@
"dependencies": [
"@stdlib/math/base/special/round",
"@stdlib/math/base/assert/is-nan",
"@stdlib/math/base/special/floor"
"@stdlib/math/base/special/ceil"
]
},
{
Expand All @@ -74,7 +74,7 @@
"dependencies": [
"@stdlib/math/base/special/round",
"@stdlib/math/base/assert/is-nan",
"@stdlib/math/base/special/floor"
"@stdlib/math/base/special/ceil"
]
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,22 @@

#include "stdlib/stats/base/dists/discrete-uniform/quantile.h"
#include "stdlib/math/base/assert/is_nan.h"
#include "stdlib/math/base/special/floor.h"
#include "stdlib/math/base/special/ceil.h"
#include <stdint.h>

/**
* Evaluates the quantile function for a discrete uniform distribution with minimum support `a` and maximum support `b` at a probability `p`.
*
* ## Method
*
* The quantile is the smallest `x` in the support with `F(x) \geq p`. As `F(x) = (x-a+1)/n`, where `n = b-a+1`, this is
*
* ```tex
* Q(p) = a - 1 + \lceil p n \rceil
* ```
*
* for `p > 0`, and `Q(0) = a`. Because `pn` can round up past an integer (e.g., `0.3 \cdot 10 = 3.0000000000000004`), the function steps `k = \lceil pn \rceil` back by one when `(k-1)/n \geq p`, which is the same comparison the CDF makes.
*
* @param p input probability
* @param a minimum support
* @param b maximum support
Expand All @@ -34,6 +44,8 @@
* // returns 1.0
*/
double stdlib_base_dists_discrete_uniform_quantile( const double p, const int32_t a, const int32_t b ) {
double n;
double k;
if (
stdlib_base_is_nan( p ) ||
a > b ||
Expand All @@ -42,5 +54,13 @@ double stdlib_base_dists_discrete_uniform_quantile( const double p, const int32_
) {
return 0.0/0.0; // NaN
}
return a + stdlib_base_floor( p * ( b - a + 1.0 ) );
if ( p == 0.0 ) {
return a;
}
n = b - a + 1.0;
k = stdlib_base_ceil( p * n );
if ( ( k-1.0 ) / n >= p ) {
k -= 1.0;
}
return a + k - 1.0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,39 @@ tape( 'if provided `a > b`, the created function always returns `NaN`', function
t.end();
});

tape( 'if provided `p = 0`, the created function returns `a`, and if provided `p = 1`, the created function returns `b`', function test( t ) {
var quantile;

quantile = factory( 2, 5 );
t.strictEqual( quantile( 0.0 ), 2, 'returns expected value' );
t.strictEqual( quantile( 1.0 ), 5, 'returns expected value' );

quantile = factory( -3, -3 );
t.strictEqual( quantile( 0.0 ), -3, 'returns expected value' );
t.strictEqual( quantile( 1.0 ), -3, 'returns expected value' );

t.end();
});

tape( 'the created function returns the smallest `x` such that `F(x) >= p` when `p*(b-a+1)` is an integer', function test( t ) {
var quantile;
var a;
var n;
var k;
var y;

for ( a = -3; a <= 3; a += 3 ) {
for ( n = 1; n <= 10; n++ ) {
quantile = factory( a, a+n-1 );
for ( k = 1; k <= n; k++ ) {
y = quantile( k/n );
t.strictEqual( y, a+k-1, 'a: '+a+', b: '+(a+n-1)+', p: '+(k/n)+', y: '+y+', expected: '+(a+k-1) );
}
}
}
t.end();
});

tape( 'the created function evaluates the quantile for `p` given a small range `b - a`', function test( t ) {
var expected;
var quantile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,31 @@ tape( 'if provided `a > b`, the function returns `NaN`', opts, function test( t
t.end();
});

tape( 'if provided `p = 0`, the function returns `a`, and if provided `p = 1`, the function returns `b`', opts, function test( t ) {
t.strictEqual( quantile( 0.0, 2, 5 ), 2, 'returns expected value' );
t.strictEqual( quantile( 1.0, 2, 5 ), 5, 'returns expected value' );
t.strictEqual( quantile( 0.0, -3, -3 ), -3, 'returns expected value' );
t.strictEqual( quantile( 1.0, -3, -3 ), -3, 'returns expected value' );
t.end();
});

tape( 'the function returns the smallest `x` such that `F(x) >= p` when `p*(b-a+1)` is an integer', opts, function test( t ) {
var a;
var n;
var k;
var y;

for ( a = -3; a <= 3; a += 3 ) {
for ( n = 1; n <= 10; n++ ) {
for ( k = 1; k <= n; k++ ) {
y = quantile( k/n, a, a+n-1 );
t.strictEqual( y, a+k-1, 'a: '+a+', b: '+(a+n-1)+', p: '+(k/n)+', y: '+y+', expected: '+(a+k-1) );
}
}
}
t.end();
});

tape( 'the function evaluates the quantile for `p` given a small range `b - a`', opts, function test( t ) {
var expected;
var delta;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,31 @@ tape( 'if provided a non-integer value for `a` or `b`, the function returns `NaN
t.end();
});

tape( 'if provided `p = 0`, the function returns `a`, and if provided `p = 1`, the function returns `b`', function test( t ) {
t.strictEqual( quantile( 0.0, 2, 5 ), 2, 'returns expected value' );
t.strictEqual( quantile( 1.0, 2, 5 ), 5, 'returns expected value' );
t.strictEqual( quantile( 0.0, -3, -3 ), -3, 'returns expected value' );
t.strictEqual( quantile( 1.0, -3, -3 ), -3, 'returns expected value' );
t.end();
});

tape( 'the function returns the smallest `x` such that `F(x) >= p` when `p*(b-a+1)` is an integer', function test( t ) {
var a;
var n;
var k;
var y;

for ( a = -3; a <= 3; a += 3 ) {
for ( n = 1; n <= 10; n++ ) {
for ( k = 1; k <= n; k++ ) {
y = quantile( k/n, a, a+n-1 );
t.strictEqual( y, a+k-1, 'a: '+a+', b: '+(a+n-1)+', p: '+(k/n)+', y: '+y+', expected: '+(a+k-1) );
}
}
}
t.end();
});

tape( 'the function evaluates the quantile for `p` given a small range `b - a`', function test( t ) {
var expected;
var delta;
Expand Down
Loading