由于浮点精度因较大值而减小,在某些情况下,根据其大小量化值可能很有用 - 而不是按绝对值进行量化。
一种天真的方法可能是检测精度并进行扩展:
float quantize(float value, float quantize_scale) {
float factor = (nextafterf(fabsf(value)) - fabsf(value)) * quantize_scale;
return floorf((value / factor) + 0.5f) * factor;
}
然而这似乎太重了。
相反,它应该可以掩盖浮动mantisa中的位 模拟类似于铸造到16位浮点数的东西,然后返回 - 例如。
不是浮点钻头的专家,我不能说结果浮点数是否有效(or need normalizing)
对于速度,当关于舍入的确切行为不重要时,量化浮点数的快速方法是什么,考虑其大小?
答案 0 :(得分:1)
Veltkamp-Dekker分裂算法将浮点数分成高低部分。示例代码如下。
如果有效数字中有 s 位(IEEE 754 64位二进制中为53),则下面代码中的值Scale
为2 b ,然后*x0
收到x
的高 s - b 位,并且*x1
收到剩余的位,您可以丢弃(或从下面的代码中删除,因此永远不会计算)。如果在编译时知道 b ,例如常数43,则可以用适当的常量替换Scale
,例如0x1p43
。否则,你必须以某种方式产生2 b 。
这需要圆到最近的模式。 IEEE 754算术就足够了,但其他合理的算法也可以。它使关系变得均匀。
这假设x * (Scale + 1)
没有溢出。必须以与分离值相同的精度评估操作。 (double
为double
,float
为float
,依此类推。如果编译器使用float
评估double
个表达式,则会中断。解决方法是将输入转换为支持的最宽浮点类型,执行该类型的拆分[相应调整Scale
],然后转换回来。)
void Split(double *x0, double *x1, double x)
{
double d = x * (Scale + 1);
double t = d - x;
*x0 = d - t;
*x1 = x - *x0;
}