Простой способ сравнить двойники

Я пишу числовой код, который должен делать обширные (и, возможно, быстрые) сравнения среди чисел двойной точности. Мое решение для сравнения двух чисел 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) вызывается миллионы раз, мне интересно, есть ли лучший или более быстрый способ кодирования этого, понятный на простом уровне.

0

Решение

Я делаю что-то вроде абс ((х-у) / х) < 1.0e-10.

Вам нужно разделить на x в случае, если оба значения являются большими или крошечными.

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% быстрее.)

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

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

0

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

bool isgreater(float x, float y)

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

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

0
По вопросам рекламы [email protected]