
[英]Sonar is wrongly reporting Remove this expression which always evaluates to “true”
[英]Does a float exist that wrongly evaluates to slightly below .5 or .0?
我正在使用它来获得正确舍入的 integer 划分:
Math.round((float)dividend/(float)divisor)
除以 0 已在其他地方处理。 除此之外,这会失败吗?
我可以想象那个除法的结果是一个应该是something.5
的浮点数,但实际上计算为something.4999997
左右。 这样的浮标存在吗?
为了自己检查这一点,我尝试打印出所有接近 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.5
和0.5
肯定是浮点数,这意味着不存在这样的浮点数。 但也许我的范围太小并且有问题的数字超出了范围。 无论如何,我想要第二个意见,所以我在这里问,也许有人对 IEEE754 有先进的内部知识,并有证据证明为什么这绝对不会发生。
将范围扩大一个数字有这个结果,这些数字都没有回答这个问题。
相关问题: something.99999
怎么样? 一个类似的测试有这个结果。 所有这些浮点数都与浮点数不同,因为它们的确切整数。
简短的回答:是的,它可能会失败。
更长的答案:您的问题完全取决于您正在考虑的 integer 和浮点格式 - 这不仅仅是关于 IEEE 754 的问题。
例如,如果您正在查看 IEEE 754 “双精度” binary64 类型(假设您的语言将其称为double
),并且仅考虑固定宽度的 32 位 integer (有符号或无符号),那么每个这样的 integer 都是完全可以表示为 binary64 浮点数,因此在这种情况下转换为double
不会改变值,并且您确实可以依赖(double)x / (double)y
根据当前舍入模式正确舍入(假设任何语言您正在使用保证根据当前舍入模式正确舍入除法,例如因为它保证遵循 IEEE 754 标准)。
另一方面,如果float
是 IEEE 754 binary32“单精度”浮点类型,则有 32 位有符号整数x
和y
的示例,使得x
可以被y
整除(因此商很小,完全可表示,整数),但(float)x / (float)y
给出不同的值。 一个这样的例子是x = 296852655
和y = 59370531
。 那么x / y
正好是5
,但是最接近x
的 binary32 浮点数是296852640.0
,最接近y
的 binary32 浮点数是59370532.0
,最接近商296852640.0 / 59370532.0
的5.0
浮点数正好是4.999999523162841796875
., 1 ulp
binary64 “双精度” IEEE 754 浮点和 64 位整数存在类似示例。 For example, with x = 2135497568948934666
and y = 305071081278419238
, both x
and y
fit into a signed 64-bit integer type, x / y
is exactly 7
, but (double)x / (double)y
is 6.99999999999999911182158029987476766109466552734375
, again 1 ulp away从确切的结果。
这里还有几个更接近您在标题中提出的问题的示例:再次假设 IEEE 754 单精度算术,采用x = 592534758
和y = 395023172
,它们都可以表示为带符号的 32 位整数。 那么x / y
正好是1.5
,但(float)x / float(y)
是1.50000011920928955078125
。 对于舍入相反的示例,如果x = 1418199327
和y = 945466218
,则x / y
是1.5
并且(float)x / (float)y
是1.49999988079071044921875
。
然而,值得一提的是0.5
不存在这样的例子:如果x
和y
是 32 位有符号整数,使得x / y
正好是0.5
,那么 than 意味着y
正好是x
的两倍,这意味着(float)y
将恰好是(float)x
因为如果(float)x
是最接近x
的可表示值,那么2.0 * (float)x
必须是最接近2.0 * x
的可表示值)。 因此,在这种情况下, (float)x / (float)y
也保证为0.5
。
您在问什么并不完全清楚:“失败”是什么意思? 我想您想知道是否有可能在您的第一行中存在 integer 值作为除数和除数,并且由于舍入问题,结果不是您所期望的。
我认为这是可能的。 在下面的代码中 999,999,999/2,000,000,000 略小于 0.5,因此我们预计结果为 0.0。 但是在 Java 中,结果是 1.0。 如果你做 Math.round(dividend/divisor) 你做 integer 除法并得到正确的答案。
int dividend = 999999999;
int divisor = 2000000000;
float result = Math.round((float)dividend/(float)divisor);
System.out.println(result); // 1.0
这是你的意思吗? 这里的问题不在于没有正确舍入的浮点数,而是在将 integer 转换为浮点数时,您会失去准确性。 float(dividend) 实际上是 1.0E9。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.