0

我正在编写一个数字代码,需要在双精度数字之间进行广泛(可能是快速)比较。我比较两个数字 A 和 B 的解决方案包括将 A 向左(或向右)移动一个 epsilon 并检查结果是否大于(或小于)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

由于这是蒙特卡洛算法的一部分,并且 s_equal(x,y) 被调用了数百万次,我想知道是否有更好或更快的方法来编写这个代码,在简单的层面上是可以理解的。

4

3 回答 3

0

通过避免所有双精度数学,我惊讶地发现显着加速:

#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%。)

一个警告:这里有很多依赖于你的硬件,你的双打范围,你的优化器的行为等等。当你开始猜测你的编译器时,这样的陷阱很常见。我很震惊地看到这对我来说有多快,因为我一直被告知整数和浮点单元在硬件上保持如此独立,以至于从一个到另一个的位传输总是需要硬件内存操作。谁知道这对你有多好。

您可能需要稍微使用一下神奇的数字(1024s)才能让它按照您的意愿去做——如果它甚至可能的话。

于 2013-04-24T16:52:43.013 回答
0

我做了类似 abs( (xy)/x ) < 1.0e-10 的事情。

如果两个值都很大或很小,则需要除以 x。

于 2013-04-24T03:37:41.880 回答
0

如果您使用的是 C++11,那么您可以使用新的math库函数,例如:

bool isgreater(float x, float y)

更多文档std::isgreater可以在这里找到

否则,总会is_equal有提升。此外,SO 已经有一堆相关的(不确定是否相同)问题,例如这里这里这里的问题。

于 2013-04-24T03:18:03.220 回答