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