这是一个特定的利基问题,因此在标题中充分说明:
给定两个非负数
a
和b
,其中a
小于或等于b
,我关心以下算法中的y
是否小于或等于b
。
算法:
x = b-a;
y = x+a;
y<=b
一般只要0<=a<=b
那么长吗?
float
和double
。我关心任何符合 IEEE 标准的号码。a和b分别是
a
和b
的值,对于x和y也类似。 b− 是小于 b 的下一个可表示的浮点格式值,b+ 是大于 b 的下一个可表示值。
纯字体的数学代表实数数学。 b−a 是不四舍五入的实数减法结果。
code font
中的数学表示浮点运算。 b-a
是执行浮点减法的结果,等于 b−a 根据选定的舍入方法舍入到可表示的值。
y
≤ b
显然是错误的:
令 b 为 1,a 为 ½(b−b−)。 (我假设格式的指数范围足以表示 a。)则 b−a 不可表示,并且位于 b− 和 b 之间。向上舍入,
x = b-a
生成 b
。那么 x+a 位于 b 和 b+ 之间,因此,向上舍入,y = x+a
会生成 b+。这违反了 y
≤ b
。
向下舍入(向−∞)或向零舍入,我们考虑两种情况:
a
为零,a
不为零(0< a
≤b
)。
当
a
= 0 时,x = b-a
产生 b
,y = x+a
产生b
,并且满足 y
≤ b
。
当
a
不为零时,由于舍入方向,x = b-a
会产生小于或等于 b−a 的值。然后 y = x+a
产生小于或等于 x+a ≤ b−a+a = b 的值,因此 y
≤ b
成立。
对
float
使用 IEEE-754 二进制 32 并进行舍入到最接近、偶数连接,此代码会生成大于 y
的 b
:
float b = 0x.FFFFFFp0;
float a = 0x.0000018p0;
float x = b-a;
float y = x+a;
解释:设 b 为 1−2−24。 (这是紧邻 1 之前的可表示值,等于 0.FFFFFF16。)令 a 为 1½•2−24(相当于 1.5•2−24、3•2−25、或 0.000001816).
b−a = 1−2−24 − 3•2−25 = 1-5•2−25 = 0.FFFFFD816,这在二进制32中无法表示。 (在二进制中,其前导 1 位位于 2−1,尾随 1 位位于 2−25,其跨度超过了二进制 32 格式有效数中的 24 位。)相邻的可表示值 1−3•2−24 = 0.FFFFFD16 和 1−2•2−24 = 0.FFFFFE16。由于这些是等距的,因此使用舍入到最接近的舍入、连到偶数进行舍入会产生具有偶数低位的数字,0.FFFFFE16 = 1−2•2−24。因此
x = b-a
将 x
设置为该值。
现在考虑
y = x+a
。 x+@a 为 1−2•2−24 + 3•2−25 = 1−2•2−25 = 0.FFFFFF816。这不具有代表性。它位于相邻可表示值 1−2−24 = 0.FFFFFF16 和 1 = 1.0000016 之间。同样,使用偶数低位的数字,因此 y = x+a
产生 1。由于 y
是 1 并且 b
是 1−2−24,因此 y
≤ b
为假。