我正在实现相干噪声函数,并且惊讶地发现使用梯度噪声(即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组装解决方案没问题。
答案 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)
您可以直接使用函数frexp
和ldexp
来修改指数。我不确定这会不会更快。