Я действительно думаю, что ключевой вопрос заключается в следующем: что значит быть точным до двойной точности?
И я думаю, что есть простой ответ: если r
— настоящий ответ, а d
— двойное представление, то d-r<=d'-r
для всех других возможных двойников — d'
.
Это означает, что мой 2nd алгоритм может быть точен до двойной точности только в том случае, если его выходные данные равны выходным данным золотого источника или действительное решение находится точно посередине между выходными данными алгоритма.
Мой 2nd алгоритм не такой точный.
Теперь возникает вопрос: какая точность мне требуется? В обмене с Дебасишем я установил, что абсолютные различия не являются подходящей метрикой. Я подозреваю, что относительные различия лучше, но не совсем то, что я хочу.
Я остановился на следующем алгоритме, чтобы сообщить о «разнице», который считает равенство до 15 значащих цифр равенством:
double doubles_differ(double a, double b) {
const int significant_figures = 15;
// This test will catch most cases
if (std::abs(a - b) < pow(.1, significant_figures)
* std::max(std::abs(a), std::abs(b)))
return 0;
// Because we are at the edge of double precision, sometimes a case that is
// actually equal slips through the above test. The following should be more
// robust, but a lot slower.
std::stringstream ss_a;
std::stringstream ss_b;
ss_a << std::setprecision(significant_figures - 1) << std::scientific << a;
ss_b << std::setprecision(significant_figures - 1) << std::scientific << b;
std::string s_a = ss_a.str();
std::string s_b = ss_b.str();
if (s_a == s_b)
return 0;
// Finally, return the difference scaled to unity.
// Format: "7.70612131004268e-013" = significand, followed by "e±nnn".
if (s_a.substr(s_a.length() - 5, 5) != s_b.substr(s_b.length() - 5, 5))
throw std::runtime_error("Big diff");
std::stringstream ss_convert_a(s_a.substr(0, s_a.length() - 6));
std::stringstream ss_convert_b(s_b.substr(0, s_b.length() - 6));
double a_converted;
double b_converted;
if (!(ss_convert_a >> a_converted))
throw std::runtime_error("Could not convert a");
if (!(ss_convert_b >> b_converted))
throw std::runtime_error("Could not convert b");
return std::abs(a_converted - b_converted);
}
Наконец, некоторые примеры данных:
a = 9.9399367132570751e-016
b = 9.9399367132633209e-016
index 1 2345678901234567
diff = 6.3007377093526884e-012
relative diff = 6.2835472672107563e-013
Обратите внимание, что показатель степени diff
указывает количество значащих цифр точности (в данном случае 12). Я не уверен, на что (если вообще что-либо) указывает относительная разница.
Должен быть лучший способ сделать это без строк...
person
Rai
schedule
26.09.2014
float
илиdouble
указанной точностью и поведением округления. - person πάντα ῥεῖ   schedule 25.09.2014