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