◆ ulpdist()

IEEEValue boost::simd::ulpdist ( IEEEValue const &  x,
IEEEValue const &  y 
)

This function object returns ulp distance between its arguments.

It is often difficult to answer to the following question: "are these two floating computations results similar enough?". The ulpdist is a way to answer which is tuned for relative errors estimations and peculiarly adapted to cope with the limited bits accuracy of floating point representations.

Header <boost/simd/function/ulpdist.hpp>
Notes
  • If the common type is integral ulpdist is the same as dist
  • If the common type is floating point the ulpdist is is computed, by the above described method.

The method is the following:

  • If one and only one of the parameters is Nan the result is Nan, if both are Nans the result is Zero
  • Else, properly normalize the two numbers by the same factor in a way that the largest of the two numbers exponents will be brought to zero
  • Return the absolute difference of these normalized numbers divided by the rounding error Eps

The rounding error is the ulp (unit in the last place) value, i.e. the floating number, the exponent of which is 0 and the mantissa is all zeros but a 1 in the last digit (it is not hard coded that way however). This means \(2^{-23}\) for float and \(2^{-52}\) for double.

  • For instance if two floating numbers (of same type) have an ulpdist of Zero that means that their floating representation are identical or they are both Nans.
  • Generally equality up to 0.5 ulp is the best that one can wish beyond strict equality.
  • Typically if a double is compared to the float representation of its floating conversion (they are exceptions as for fully representable reals) the ulpdist will be around \(2^{26.5}\) (~ \(10^8\))
  • ulpdist(1.0,1+Eps<double>())==0.5
  • ulpdist(1.0,1+Eps<double>()/2)==0.0
  • ulpdist(1.0,1-Eps<double>()/2)==0.25
  • ulpdist(1.0,1-Eps<double>())==0.5
  • ulpdist(double(Pi<float>()),Pi<double>())==9.84293e+07
See also
ulp, Eps, eps
Example:
#include <boost/simd/ieee.hpp>
#include <boost/simd/pack.hpp>
#include <boost/simd/constant/eps.hpp>
#include <iostream>
namespace bs = boost::simd;
using pack_ft = bs::pack <float, 4>;
int main()
{
pack_ft pf = {1.0f, 2.0f, -1.0f, 0.5f};
pack_ft qf = pf+10*bs::Eps<float>();
std::cout
<< "---- simd" << '\n'
<< "<- pf = " << pf << '\n'
<< "<- qf = " << qf << '\n'
<< "-> bs::ulpdist(pf, qf) = " << bs::ulpdist(pf, qf) << '\n';
float xf = 2.0f;
float yf = xf+10*bs::Eps<float>();
std::cout
<< "---- scalar" << '\n'
<< "<- xf = " << xf << '\n'
<< "<- yf = " << yf << '\n'
<< "-> bs::ulpdist(xf, yf) = " << bs::ulpdist(xf, yf) << '\n';
return 0;
}
Possible output:
---- simd
<- pf = (1, 2, -1, 0.5)
<- qf = (1, 2, -0.999999, 0.500001)
-> bs::ulpdist(pf, qf) = (5, 2.5, 5, 10)
---- scalar
<- xf = 2
<- yf = 2
-> bs::ulpdist(xf, yf) = 2.5