## 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.

## Issues with `std::abs`

`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 `<stdint.h>`

has `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 `#ifdef`

s 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

The integral `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, `INT8_MIN`

is `-128`

, `INT8_MAX`

is `+127`

, and `+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 `mozilla::Abs`

, not `std::abs`

Unfortunately the only solution is to implement our own absolute-value function. `mozilla::Abs`

in `"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.

As a brief footnote, people wondering why all the standard integral

`abs`

functions return the signed type may find this Stack Overflow question informative.Comment by Jeff — 30.04.13 @ 11:17

If only you could write

(I hope this works, given that there’s no preview…)

(Side note: why do you need const T t when T is a primitive type?)

Comment by Neil Rashbrook — 01.05.13 @ 04:36

It’s possible to write a

`template<typename T> MakeUnsigned`

containing a member`typedef`

that does that. C++11`<type_traits>`

has`std::make_unsigned`

that does exactly this, and nothing in it requires C++11. I imagine we’ll pick it up at some point, too, in`mozilla/TypeTraits.h`

.There’s no particular reason to use

`const T t`

except (perhaps) extra clarity about the parameter not being modified.Comment by Jeff — 01.05.13 @ 10:29