我真的认为关键问题是:精确到双精度意味着什么?
我认为有一个简单的答案:如果r 是真正的答案,而d 是双重表示,那么d-r<=d'-r 对于所有其他可能的双重表示,d'。
这意味着我的 2nd 算法只有在其输出等于黄金源的输出或真正的解决方案恰好位于算法输出之间的一半时才能精确到双精度。
我的 2nd 算法不是那么准确。
现在问题演变为:我需要什么精度?我在与 Debasish 的交流中确定绝对差异不是一个合适的度量标准。我怀疑相对差异更好,但不是我想要的。
我选择了以下算法来报告“差异”,它将 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)。我不确定相对差异表明什么(如果有的话)。
应该有更好的方法来做到这一点,而无需字符串...