...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Function ulp
gives the size
of a unit-in-the-last-place for a specified floating-point value.
#include <boost/math/special_functions/ulp.hpp>
namespace boost{ namespace math{ template <class FPT> FPT ulp(const FPT& x); template <class FPT, class Policy> FPT ulp(const FPT& x, const Policy&); }} // namespaces
Returns one unit in the last place of x.
Corner cases are handled as follows:
double
this would be either std::numeric_limits<double>::min()
or std::numeric_limits<double>::denorm_min()
depending whether denormals are supported
(which have the values 2.2250738585072014e-308
and 4.9406564584124654e-324
respectively).
ulp(x) == ulp(-x)
.
Important: The behavior of this function is aligned to that of Java's ulp function, please note however that this function should only ever be used for rough and ready calculations as there are enough corner cases to trap even careful programmers. In particular:
u
= ulp(x)
if x
> 0
then x +
u
is the next floating-point
value, but x -
u
is not necessarily the previous
value. Similarly, if x < 0
then x -
u
is the previous floating-point
value, but x +
u
is not necessarily the next
value. The corner cases occur at power of 2 boundaries.
boost::math::detail::has_denorm_now<FPT>()
), but also whether these are currently
enabled at runtime (for example on SSE hardware, the DAZ or FTZ flags
will disable denormal support). In this situation, the ulp
function may return a value that
is many orders of magnitude too large.
In light of the issues above, we recommend that:
std::nextafter
is another candidate, but
our experience is that this also often breaks depending which optimizations
and hardware flags are in effect).
There is none the less, one important use case for this function:
If it is known that the true result of some function is xt and the calculated
result is xc, then the error measured in ulp is simply fabs(xt -
xc) / ulp(xt)
.