2013-04-23 118 views
0

我在写一个数字代码,需要在双精度数字之间进行广泛的(也可能是快速的)比较。我比较两个数字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 

由于这是蒙特卡洛算法和s_equal(X,Y)的部分被称为数百万次,我不知道是否有任何更好或更快地码这在简单的层面上是可以理解的。

+2

我喜欢abs((x-y)/ x)<1.0e-10 – 2013-04-23 23:33:21

+0

“几乎相等”是一种先进的技术,不应该轻易进行。例如,如果'a'几乎等于'b'且'b'几乎等于'c',那么'a'几乎等于'c'。这可能会导致意想不到的并发症。 – 2013-04-24 00:39:44

+0

@brianbeuning考虑发布这个答案。它与所提出的算法非常接近匹配,并且通过消除所有分支,它应该比所呈现的快得多。 – 2013-04-24 03:30:40

回答

0

我做一些像abs((x-y)/ x)< 1.0e-10。

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

+0

感谢您的回复!我想到了这种实现,但意识到它可能是危险的:1)当x为0时,它会给NaN 2)当y为0时,lhs等于1,不管x如何接近于0。解决方案中的'abs'对我来说似乎很自然,以便摆脱许多if语句,但将0附近的数字处理并不明显。你有没有想过这个问题?你是如何解决它的? – Ale 2013-04-24 19:42:45

+0

abs(((x == 0.0)?y:((y == 0.0)?x:(x-y)/ x)))<1.0e-10 – 2013-04-24 23:35:51

0

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

bool isgreater(float x, float y)

更多的文档上std::isgreater就可以了here

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

+0

谢谢。我不确定这是否解决了我的问题。我试图找到isgreater或is_equal的定义,并且无法看到它们是否进行epsilon比较,如果是的话,以及哪个精度。关于其他线程,我确实搜索了它们,但发现大部分讨论都是关于“固定”epsilon与abs(xy)<ε的比较,我认为这是错误的... – Ale 2013-04-24 20:02:12

+1

@Ale http:// www。 boost.org/doc/libs/1_36_0/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html – Jeff 2014-08-06 12:52:23

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)才能让它处理你想要的东西 - 如果它是可能的话。

+0

谢谢。这是一个有趣的建议,但吓人。代码必须是可移植的并且由社区中的任何人编译。我宁愿牺牲一些速度来减少错误发生的几率! – Ale 2013-04-24 20:30:36