Reputation: 16731
Is it possible to detect the loss of precision, when you operate with floating-point numbers (of float
, double
, long double
types)? Say:
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_;
}
Especially intrested in case of when x87 FPU is present on target architecture, but without the intervention of the asm
routines into the pure C++ code. C++11 or gnu++11 specific features also accepted if any.
Upvotes: 5
Views: 1559
Reputation: 851
You can use something like the following:
#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;
}
A quick estimate of the maximum error amount is returned in the error
argument. Bear in mind that switching the rounding mode flushes the floating-point unit (FPU) pipeline, so don't expect blazing fast speeds.
A better solution would be to try Interval Arithmetic (tends to give pessimistic error intervals, because variable correlations are not accounted for), or Affine Arithmetic (tracks variable correlations, and thus gives somewhat tighter error bounds).
Read here for a primer in these methods: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.36.8089
Upvotes: 2
Reputation: 2200
You may consider to use the interval arithmetic in boost library. It can guarantee the property that the error for an interval is always increasing during calculation: ∀ x ∈[a,b], f(x) ∈ f([a,b])
.
In your case, you might consider to use the initial range [a-EPS,a+EPS]
for the initial number a
. After a series of operations, the abs(y-x)
for the resulting interval [x,y]
will be the (maximum) loss of precision you want to know.
Upvotes: 2
Reputation: 33126
One thing that will help you is std::numeric_limits<double>::epsilon
, which returns "the difference between 1 and the least value greater than 1 that is representable." In other words, it tells you the largest x
>0 such that 1+x
evaluates to 1.
Upvotes: 1
Reputation: 63947
The C++ standard is very vague on the concept of floating point precision. There is no fully standard-conforming way to detect precision loss.
GNU provides an extension to enable floating-point exceptions. The exception you would want to trap is FE_INEXACT
.
Upvotes: 5