准确创建[a,b]范围内的浮点值

时间:2017-02-23 08:56:39

标签: c++ floating-point

考虑

auto x = a + (b-a)*v;

这意味着在[a,b)中按因子v创建[0,1.0)范围内的值。从纯粹的数学角度来看,x>=ax<b。但是,我们如何证明或确保这适用于浮点? abv是相同类型的非负和有限浮点值(doublefloat)和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)。

1 个答案:

答案 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 > ab - 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,您试图避免这种情况。

我的示例是使用ab的异常值构建的,因为这使我免于编写程序以通过暴力查找反例,但不要假设其他更可能, ab的值对不会出现问题。如果我正在寻找其他反例,我会特别寻找浮点减法b - a向上舍入的值对。

编辑:哦,好吧,这是另一个反例:

a作为-1.0后继者的继承者(即双精度,使用C99&#39;十六进制表示法,-0x1.ffffffffffffep-1)和{{1成为b。然后3.0向上舍入到4.0,并将b - a作为v1.0 rounds upa + (b - a) * v的前身。

3.0b - a的某些值不需要向上舍入a进行舍入,这是一个反例,如here所示:take {{ 1}}作为ba的后继作为1.0也可以。