对于任何浮点数 x,y,整数 n,其中 const y=n-x 和 0<=x,y,n<=MAX_VALUE,x+y==n 总是真的吗?

For any float number x,y,integer n, where const y=n-x, and 0<=x,y,n<=MAX_VALUE, is x+y==n always true?

提问人:displaydisplayname 提问时间:3/21/2023 最后编辑:displaydisplayname 更新时间:3/21/2023 访问量:80

问:

例如:

const n=5;
const x=1.23;
const y=n-x;
document.write(x+y==n);

有关代码为 n=5,x=1.23,y=5-1.23(四舍五入后的值)打印 true。我认为这只是一个“幸运”的情况,因为我认为在某些情况下,n-x 会四舍五入到某个值,这样 x+y 就不会再次等于 n。但是我尝试使用for循环来查找一些错误的情况:

for(let i=0;i<100000;i++){
  const n=Math.floor(Math.random()*10000);
  const x=Math.random()*5000;
  const y=n-x;
  if(x+y!=n){
    document.write(x+","+y+","+n);
    break;
  }
}

令人惊讶的是,连续多次打印任何异常。

所以我的问题是,对于任何浮点数 x,y,整数 n,其中 const y=n-x 和 o<=x,y,n<=MAX_VALUE,x+y==n 总是真的吗?如果是这样,原因是什么?有没有假的案例?

旁注:似乎 x>n 也是如此,例如:

for(let i=0;i<100000;i++){
      const n=Math.floor(Math.random()*10000);
      const x=10000+Math.random()*5000;
      const y=n-x;
      if(x+y!=n){
        document.write(x+","+y+","+n);
        break;
      }
}

但在 x 为负数的情况下则不然:

for(let i=0;i<100000;i++){
      const n=Math.floor(Math.random()*10000);
      const x=Math.random()*-5000;
      const y=n-x;
      if(x+y!=n){
        document.write(x+","+y+","+n);
        break;
      }
}

原因是什么?

JavaScript 浮点 精度

评论

0赞 Sam Mason 3/23/2023
2**±52 左右的值通常是 64 位IEEE754二进制浮点数发生有趣事情的地方,因为这是您开始耗尽精度的地方。以“十六进制格式”打印出值会有所帮助,这是我在 JS 中能找到的最好的,在 C 中它是在 C++ 或 Python 中使用 std::hexfloat 时的转换js-hexfloat%aprintffloat.hex()

答:

1赞 alias 3/21/2023 #1

不,不是。下面是一个反例:

const n=5847425060810559;
const x=87667.5;
const y=n-x;
document.write(x+y==n);
document.write("<br>lhs = " + (x+y) + "<br>rhs = " + n);

评论

1赞 Sam Mason 3/23/2023
n = 2**52 + 1; x = 0.5并且是反例,在这些例子中可能更容易看到正在发生的事情n = 2**53 + 2; x = 1