这是一个示例函数:
function step(x, min, max) {
return x >= min && x <= max ? x : 0;
}
console.log(step(-3 - Number.EPSILON, -3, 5)); // Expected 0, actual -3
console.log(step(5 + Number.EPSILON, -3, 5)); // Expected 0, actual 5
Run Code Online (Sandbox Code Playgroud)
我需要检查,对于 [min, max] 间隔之外的值,它是否返回零。当然,我可以减去/添加一个更大的数字,例如 1。但我很确定,应该存在一个返回上一个/下一个浮点数的函数。您能否建议一下该功能或如何实现它?
并非所有相邻的可表示数字彼此之间的数学距离都相同。浮点阿尔卡纳不是我的强项,但如果你想找到下一个可表示的数字,我认为你需要不断增加你添加/减去的内容,Number.EPSILON只要你不断得到相同的数字。
非常天真的、简单化的方法看起来像这样(但请继续阅读):
// DON'T USE THIS
function next(x) {
const ep = x < 0 ? -Number.EPSILON : Number.EPSILON;
let adder = ep;
let result;
do {
result = x + adder;
adder += ep;
} while (result === x);
return result;
}
console.log(`Next for -3: ${next(-3)}`);
console.log(`Next for 5: ${next(5)}`);Run Code Online (Sandbox Code Playgroud)
(这是根据给定数字的符号假设方向,这可能不是您真正想要的,但很容易切换。)
但是,这(至少)需要几个小时next(Number.MAX_SAFE_INTEGER)才能处理。
当我最初在上面发布我的警告时,我说更好的方法将考虑x“ ......或者做一些旋转(这肯定会让我们进入浮点奥秘领域)......”的大小,并且你指出了Java的Math.nextAfter操作,所以我必须找出他们做了什么。事实上,这有点麻烦,而且非常简单。下面是 OpenJDK 版本的重新实现(该链接中的行号将会失效):
// A JavaScript implementation of OpenJDK's `Double.nextAfter` method.
function nextAfter(start, direction) {
// These arrays share their underlying memory, letting us use them to do what
// Java's `Double.doubleToRawLongBits` and `Double.longBitsToDouble` do.
const f64 = new Float64Array(1);
const b64 = new BigInt64Array(f64.buffer);
// Comments from https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/lang/Math.java:
/*
* The cases:
*
* nextAfter(+infinity, 0) == MAX_VALUE
* nextAfter(+infinity, +infinity) == +infinity
* nextAfter(-infinity, 0) == -MAX_VALUE
* nextAfter(-infinity, -infinity) == -infinity
*
* are naturally handled without any additional testing
*/
/*
* IEEE 754 floating-point numbers are lexicographically
* ordered if treated as signed-magnitude integers.
* Since Java's integers are two's complement,
* incrementing the two's complement representation of a
* logically negative floating-point value *decrements*
* the signed-magnitude representation. Therefore, when
* the integer representation of a floating-point value
* is negative, the adjustment to the representation is in
* the opposite direction from what would initially be expected.
*/
// Branch to descending case first as it is more costly than ascending
// case due to start != 0.0d conditional.
if (start > direction) {
// descending
if (start !== 0) {
f64[0] = start;
const transducer = b64[0];
b64[0] = transducer + (transducer > 0n ? -1n : 1n);
return f64[0];
} else {
// start == 0.0d && direction < 0.0d
return -Number.MIN_VALUE;
}
} else if (start < direction) {
// ascending
// Add +0.0 to get rid of a -0.0 (+0.0 + -0.0 => +0.0)
// then bitwise convert start to integer.
f64[0] = start + 0;
const transducer = b64[0];
b64[0] = transducer + (transducer >= 0n ? 1n : -1n);
return f64[0];
} else if (start == direction) {
return direction;
} else {
// isNaN(start) || isNaN(direction)
return start + direction;
}
}
function test(start, direction) {
const result = nextAfter(start, direction);
console.log(`${start} ${direction > 0 ? "up" : "down"} is ${result}`);
}
test(-3, -Infinity);
test(5, Infinity);
test(Number.MAX_SAFE_INTEGER, Infinity);
test(Number.MAX_SAFE_INTEGER + 2, Infinity);Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
639 次 |
| 最近记录: |