Computing absolute values in C/C++
C includes various functions for computing the absolute value of a signed number. C++98 implementations add the C functions to
namespace std, and it adds
abs() overloads to
namespace std so
std::abs works on everything. For a long time Mozilla used
NS_ABS to compute absolute value, but recently we switched to
std::abs. This works on many systems, but it has a few issues.
std::abs is split across two headers
With some compilers, the integral overloads are in
<cstdlib> and the floating point overloads are in
<cmath>. This led to confusion when
std::abs compiled on one type but not on another, in the same file. (Or worse, when it worked with just one
#include because of that developer’s compiler.) The solution was to include both headers even if only one was needed. This is pretty obscure.
std::abs(int64_t) doesn’t work everywhere
On many systems
typedef long long int64_t;. But
long long was only added in C99 and C++11, and some compilers don’t have
long long std::abs(long long), so
int64_t i = 0; std::abs(i); won’t compile. We “solved” this with compiler-specific
#ifdefs around custom
std::abs specializations in a somewhat-central header. (That’s three headers to include!) C++ says this has undefined behavior, and indeed it’ll break as we update compilers.
std::abs(int32_t(INT32_MIN)) doesn’t work
abs overloads don’t work on the most-negative value of each signed integer type. On twos-complement machines (nearly everything), the absolute value of the smallest integer of a signed type won’t fit in that type. (For example,
+128 won’t fit in
int8_t.) The integral
abs functions take and return signed types. If the smallest integer flows through, behavior is undefined: as absolute-value is usually implemented, the value is returned unchanged. This has caused Mozilla bugs.
Mozilla code should use
Unfortunately the only solution is to implement our own absolute-value function.
"mozilla/MathAlgorithms.h" is overloaded for all signed integral types and the floating point types, and the integral overloads return the unsigned type. Thus you should use
mozilla::Abs to compute absolute values. Be careful about signedness: don’t assign directly into a signed type! That loses
mozilla::Abs‘s ability to accept all inputs and will cause bugs. Ideally this would be a compiler warning, but we don’t use
-Wconversion or Microsoft equivalents and so can’t do better.