有效地将双倍除以2的幂

时间:2012-01-19 13:21:13

标签: c++ c x86

我正在实现相干噪声函数,并且惊讶地发现使用梯度噪声(即Perlin噪声)实际上比值噪声略快。分析表明,原因是将随机int值转换为范围-1.0到1.0的双倍所需的除法:

static double noiseValueDouble(int seed, int x, int y, int z) {
    return 1.0 - ((double)noiseValueInt(seed, x, y, z) / 1073741824.0);
}

渐变噪声需要多次乘法,但由于预先计算的梯度表直接使用noiseValueInt来计算表中的索引,并且不需要任何除法。所以我的问题是,考虑到除法是2(2 ^ 30)的幂,我怎样才能使上述除法更有效。

从理论上讲,所有需要做的就是从双指数中减去30,但是通过强力(即位操作)这样做会导致各种极端情况(INF,NAN,指数溢出等) 。 x86组装解决方案没问题。

4 个答案:

答案 0 :(得分:6)

用反向值声明一个变量(或常量)并乘以它,有效地将除法改为乘法:

static const double div_2_pow_30 = 1.0 / 1073741824.0;

另一种方式(利用数字是2的幂的属性)是用位操作修改指数。这样做会使代码依赖于使用可能不太便携的IEEE标准存储的双精度。

答案 1 :(得分:2)

我不确定你能相信这里的分析。对于更小,更快的函数,分析代码本身的效果开始扭曲结果。

在循环中运行noiseValueDouble和相应的替代方案以获得更好的数字。

x86汇编程序解决方案 是一个有点小问题的解决方案,您也可以在C中进行数字处理。快速二次除法指令(位移)仅对整数存在。< / p>

如果你真的想使用特殊说明,MMX或其他东西。

答案 2 :(得分:0)

我尝试用gcc编译:

double divide(int i) {
    return 1.0 - (double)i / 1073741824.0;
}

-O3将其编码为FMULS - 指令,-O3 -mfpmath=sse -march=core2使用SSE指令集并将其编码为MULSD。我不知道什么是最快的,但函数调用本身可能比实际分区慢几个数量级。

答案 3 :(得分:0)

您可以直接使用函数frexpldexp来修改指数。我不确定这会不会更快。