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

Joh*_*erg 3 c++ floating-point

考虑

auto x = a + (b-a)*v;
Run Code Online (Sandbox Code Playgroud)

其目的是要建立在范围内的值[a,b)由系数v[0,1.0).从纯数学的角度来看x>=a,和x<b.但是,我们如何证明或确保这适用于浮点? a,b,v是同一类型的非负的有限浮点值(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;
Run Code Online (Sandbox Code Playgroud)

但这也是多余的吗?

if (x>=b) return std::nextafter(b,a);
Run Code Online (Sandbox Code Playgroud)

可能编译器(优化)重写表达式来影响这些问题吗?浮点表示的类型是否输入?(我最感兴趣的是最常见的(iec559/IEEE 754).

Pas*_*uoq 5

很明显,ba> 0,因此(ba)*v> = 0,所以我们不需要检查: if (x<a) return a;

该属性b - a > 0在IEEE 754中是正确的,但我不会说它是显而易见的.在浮点标准化的时候,Kahan 争夺这个属性,因为"逐渐下溢"是真的.其他提案没有低于正常的数字,也没有成功.你可以拥有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)*vb,您试图避免.


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


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

就拿a是的继任者的继任者-1.0(即,在双精度,采用C99的十六进制表示,-0x1.ffffffffffffep-1)和b3.0.然后b - a向上舍入到4.0,并且v成为前者1.0,a + (b - a) * v 最后到达3.0.

浮点减法b - a围捕不需要的一些值a,并b制作一个反例,如在这里:以a作为继任者1.0,并b2.0也适用.