Мне удалось написать функцию на основе Ulps, которая сравнивает два двойника для равенства. Согласно this page, сравнение может быть выполнено с использованием комбинации абсолютного и относительного эпсилона или с использованием целых чисел (Ulps).Сравнение удвоений с использованием ULP (единицы в последнем месте)
У меня есть функции на основе эпсилона и ульпа. Эта функция основана эпсилон:
var IsAlmostEqual_Epsilon = function(a, b) { if (a == b) return true; var diff = Math.abs(a - b); if (diff < 4.94065645841247E-320) return true; a = Math.abs(a); b = Math.abs(b); var smallest = (b < a) ? b : a; return diff < smallest * 1e-12; }
И это Ulps основе (DoubleToInt64Bits
, subtract
, negate
и lessthan
функции в указанной ниже JSBIN):
var IsAlmostEqual_Ulps = function(A, B) { if (A==B) return true; DoubleToInt64Bits(A, aInt); if(aInt.hi < 0) aInt = subtract(Int64_MinValue, aInt); DoubleToInt64Bits(B, bInt); if(bInt.hi < 0) bInt = subtract(Int64_MinValue, bInt); var sub = subtract(aInt, bInt); if (sub.hi < 0) sub = negate(sub); if (lessthan(sub, maxUlps)) return true; return false; }
Согласно Bruce Dawson Ulps основе является предпочтительным. IsAlmostEqual_Ulps
работает нормально в соответствии с тестовой базой из 83 случаев, но функция довольно медленная. Для завершения тестовой базы (JSBIN) требуется около 700-900 мс при выполнении как автономный html (вне JSBIN). На основе Epsilon IsAlmostEqual_Epsilon
занимает всего около 100 мс.
Есть ли что-либо, что можно сделать для ускорения IsAlmostEqual_Ulps
функция? Вы можете предложить также совершенно другое решение или некоторые исправления для моего кода.
Я уже тестировал все, но он сокращает время только на 5-10%. Я ищу что-то вроде 50-80% -ного улучшения времени выполнения. Улучшение 100-500% будет прекрасным, но это может быть только сон.
right_answers
в коде JSBIN получены с использованием функции C# IsAlmostEqual
(см. Вверху кода JSBIN). Обе вышеприведенные функции дают одинаковые результаты во всех 83 случаях.
EDIT:
C++ версии от here:
bool IsAlmostEqual(double A, double B)
{
//http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm
long long aInt = reinterpret_cast<long long&>(A);
if (aInt < 0) aInt = -9223372036854775808LL - aInt;
long long bInt = reinterpret_cast<long long&>(B);
if (bInt < 0) bInt = -9223372036854775808LL - bInt;
return (std::abs(aInt - bInt) <= 10000);
}
Это звучит как задание для типизированных видов буфера: https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView –
Не могли бы вы создать буферизованную версию просмотра? –
@FabioBeltramini: ... и введите его как новый ответ. Текущий только один ответ не дает решения в этом случае. –