@lvlte/ulp 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +50 -0
- package/dist/index.d.ts +22 -3
- package/dist/index.js +22 -5
- package/package.json +16 -22
- package/readme.md +32 -14
- package/dist/cjs/index.d.ts +0 -25
- package/dist/cjs/index.js +0 -31
- package/dist/cjs/package.json +0 -3
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ulp = exports.FLOAT64_MIN = void 0;
|
|
4
|
+
exports.eps = eps;
|
|
5
|
+
exports.exponent = exponent;
|
|
6
|
+
exports.nextFloat = nextFloat;
|
|
7
|
+
exports.prevFloat = prevFloat;
|
|
8
|
+
exports.FLOAT64_MIN = Math.pow(2, -1022);
|
|
9
|
+
function eps(x = 1) {
|
|
10
|
+
if (Number.isFinite(x)) {
|
|
11
|
+
x = Math.abs(x);
|
|
12
|
+
if (x <= exports.FLOAT64_MIN) {
|
|
13
|
+
return Number.MIN_VALUE;
|
|
14
|
+
}
|
|
15
|
+
return Math.pow(2, (_exponent(x) - 52));
|
|
16
|
+
}
|
|
17
|
+
return NaN;
|
|
18
|
+
}
|
|
19
|
+
exports.ulp = eps;
|
|
20
|
+
function exponent(x) {
|
|
21
|
+
if (Number.isFinite(x) && x !== 0) {
|
|
22
|
+
return _exponent(Math.abs(x));
|
|
23
|
+
}
|
|
24
|
+
return NaN;
|
|
25
|
+
}
|
|
26
|
+
function _exponent(x) {
|
|
27
|
+
const s = x.toString(2);
|
|
28
|
+
return x < 1 ? -(s.split('1', 1)[0].length - 1) : s.split('.', 1)[0].length - 1;
|
|
29
|
+
}
|
|
30
|
+
function nextFloat(x) {
|
|
31
|
+
switch (x) {
|
|
32
|
+
case -Infinity:
|
|
33
|
+
return -Number.MAX_VALUE;
|
|
34
|
+
case Infinity:
|
|
35
|
+
case Number.MAX_VALUE:
|
|
36
|
+
return Infinity;
|
|
37
|
+
case -Number.MIN_VALUE:
|
|
38
|
+
return -0;
|
|
39
|
+
default:
|
|
40
|
+
if (!Number.isFinite(x)) {
|
|
41
|
+
return NaN;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const e = eps(x);
|
|
45
|
+
const y = x + e / 2;
|
|
46
|
+
return y > x ? y : x + e;
|
|
47
|
+
}
|
|
48
|
+
function prevFloat(x) {
|
|
49
|
+
return typeof x === 'number' ? -nextFloat(-x) : NaN;
|
|
50
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,7 +5,8 @@ export declare const FLOAT64_MIN: number;
|
|
|
5
5
|
/**
|
|
6
6
|
* Return the unit in the last place or unit of least precision (ulp) of x, that
|
|
7
7
|
* is, the distance between two consecutive representable floating-point numbers
|
|
8
|
-
* at x.
|
|
8
|
+
* at x. If x is a power of 2, the distance on either side of x is different, in
|
|
9
|
+
* which case the larger distance is returned.
|
|
9
10
|
*
|
|
10
11
|
* @param x The input number (default: 1)
|
|
11
12
|
* @returns The ulp of x, or `NaN` if `x` is not a finite number.
|
|
@@ -19,7 +20,25 @@ export declare const ulp: typeof eps;
|
|
|
19
20
|
* Exponent of a normalized floating-point number x.
|
|
20
21
|
*
|
|
21
22
|
* @param x The input number
|
|
22
|
-
* @returns The largest integer `y` such that `2^y ≤ |x
|
|
23
|
-
*
|
|
23
|
+
* @returns The largest integer `y` such that `2^y ≤ |x|`. If `x` is not a
|
|
24
|
+
* finite number or equals ±0, returns `NaN`.
|
|
24
25
|
*/
|
|
25
26
|
export declare function exponent(x: number): number;
|
|
27
|
+
/**
|
|
28
|
+
* Return the smallest representable floating-point number that comes after `x`
|
|
29
|
+
* on the float64 number line (towards +∞).
|
|
30
|
+
*
|
|
31
|
+
* @param x The input number
|
|
32
|
+
* @returns The smallest floating-point number `y` such that `y > x`. If `x` is
|
|
33
|
+
* `±Infinity` or `NaN`, returns `x`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function nextFloat(x: number): number;
|
|
36
|
+
/**
|
|
37
|
+
* Return the largest representable floating-point number that comes before `x`
|
|
38
|
+
* on the float64 number line (towards -∞).
|
|
39
|
+
*
|
|
40
|
+
* @param x The input number
|
|
41
|
+
* @returns The largest floating-point number `y` such that `y < x`. If `x` is
|
|
42
|
+
* `±Infinity` or `NaN`, returns `x`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function prevFloat(x: number): number;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { modf } from '@lvlte/modf';
|
|
2
1
|
export const FLOAT64_MIN = Math.pow(2, -1022);
|
|
3
2
|
export function eps(x = 1) {
|
|
4
3
|
if (Number.isFinite(x)) {
|
|
@@ -18,9 +17,27 @@ export function exponent(x) {
|
|
|
18
17
|
return NaN;
|
|
19
18
|
}
|
|
20
19
|
function _exponent(x) {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
const s = x.toString(2);
|
|
21
|
+
return x < 1 ? -(s.split('1', 1)[0].length - 1) : s.split('.', 1)[0].length - 1;
|
|
22
|
+
}
|
|
23
|
+
export function nextFloat(x) {
|
|
24
|
+
switch (x) {
|
|
25
|
+
case -Infinity:
|
|
26
|
+
return -Number.MAX_VALUE;
|
|
27
|
+
case Infinity:
|
|
28
|
+
case Number.MAX_VALUE:
|
|
29
|
+
return Infinity;
|
|
30
|
+
case -Number.MIN_VALUE:
|
|
31
|
+
return -0;
|
|
32
|
+
default:
|
|
33
|
+
if (!Number.isFinite(x)) {
|
|
34
|
+
return NaN;
|
|
35
|
+
}
|
|
24
36
|
}
|
|
25
|
-
|
|
37
|
+
const e = eps(x);
|
|
38
|
+
const y = x + e / 2;
|
|
39
|
+
return y > x ? y : x + e;
|
|
40
|
+
}
|
|
41
|
+
export function prevFloat(x) {
|
|
42
|
+
return typeof x === 'number' ? -nextFloat(-x) : NaN;
|
|
26
43
|
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvlte/ulp",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Compute the
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Compute the ULP of a given number / Get the closest representable number that comes before/after it on the float64 number line",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Eric Lavault <lvlte.code@gmail.com>",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/lvlte/ulp"
|
|
9
|
+
"url": "git+https://github.com/lvlte/ulp.git"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
12
|
-
"main": "./dist/
|
|
12
|
+
"main": "./dist/index.cjs",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
13
14
|
"exports": {
|
|
14
15
|
".": {
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
"require": {
|
|
20
|
-
"types": "./dist/cjs/index.d.ts",
|
|
21
|
-
"default": "./dist/cjs/index.js"
|
|
22
|
-
}
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"import": "./dist/index.js",
|
|
18
|
+
"require": "./dist/index.cjs"
|
|
23
19
|
}
|
|
24
20
|
},
|
|
25
21
|
"engines": {
|
|
@@ -32,35 +28,33 @@
|
|
|
32
28
|
"test": "jest",
|
|
33
29
|
"prebuild": "rimraf dist && make-dir dist",
|
|
34
30
|
"build": "tsc && tsc -p tsconfig-cjs.json",
|
|
35
|
-
"postbuild": "
|
|
36
|
-
"prepublishOnly": "npm test && npm run build && tsc --emitDeclarationOnly true --removeComments false
|
|
31
|
+
"postbuild": "mv dist/cjs/index.js dist/index.cjs && rimraf dist/cjs",
|
|
32
|
+
"prepublishOnly": "npm test && npm run build && tsc --emitDeclarationOnly true --removeComments false"
|
|
37
33
|
},
|
|
38
34
|
"keywords": [
|
|
39
35
|
"number",
|
|
40
36
|
"epsilon",
|
|
41
|
-
"function",
|
|
42
37
|
"precision",
|
|
43
38
|
"eps",
|
|
44
39
|
"ulp",
|
|
40
|
+
"nextFloat",
|
|
41
|
+
"prevFloat",
|
|
42
|
+
"next",
|
|
43
|
+
"previous",
|
|
45
44
|
"float",
|
|
46
45
|
"float64",
|
|
47
46
|
"IEEE-754",
|
|
48
47
|
"rounding",
|
|
49
48
|
"tolerance",
|
|
50
|
-
"compare",
|
|
51
|
-
"equal",
|
|
52
49
|
"ULP"
|
|
53
50
|
],
|
|
54
51
|
"devDependencies": {
|
|
55
|
-
"@lvlte/tsconfig": "^1.0
|
|
52
|
+
"@lvlte/tsconfig": "^1.1.0",
|
|
56
53
|
"@types/jest": "^29.5.12",
|
|
57
54
|
"jest": "^29.7.0",
|
|
58
55
|
"make-dir-cli": "^4.0.0",
|
|
59
56
|
"rimraf": "^6.0.1",
|
|
60
57
|
"ts-jest": "29.2.5",
|
|
61
|
-
"typescript": "^5.9.
|
|
62
|
-
},
|
|
63
|
-
"dependencies": {
|
|
64
|
-
"@lvlte/modf": "^1.1.0"
|
|
58
|
+
"typescript": "^5.9.3"
|
|
65
59
|
}
|
|
66
60
|
}
|
package/readme.md
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
# ulp (epsilon function)
|
|
2
2
|
|
|
3
3
|
> Compute the [unit of least precision](https://en.wikipedia.org/wiki/Unit_in_the_last_place)
|
|
4
|
-
of a given IEEE-754 64-bit number
|
|
4
|
+
of a given IEEE-754 64-bit number : `eps(x)` (alias `ulp(x)`).<br>
|
|
5
|
+
> Get the closest representable number that comes before/after it on the float64
|
|
6
|
+
number line : `nextFloat(x)`, `prevFloat(x)`.
|
|
7
|
+
|
|
5
8
|
|
|
6
9
|
## Install
|
|
7
10
|
|
|
@@ -13,28 +16,43 @@ npm install @lvlte/ulp
|
|
|
13
16
|
|
|
14
17
|
```js
|
|
15
18
|
// ESM
|
|
16
|
-
import { eps } from '@lvlte/ulp';
|
|
19
|
+
import { eps, nextFloat, prevFloat } from '@lvlte/ulp';
|
|
17
20
|
```
|
|
18
21
|
```js
|
|
19
22
|
// CJS
|
|
20
|
-
const { eps } = require('@lvlte/ulp');
|
|
23
|
+
const { eps, nextFloat, prevFloat } = require('@lvlte/ulp');
|
|
24
|
+
```
|
|
25
|
+
```js
|
|
26
|
+
console.log( eps() ); // 2.220446049250313e-16
|
|
27
|
+
console.log( eps() === eps(1) ); // true
|
|
28
|
+
console.log( eps() === Number.EPSILON ); // true
|
|
29
|
+
|
|
30
|
+
console.log( eps(Number.MAX_SAFE_INTEGER) ); // 1
|
|
31
|
+
console.log( eps(Number.MAX_SAFE_INTEGER + 1) ); // 2
|
|
32
|
+
|
|
33
|
+
console.log( eps(0) ); // 5e-324
|
|
34
|
+
console.log( eps(0) === Number.MIN_VALUE ); // true
|
|
35
|
+
|
|
36
|
+
console.log( eps(Infinity) ); // NaN
|
|
21
37
|
```
|
|
22
38
|
```js
|
|
23
|
-
console.log(
|
|
24
|
-
console.log(
|
|
25
|
-
console.log(eps() === Number.EPSILON); // true
|
|
39
|
+
console.log( nextFloat(0) ); // 5e-324
|
|
40
|
+
console.log( nextFloat(0) === Number.MIN_VALUE ); // true
|
|
26
41
|
|
|
27
|
-
console.log(
|
|
28
|
-
console.log(
|
|
42
|
+
console.log( nextFloat(1) ); // 1.0000000000000002
|
|
43
|
+
console.log( nextFloat(1) === 1 + eps(1) ); // true
|
|
29
44
|
|
|
30
|
-
console.log(
|
|
31
|
-
console.log(
|
|
45
|
+
console.log( nextFloat(Number.MAX_SAFE_INTEGER) ); // 9007199254740992
|
|
46
|
+
console.log( nextFloat(9007199254740992) ); // 9007199254740994
|
|
47
|
+
console.log( nextFloat(Number.MAX_VALUE) ); // Infinity
|
|
32
48
|
|
|
33
|
-
console.log(
|
|
49
|
+
console.log( prevFloat(0) ); // -5e-324
|
|
50
|
+
console.log( prevFloat(1) ); // 0.9999999999999999
|
|
51
|
+
console.log( prevFloat(9007199254740992) ); // 9007199254740991
|
|
52
|
+
console.log( prevFloat(Infinity) ); // 1.7976931348623157e+308
|
|
34
53
|
```
|
|
35
54
|
|
|
36
55
|
## Use case
|
|
37
56
|
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
- Get the next/previous float on the float64 number line.
|
|
57
|
+
- Use the proper tolerance to check whether two floating-point numbers should be considered equal.
|
|
58
|
+
- Use the proper tolerance to approximate a floating-point number as a rational number.
|
package/dist/cjs/index.d.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The smallest positive normal number representable by IEEE-754 float64.
|
|
3
|
-
*/
|
|
4
|
-
export declare const FLOAT64_MIN: number;
|
|
5
|
-
/**
|
|
6
|
-
* Return the unit in the last place or unit of least precision (ulp) of x, that
|
|
7
|
-
* is, the distance between two consecutive representable floating-point numbers
|
|
8
|
-
* at x.
|
|
9
|
-
*
|
|
10
|
-
* @param x The input number (default: 1)
|
|
11
|
-
* @returns The ulp of x, or `NaN` if `x` is not a finite number.
|
|
12
|
-
*/
|
|
13
|
-
export declare function eps(x?: number): number;
|
|
14
|
-
/**
|
|
15
|
-
* @borrows eps as ulp
|
|
16
|
-
*/
|
|
17
|
-
export declare const ulp: typeof eps;
|
|
18
|
-
/**
|
|
19
|
-
* Exponent of a normalized floating-point number x.
|
|
20
|
-
*
|
|
21
|
-
* @param x The input number
|
|
22
|
-
* @returns The largest integer `y` such that `2^y ≤ |x|`, or `NaN` if x is not
|
|
23
|
-
* a finite number / if x is ±0.
|
|
24
|
-
*/
|
|
25
|
-
export declare function exponent(x: number): number;
|
package/dist/cjs/index.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ulp = exports.FLOAT64_MIN = void 0;
|
|
4
|
-
exports.eps = eps;
|
|
5
|
-
exports.exponent = exponent;
|
|
6
|
-
const modf_1 = require("@lvlte/modf");
|
|
7
|
-
exports.FLOAT64_MIN = Math.pow(2, -1022);
|
|
8
|
-
function eps(x = 1) {
|
|
9
|
-
if (Number.isFinite(x)) {
|
|
10
|
-
x = Math.abs(x);
|
|
11
|
-
if (x <= exports.FLOAT64_MIN) {
|
|
12
|
-
return Number.MIN_VALUE;
|
|
13
|
-
}
|
|
14
|
-
return Math.pow(2, (_exponent(x) - 52));
|
|
15
|
-
}
|
|
16
|
-
return NaN;
|
|
17
|
-
}
|
|
18
|
-
exports.ulp = eps;
|
|
19
|
-
function exponent(x) {
|
|
20
|
-
if (Number.isFinite(x) && x !== 0) {
|
|
21
|
-
return _exponent(Math.abs(x));
|
|
22
|
-
}
|
|
23
|
-
return NaN;
|
|
24
|
-
}
|
|
25
|
-
function _exponent(x) {
|
|
26
|
-
const [ipart, fpart] = (0, modf_1.modf)(x);
|
|
27
|
-
if (ipart > 0) {
|
|
28
|
-
return ipart.toString(2).split('.', 1)[0].length - 1;
|
|
29
|
-
}
|
|
30
|
-
return -(fpart.toString(2).split('1', 1)[0].length - 1);
|
|
31
|
-
}
|
package/dist/cjs/package.json
DELETED