2013-04-23 3 views
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 

Поскольку это является частью MonteCarlo алгоритма и s_equal (х, у) называется миллионы раз, я задаюсь вопросом, есть ли лучше или быстрее способ кодирования это, понятно на простом уровне.

+2

Я делаю что-то вроде abs ((x-y)/x) <1.0e-10 –

+0

«Почти равный» является передовой техникой и не должен быть легко предпринят. Например, если 'a' почти равно' b' и 'b' почти равно' c', из этого не следует, что 'a' почти равно' c'. Это может привести к непредвиденным осложнениям. –

+0

@brianbeuning Рассмотрите возможность публикации этого ответа. Это очень близкое соответствие с представленным алгоритмом, и, удалив все это, если-ветвление, оно должно быть намного быстрее, чем представлено. –

ответ

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

+0

abs (((x == 0.0)? Y: ((y == 0.0)? X: (x-y)/x))) <1.0e-10 –

0

Если вы используете C++ 11, то вы могли бы использовать новые math библиотечные функции, такие как:

bool isgreater(float x, float y)

Больше документации на std::isgreater можно было here.

В противном случае всегда есть is_equal в boost. Кроме того, у SO уже есть куча связанных (не уверены, одинаковых) вопросов, таких как here, here и here.

+0

Спасибо. Я не уверен, что это решает мою проблему. Я попытался найти определение isgreater или is_equal и не вижу, если они делают сравнение epsilon, и если да, то какая точность.Что касается других потоков, я искал их, но выяснил, что большая часть обсуждения посвящена «фиксированному» сравнению с abs (xy) Ale

+1

@Ale http: // www. boost.org/doc/libs/1_36_0/libs/test/doc/html/utf/testing-tools/floating_point_comparison.html – Jeff

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); 

(Во время тестирования я прооперировал случайно сгенерированные двойники между 1М и 1М, выполнением каждой операции 100M раз . с различным входом для каждой итерации каждой операции была приурочена в независимом цикле, сравнивая раз системы -. не стена раз включая накладные петли и генерацию случайных чисел, это решение было около 25% быстрее)

слова. предупреждения: здесь есть много зависимостей аппаратное обеспечение, диапазон ваших удвоений, поведение вашего оптимизатора и т. д. и т. д. Такие ошибки являются обычным явлением, когда вы начинаете угадывать свой компилятор. Я был потрясен, увидев, насколько это было для меня быстрее, так как мне всегда говорили, что целые и плавающие единицы хранятся настолько раздельно на аппаратных средствах, что передача бит от одного к другому всегда требует операции с аппаратной памятью. Кто знает, как хорошо это сработает для вас.

Вам, вероятно, придется немного поиграть с магическими цифрами (1024-е), чтобы заставить его делать то, что вы хотите, - если это возможно.

+0

Спасибо. Это интересное предложение, но пугающее. Код должен быть переносимым и компилироваться кем-либо из сообщества. Я бы предпочел пожертвовать некоторой скоростью, чтобы сделать что-то менее подверженное ошибкам! – Ale