如果具有以下C函数,则用于确定一个数字是否是另一个数字与arbirary容差的倍数
#include <math.h>
#define TOLERANCE 0.0001
int IsMultipleOf(double x,double mod)
{
return(fabs(fmod(x, mod)) < TOLERANCE);
}
它工作正常,但分析显示它非常慢,只要它已成为优化的候选者。约有75%的时间用于modulo
,其余时间用于fabs
。我正在试图找到一种加快速度的方法,使用像查找表这样的东西。参数x
会定期更改,而mod
不经常更改。 x的可能值的数量足够小,使得查找的空间不会成为问题,通常它将是几百个可能值中的一个。我可以很容易地摆脱fabs
,但无法找出模数的合理替代方案。关于如何优化上述的任何想法?
编辑该代码将在各种Windows桌面和移动设备上运行,因此处理器可能包括英特尔,AMD在桌面上,以及ARM或SH4在移动设备上。 VisualStudio 2008是编译器。
答案 0 :(得分:3)
你真的必须使用modulo
吗?
是不是可以只result = x / mod
,然后检查result
的小数部分是否接近0.例如:
11 / 5.4999 = 2.000003 ==> 0.000003 < TOLERANCE
或类似的东西。
答案 1 :(得分:1)
除法(在你的情况下是浮点,fmod
)通常是一个操作,执行时间根据cpu和编译器的不同而变化很多:
__builtin_fmod
明确。然后这可能会映射
操作上少数
汇编指令。通过这些技巧,取决于你的环境(你没有告诉哪个),时间可能会从一些时钟周期变化到几百个。我认为最好是查看编译器和cpu的文档以了解该特定操作。
答案 2 :(得分:1)
以下可能是矫枉过正,并且次优。但是,这里有什么值得一提的方法。
我们知道双重格式...
让...
一旦你拥有了......
/*
* If applying the exponent would eliminate the fraction bits
* then for double precision resolution it is a multiple.
* Note: lsb may require some massaging.
*/
if (exp > lsb)
return (true);
if (exp < 0)
return (false);
剩下的唯一案例是容忍案例。建立你的双倍,以便你摆脱小数点左边的所有数字。
现在将它与您的容忍度进行比较。
答案 3 :(得分:1)
我认为您需要检查C RTL fmod()
函数的大小:X86 FPU有'FPREM/FPREM1'指令,通过重复减法计算余数。
虽然浮点除法是单指令,但似乎您可能需要重复调用FPREM以获得模数的正确答案,因此您的RTL可能不会使用它。
答案 4 :(得分:1)
我根本没有测试过这个,但从我理解fmod的方式来看,这应该是等效内联的,这可能让编译器更好地优化它,尽管我会认为编译器的数学库(或内置函数)只能工作同样。 (另外,我甚至不确定这是否正确)。
#include <math.h>
int IsMultipleOf(double x, double mod) {
long n = x / mod; // You should probably test for /0 or NAN result here
double new_x = mod * n;
double delta = x - new_x;
return fabs(delta) < TOLERANCE; // and for NAN result from fabs
}
答案 5 :(得分:1)
如果你有相当规模的数据,也许你可以用很长的时间而不是双倍。例如long long
就足以超过60 astronomical units in micrometer resolution。
答案 6 :(得分:0)
需要双精度吗?根据你的数学库有多好,这应该更快:
#include <math.h>
#define TOLERANCE 0.0001f
bool IsMultipleOf(float x, float mod)
{
return(fabsf(fmodf(x, mod)) < TOLERANCE);
}
答案 7 :(得分:0)
我认为modulo在内部看起来有点像这样:
mod(x,m) {
while (x > m) {
x = x - m
}
return x
}
我认为通过某种搜索我可以进行优化:例如:
fastmod(x,m) {
q = 1
while (m * q < x) {
q = q * 2
}
return mod((x - (q / 2) * m), m)
}
您甚至可以选择将finall调用替换为mod,并调用fastmod,添加条件:如果x&lt;然后返回x。