ATLAS Offline Software
Classes | Namespaces | Macros | Functions
fpcompare.h File Reference

Workaround x86 precision issues for FP inequality comparisons. More...

#include <cmath>
#include <functional>
Include dependency graph for fpcompare.h:

Go to the source code of this file.

Classes

struct  CxxUtils::fpcompare_fn::equal
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::equalf
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::greater
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::greaterf
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::less
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::lessf
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::greater_equal
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::greater_equalf
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::less_equal
 Compare two FP numbers, working around x87 precision issues. More...
 
struct  CxxUtils::fpcompare_fn::less_equalf
 Compare two FP numbers, working around x87 precision issues. More...
 

Namespaces

 CxxUtils
 
 CxxUtils::fpcompare
 
 CxxUtils::fpcompare_fn
 

Macros

#define CXXUTILS_FPCOMPARE_VOLATILE
 

Functions

bool CxxUtils::fpcompare::equal (double a, double b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::equal (float a, float b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::greater (double a, double b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::greater (float a, float b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::less (double a, double b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::less (float a, float b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::greater_equal (double a, double b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::greater_equal (float a, float b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::less_equal (double a, double b)
 Compare two FP numbers, working around x87 precision issues. More...
 
bool CxxUtils::fpcompare::less_equal (float a, float b)
 Compare two FP numbers, working around x87 precision issues. More...
 

Detailed Description

Workaround x86 precision issues for FP inequality comparisons.

Author
scott snyder
Date
Sep 2008 The functions contained here can be used to work around one of the effects of the brain-damage of the x87 FPU.

Brief summary: If you're writing a comparison function for sort, where the comparison depends on computed floating-point values, eg:

{ return a->pt() > b->pt(); }

then you should replace the comparison with a call to one of the functions in this file:

{ return CxxUtils::fpcompare::greater (a->pt(), b->pt()); }

Longer explanation:

An expression like this (where pt() returns a double):

a->pt() > b->pt()

is compiled (on x86) into a sequence like this:

call a->pt()
save result from FPU to a double stack temporary
call b->pt()
load the temporary back into the FPU
do the comparison

If pt() returns a result with the extra precision bits used (so that the value changes when rounded to a double), then it is possible for this comparison to return true for the case where a==b. This violates the assumptions that std::sort makes of the comparison function, and can cause a crash (possibly even silently wrong results!).

As a fix, we force both parameters into something that has been declared volatile. That forces them to be spilled to memory, ensuring that they are both correctly rounded for the declared data type. The comparison is then done on these rounded values.

We condition this on the parameter FLT_EVAL_METHOD being 2. This is defined in the C standard; a value of 2 means that all FP calculations are done as long double. For other cases, we leave out the volatile qualifiers; this should result in the functions being inlined completely away.

In addition to the free functions in the CxxUtils::fpcompare namespace. we define corresponding functionals in the CxxUtils::fpcompare_fn namespace.

It's also worth pointing out that exactly the same issue arises if one uses a floating-point value as the key for a STL associative container. In that case, this comparison instability may cause the container to become corrupted. While it's probably best to avoid using floats for associative container keys in the first place, if you do have to do that, you can work around this problem by using one of the above functionals as the container's comparison type.

Definition in file fpcompare.h.

Macro Definition Documentation

◆ CXXUTILS_FPCOMPARE_VOLATILE

#define CXXUTILS_FPCOMPARE_VOLATILE

Definition at line 102 of file fpcompare.h.

Amg::compare
std::pair< int, int > compare(const AmgSymMatrix(N) &m1, const AmgSymMatrix(N) &m2, double precision=1e-9, bool relative=false)
compare two matrices, returns the indices of the first element that fails the condition,...
Definition: EventPrimitivesHelpers.h:109
CxxUtils::fpcompare::greater
bool greater(double a, double b)
Compare two FP numbers, working around x87 precision issues.
Definition: fpcompare.h:140
plotBeamSpotMon.b
b
Definition: plotBeamSpotMon.py:77
a
TList * a
Definition: liststreamerinfos.cxx:10
IParticle
Definition: Event/EventKernel/EventKernel/IParticle.h:43