当您使用浮点数(float
,double
,long double
类型)时,是否可以检测到精度损失?说:
template< typename F >
F const sum(F const & a, F const & b)
{
F const sum_(a + b);
// The loss of precision must be detected (here or one line above) if some fraction bit is lost due to rounding
return sum_;
}
特别感兴趣的是 x87 FPU存在于目标体系结构中,但没有asm
例程介入纯C ++代码。如果有的话, C ++ 11 或 gnu ++ 11 也会被接受。
答案 0 :(得分:4)
C ++标准对浮点精度的概念非常模糊。没有完全符合标准的方法来检测精度损失。
GNU provides an extension启用浮点异常。您想要捕获的异常是FE_INEXACT
。
答案 1 :(得分:1)
有助于您的一件事是std::numeric_limits<double>::epsilon
,它返回“1和最大值之间的差值,大于1可表示”。换句话说,它会告诉您最大的x
&gt; 0,以便1+x
评估为1。
答案 2 :(得分:1)
您可以考虑在boost库中使用interval arithmetic。它可以保证在计算期间间隔的误差始终增加的属性:∀ x ∈[a,b], f(x) ∈ f([a,b])
。
在您的情况下,您可以考虑将初始范围[a-EPS,a+EPS]
用于初始数字a
。经过一系列操作后,结果间隔abs(y-x)
的{{1}}将是您想知道的(最大)精度损失。
答案 3 :(得分:1)
您可以使用以下内容:
#include <iostream>
#include <fenv.h>
#pragma STDC FENV_ACCESS ON
template <typename F> F sum (const F a, const F b, F &error) {
int round = fegetround();
fesetround(FE_TONEAREST);
F c = a + b;
fesetround(FE_DOWNWARD);
F c_lo = a + b;
fesetround(FE_UPWARD);
F c_hi = a + b;
fesetround(FE_TONEAREST);
error = std::max((c - c_lo), (c_hi - c));
fesetround(round);
return c;
}
int main() {
float a = 23.23528;
float b = 4.234;
float e;
std::cout << sum(a, b, e) << std::endl;
std::cout << e << std::endl;
}
在error
参数中返回最大错误量的快速估计值。请记住,切换舍入模式会刷新浮点单元(FPU)管道,因此不要指望超快速度。
更好的解决方案是尝试间隔算术(倾向于给出悲观的错误间隔,因为不考虑变量相关性),或仿射算术(跟踪变量相关性,从而给出更严格的误差界限)。
在这里阅读这些方法的入门知识: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.36.8089