簡體   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