Opened 8 years ago

Closed 8 years ago

Last modified 8 years ago

#6700 closed task (fixed)

ABS -> std::abs for C++

Reported by: Kurt Schwehr Owned by: Kurt Schwehr
Priority: normal Milestone:
Component: default Version: unspecified
Severity: minor Keywords:
Cc:

Description (last modified by Kurt Schwehr)

Unless some compiler strangeness crops up, I'm going to try to convert all of the uses of the ABS macro in C++ to std::abs.

std::abs should help with possible better type checking and possibly better optimization compared to the existing macro. Worst case, there should be no difference. We do need to keep an eye out for issues with NaN and Inf behavior changes.

#ifndef ABS
#  define ABS(x)        ((x<0) ? (-1*(x)) : x)
#endif
Error: Failed to load processor bash
No macro or processor named 'bash' found

e.g. r35943

The one quirk is that the float/double ones are in <cmath> and the integral type ones are in <cstdlib>

http://en.cppreference.com/w/cpp/numeric/math/fabs

Change History (6)

comment:1 by Kurt Schwehr, 8 years ago

Description: modified (diff)
Owner: changed from warmerdam to Kurt Schwehr
Status: newassigned

comment:2 by Even Rouault, 8 years ago

In r35947: Fix compilation with ancient mingw32 (refs #6700)

comment:3 by Kurt Schwehr, 8 years ago

A lot of the uses of ABS are related to doing float/double almost equal. We need a proper templated CPLAlmostEqual(T v1, T v2, delta=1e-9) for C++. Same goes for float comparisons in autotest python code to match what self.assertAlmostEqual does in unittest.

This isn't great for C++. The delta is fixed and it always uses fabs. std::abs in <cmath> will do match the float or double type.

// From cpl_port.h
/* -------------------------------------------------------------------- */
/*      Macro to test equality of two floating point values.            */
/*      We use fabs() function instead of ABS() macro to avoid side     */
/*      effects.                                                        */
/* -------------------------------------------------------------------- */
/*! @cond Doxygen_Suppress */
#ifndef CPLIsEqual
#  define CPLIsEqual(x,y) (fabs((x) - (y)) < 0.0000000000001)
#endif

Something like this is possibly borked in some cases.

#ifdef __cplusplus
#include <cmath>
#include <cstdlib>
template<typename T> inline bool CPLAlmostEqual( T x, T y, T delta )
{
    if (is_nan(x) || is_nan(y)) return false;
    return std::abs(x - y) < delta;
}
#endif

We'd want to look carefully at

https://github.com/google/googletest/blob/master/googletest/include/gtest/internal/gtest-internal.h#L358

  // Returns true iff this number is at most kMaxUlps ULP's away from
  // rhs.  In particular, this function:
  //
  //   - returns false if either number is (or both are) NAN.
  //   - treats really large numbers as almost equal to infinity.
  //   - thinks +0.0 and -0.0 are 0 DLP's apart.
  bool AlmostEquals(const FloatingPoint& rhs) const {
    // The IEEE standard says that any comparison operation involving
    // a NAN must return false.
    if (is_nan() || rhs.is_nan()) return false;

    return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
        <= kMaxUlps;
  }

and http://stackoverflow.com/questions/17333/most-effective-way-for-float-and-double-comparison

comment:4 by Kurt Schwehr, 8 years ago

Resolution: fixed
Status: assignedclosed

Most of the ABS have been converted: r35955 r35954 r35953 r35952 r35951 r35946.

Closing for now. I'm not going to worry about the almost equals right now.

comment:5 by Kurt Schwehr, 8 years ago

A few more patches to get all platforms happy.

r35960 r35956 It seems that starting with a 16-bit integer has issues on some platforms where it gets up converted to a float even if <cstdlib> is included. Casting to an int first causes the compiler to do the correct thing.

comment:6 by Kurt Schwehr, 8 years ago

#6704 for std::min and std::max

Note: See TracTickets for help on using tickets.