是否存在错误计算为略低于 .5 或 .0 的浮点数?
Does a float exist that wrongly evaluates to slightly below .5 or .0?
我正在使用它来获得正确舍入的整数除法:
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 有先进的内部知识,并且有证据证明为什么这绝对不可能发生。
将范围扩大一位数,其中 this result、none 个数字回答了这个问题。
相关问题:something.99999
呢?一个similar test had this result。所有这些浮点数都与精确整数的浮点数不同。
你问的不是很清楚:'fail' 是什么意思?我想你想知道是否有可能在你的第一行中有股息和除数的整数值,并且由于四舍五入问题,结果不是你所期望的。
我认为这是可能的。在下面的代码中,999,999,999/2,000,000,000 略小于 0.5,因此我们期望结果为 0.0。但是在 Java 中,结果是 1.0。如果你做 Math.round(dividend/divisor) 你做整数除法并得到正确答案。
int dividend = 999999999;
int divisor = 2000000000;
float result = Math.round((float)dividend/(float)divisor);
System.out.println(result); // 1.0
你是这个意思吗?这里的问题不是没有正确舍入的浮点数,而是在将整数转换为浮点数时你失去了准确性。 float(dividend) 实际上是 1.0E9.
简短回答:是的,它可能会失败。
更长的答案:您的问题完全取决于您正在考虑的整数和 floating-point 格式 - 这不仅仅是关于 IEEE 754 的问题。
例如,如果您正在查看 IEEE 754 "double precision" binary64 类型(假设您的语言称之为 double
),并且只考虑 fixed-width 32 位整数(有符号或无符号),那么每个这样的整数都可以精确表示为 binary64 浮点数,因此在这种情况下转换为 double
不会更改值,您确实可以依赖 (double)x / (double)y
是正确的根据当前舍入模式舍入(假设您使用的任何语言都能保证除法根据当前舍入模式正确舍入,例如因为它保证遵循 IEEE 754 标准)。
如果另一方面 float
是 IEEE 754 binary32 "single-precision" floating-point 类型,则有 32 位有符号整数的示例 x
和 y
使得 x
可以被 y
整除(因此商是一个小的、可以完美表示的整数),但是 (float)x / (float)y
给出了不同的值。一个这样的例子是 x = 296852655
和 y = 59370531
。那么 x / y
恰好是 5
,但是最接近 x
的 binary32 float 是 296852640.0
,最接近 y
的 binary32 float 是 59370532.0
,并且最接近商 296852640.0 / 59370532.0
的 binary32 浮点数正好是 4.999999523162841796875
,距离 5.0
.
一个 ulp
binary64 "double precision" IEEE 754 floating-point 和 64 位整数也存在类似的例子。例如,对于 x = 2135497568948934666
和 y = 305071081278419238
,x
和 y
都适合一个带符号的 64 位整数类型,x / y
正好是 7
, 但 (double)x / (double)y
是 6.99999999999999911182158029987476766109466552734375
, 又与确切结果相差 1 ulp。
这里有几个例子更接近你在标题中提出的问题:再次假设 IEEE 754 single-precision 算法,取 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
的两倍,而 that 意味着 (float)y
恰好是 (float)x
的两倍](因为如果 (float)x
是最接近 x
的可表示值,那么 2.0 * (float)x
必须是最接近 2.0 * x
的可表示值)。所以在那种情况下,(float)x / (float)y
也保证是 0.5
。
我正在使用它来获得正确舍入的整数除法:
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 有先进的内部知识,并且有证据证明为什么这绝对不可能发生。
将范围扩大一位数,其中 this result、none 个数字回答了这个问题。
相关问题:something.99999
呢?一个similar test had this result。所有这些浮点数都与精确整数的浮点数不同。
你问的不是很清楚:'fail' 是什么意思?我想你想知道是否有可能在你的第一行中有股息和除数的整数值,并且由于四舍五入问题,结果不是你所期望的。
我认为这是可能的。在下面的代码中,999,999,999/2,000,000,000 略小于 0.5,因此我们期望结果为 0.0。但是在 Java 中,结果是 1.0。如果你做 Math.round(dividend/divisor) 你做整数除法并得到正确答案。
int dividend = 999999999;
int divisor = 2000000000;
float result = Math.round((float)dividend/(float)divisor);
System.out.println(result); // 1.0
你是这个意思吗?这里的问题不是没有正确舍入的浮点数,而是在将整数转换为浮点数时你失去了准确性。 float(dividend) 实际上是 1.0E9.
简短回答:是的,它可能会失败。
更长的答案:您的问题完全取决于您正在考虑的整数和 floating-point 格式 - 这不仅仅是关于 IEEE 754 的问题。
例如,如果您正在查看 IEEE 754 "double precision" binary64 类型(假设您的语言称之为 double
),并且只考虑 fixed-width 32 位整数(有符号或无符号),那么每个这样的整数都可以精确表示为 binary64 浮点数,因此在这种情况下转换为 double
不会更改值,您确实可以依赖 (double)x / (double)y
是正确的根据当前舍入模式舍入(假设您使用的任何语言都能保证除法根据当前舍入模式正确舍入,例如因为它保证遵循 IEEE 754 标准)。
如果另一方面 float
是 IEEE 754 binary32 "single-precision" floating-point 类型,则有 32 位有符号整数的示例 x
和 y
使得 x
可以被 y
整除(因此商是一个小的、可以完美表示的整数),但是 (float)x / (float)y
给出了不同的值。一个这样的例子是 x = 296852655
和 y = 59370531
。那么 x / y
恰好是 5
,但是最接近 x
的 binary32 float 是 296852640.0
,最接近 y
的 binary32 float 是 59370532.0
,并且最接近商 296852640.0 / 59370532.0
的 binary32 浮点数正好是 4.999999523162841796875
,距离 5.0
.
binary64 "double precision" IEEE 754 floating-point 和 64 位整数也存在类似的例子。例如,对于 x = 2135497568948934666
和 y = 305071081278419238
,x
和 y
都适合一个带符号的 64 位整数类型,x / y
正好是 7
, 但 (double)x / (double)y
是 6.99999999999999911182158029987476766109466552734375
, 又与确切结果相差 1 ulp。
这里有几个例子更接近你在标题中提出的问题:再次假设 IEEE 754 single-precision 算法,取 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
的两倍,而 that 意味着 (float)y
恰好是 (float)x
的两倍](因为如果 (float)x
是最接近 x
的可表示值,那么 2.0 * (float)x
必须是最接近 2.0 * x
的可表示值)。所以在那种情况下,(float)x / (float)y
也保证是 0.5
。