是否存在一个浮点数,错误地计算为略低于0.5或0.0?

问题描述 投票:0回答:1

我正在用它来获得一个正确的四舍五入的整数除法。

Math.round((float)dividend/(float)divisor)

除以0已经在其他地方处理过了 除此之外,这可能会失败吗?我可以想象除法的结果是一个浮点数,这个浮点数的值是 something.5但实际上评价为 something.4999997 左右。这样的浮点数存在吗?

为了亲自检查,我试着打印出所有接近0.5的浮点数,像这样。

for(int i=Integer.MIN_VALUE+1; i!=Integer.MIN_VALUE; i++){
   float f=Float.intBitsToFloat(i);
   if ((f>(int)f+0.4999999 && f<(int)f+0.5000001 && f!=(int)f+0.5)
     ||(f<(int)f-0.4999999 && f>(int)f-0.5000001 && f!=(int)f-0.5)){
      System.out.println(Float.toString(f));
   }
}

(Integer.MIN_VALUE 手动检查了)。)

这只能打印。

-0.4999999
-0.49999994
-0.49999997
-0.50000006
0.4999999
0.49999994
0.49999997
0.50000006

因为... -0.50.5 肯定是浮动的,那就说明不存在这样的浮动。但也许有一种可能,就是我的范围太小,有问题的数字超出了范围。反正我想听听第二种意见,所以我在这里问一下,也许有人对IEEE754有先进的内部知识,有证据证明这种情况绝对不可能发生。

把范围扩大一位数有 这个结果,这些数字都没有回答这个问题。

相关问题。那... something.99999? A 类似试验这个结果. 所有这些浮点数都与它们精确整数的浮点数不同。

rounding precision ieee-754
1个回答
3
投票

简短的回答:是的,它可能会失败。

长话短说:你的问题取决于你考虑的是哪种整数和浮点格式--这不是一个纯粹的关于IEEE 754的问题。

例如,如果你正在寻找IEEE 754 "双精度 "二进制64类型(假设你的语言将其称为 "双精度")。double),并且只考虑一个固定宽度的32位整数(有符号或无符号),那么每一个这样的整数都完全可以表示为二进制64浮点数,所以在这种情况下,转换为 double 并没有改变价值,你确实可以依靠 (double)x / (double)y 根据当前的四舍五入模式被正确地四舍五入(假设你使用的任何语言都能保证除法根据当前的四舍五入模式被正确地四舍五入,例如因为它保证遵循IEEE 754标准)。

另一方面,如果 float 是IEEE 754 binary32 "单精度 "浮点类型,那么就有32位有符号整数的例子。xy 以致于 x 正好除以 y 所以商是一个小的,完全可以表示的整数),但 (float)x / (float)y 给出不同的值。其中一个例子是 x = 296852655y = 59370531. 那么 x / y 正好 5但最接近二进制32浮点数的是 x296852640.0的最接近的二进制32浮点数。y59370532.0和最接近于商的二进制32浮动数 296852640.0 / 59370532.0 正好 4.999999523162841796875,还差一个ulp 5.0.

类似的例子还有binary64 "双精度 "IEEE 754浮点和64位整数。例如,对于 x = 2135497568948934666y = 305071081278419238,两者 xy 适应一个有符号的64位整数类型。x / y 正好 7(double)x / (double)y6.99999999999999911182158029987476766109466552734375,同样离精确的结果还差1ulp。

这里还有几个更接近你在题目中提出的问题的例子:假设又是IEEE 754单精度算术,取 x = 592534758y = 395023172,它们都可以表示为有符号的32位整数。那么 x / y 正好 1.5(float)x / float(y)1.50000011920928955078125. 对于一个四舍五入的例子,如果...。x = 1418199327y = 945466218那么 x / y1.5(float)x / (float)y1.49999988079071044921875.

然而,值得一提的是,在以下情况下,并没有这样的例子。0.5:如果 xy 是32位有符号的整数,这样 x / y 正好 0.5那么,比意味着 y 正好是两倍 x 意味着 (float)y 将是两倍 (float)x 因为如果 (float)x 是最接近于 x 然后 2.0 * (float)x 必须是最接近于 2.0 * x). 所以在这种情况下。(float)x / (float)y 保证是 0.5我也是


2
投票

你不太清楚你在问什么:你说的 "失败 "是什么意思? 我想你想知道的是,在你的第一行中,是否有可能出现红利和除数的整数值,而结果却因为四舍五入的问题而不是你所期望的那样。

我想这是有可能的。 在下面的代码中,999,999,9992,000,000,000略小于0.5,所以我们期望的结果是0.0。 然而在Java中,结果是1.0。 如果你用Math.round(dividenddivisor)做整数除法,就会得到正确的答案。

int dividend = 999999999;
int divisor = 2000000000;
float result = Math.round((float)dividend/(float)divisor);
System.out.println(result);  // 1.0

你是这个意思吗? 这里的问题不是因为有一个浮点数不能正确进位,而是在将整数投向浮点数的过程中,你失去了准确性。"浮点数(dividend) "实际上是1.0E9。

© www.soinside.com 2019 - 2024. All rights reserved.