繁体   English   中英

如何获得小于/大于给定数字的最接近的浮点数

[英]How to get closest floating point number that is less/greater than a given number

这是一个示例函数:

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

我需要检查,对于 [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)}`);

(这是根据给定数字的符号假设方向,这可能不是您真正想要的,但很容易切换。)

但是,处理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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM