我正在编写一个数字代码,需要在双精度数之间进行广泛(可能是快速)的比较。我比较两个数字A和B的方法是将A向左(或向右)移动一个,并检查结果是否比B大(或小)。如果是,两个双精度数是相同的。(负数或零数需要额外编码)。
这是比较函数:
#define S_
inline double s_l (double x){
if(x>0){return 0.999999999*x;}
else if(x<0){return 1.00000001*x;}
else {return x-0.000000000001;}
}
inline double s_r (double x){
if(x>0){return 1.00000001*x;}
else if(x<0){return 0.999999999*x;}
else{return x+0.000000000001;}
}
inline bool s_equal (double x,double y){
if(x==y){return true;}
else if(x<y && s_r(x)>y){return true;}
else if(x>y && s_l(x)<y){return true;}
else{return false;}
}
#endif
由于这是MonteCarlo算法的一部分,并且s_equal(x,y)被调用了数百万次,我想知道是否有更好或更快的方法来编写此代码,在简单的级别上可以理解
我做的是abs((x-y)/x) <1.0平台以及。
如果两个值都很大或很小,则需要除以x
我惊讶地发现,通过避免所有的双精度计算,可以显著提高速度:
#define S_L(x) (x)+((x)<0?1024:-1024)
#define S_R(x) (x)+((x)<0?-1024:1024)
#define S_EQUAL(x,y) (S_L(x)<(y) && S_R(x)>(y))
double foo;
double bar;
long *pfoo;
long *pbar;
pfoo = (long*)&foo;
pbar = (long*)&bar;
double result1 = S_R(*pfoo);
double result2 = S_L(*pbar);
bool result3 = S_EQUAL(*pfoo, *pbar);
(在测试中,我对在-1M和1M之间随机生成的双精度对象进行操作,每次迭代使用不同的输入执行每个操作100M次。每个操作都在一个独立的循环中计时,比较系统时间,而不是墙时间。包括循环开销和随机数的生成,这个解决方案大约快了25%。)
一个警告:这里有很多依赖于你的硬件,你的双精度范围,你的优化器的行为,等等。当您开始对编译器进行事后评估时,这样的陷阱很常见。看到这对我来说有多快,我很震惊,因为我一直被告知,整数和浮点单位在硬件上是分开的,所以从一个到另一个的比特传输总是需要硬件内存操作。谁知道这对你有多管用呢。
你可能不得不玩弄一些神奇的数字(1024)来让它做你想做的事情——如果它可能的话。
如果您使用的是c++ 11,那么您可以使用新的math
库函数,例如:
bool isgreater(float x, float y)
关于std::isgreater
的更多文档可以在这里找到。
否则,boost中总是有is_equal
。此外,SO已经有一堆相关的(不确定是否相同)问题,如这里,这里和这里的问题。