考虑
auto x = a + (b-a)*v;
这意味着在[a,b)
中按因子v
创建[0,1.0)
范围内的值。从纯粹的数学角度来看,x>=a
和x<b
。但是,我们如何证明或确保这适用于浮点?
a
,b
,v
是相同类型的非负和有限浮点值(double
或float
)和b>a
(最初说的b>=a
显然与我对x
)和v<=netxtafter(1.0,0)
的要求不相符(也就是说,它刚好低于1.0)。
很明显,b-a >0
,因此(b-a)*v >=0
,所以我们不需要检查:
if (x<a) return a;
但这也是多余的吗?
if (x>=b) return std::nextafter(b,a);
编译器(优化)可以重写表达式来影响这些问题吗? 浮点表示的类型是否输入? (我最感兴趣的是最常见的(iec559 / IEEE 754)。
答案 0 :(得分:5)
很明显,b-a> 0,因此(b-a)* v> = 0,因此我们不需要检查:
if (x<a) return a;
属性b - a > 0
在IEEE 754中是正确的,但我不会说它很明显。在浮点标准化时,Kahan fought for this property resulting from “gradual underflow” to be true。其他提案没有低于正常的数字,也没有成功。您可以在这些其他提案中使用b > a
和b - a == 0
,例如将a
取为最小的正数而b
为其后继者。
即使没有逐渐下溢,在一个错误实现IEEE 754的系统上,通过将子范数刷新为零,b > a
隐含b - a >= 0
,因此无需担心x
低于a
。
但这也是多余的吗?
if (x>=b) return std::nextafter(b,a);
即使在IEEE 754中,此测试也不冗余。例如,b
成为a
的后继者。对于v
以上0.5
的所有值,在默认的舍入到最近模式中,a + (b-a)*v
的结果为b
,您试图避免这种情况。
我的示例是使用a
和b
的异常值构建的,因为这使我免于编写程序以通过暴力查找反例,但不要假设其他更可能, a
和b
的值对不会出现问题。如果我正在寻找其他反例,我会特别寻找浮点减法b - a
向上舍入的值对。
编辑:哦,好吧,这是另一个反例:
将a
作为-1.0
后继者的继承者(即双精度,使用C99&#39;十六进制表示法,-0x1.ffffffffffffep-1
)和{{1成为b
。然后3.0
向上舍入到4.0,并将b - a
作为v
,1.0
rounds up到a + (b - a) * v
的前身。
3.0
和b - a
的某些值不需要向上舍入a
进行舍入,这是一个反例,如here所示:take {{ 1}}作为b
和a
的后继作为1.0
也可以。