On the std::abs function

absolute-value, c++, c++11, standards-compliance

Solution

The correct overloads are guaranteed to be present in `<cmath>`/`<cstdlib>`:

C++11, [c.math]:

In addition to the `int` versions of certain math functions in `<cstdlib>`, C++ adds `long` and `long long` overloaded versions of these functions, with the same semantics.

The added signatures are:

long abs(long);            // labs()
long long abs(long long);  // llabs()

[...]

In addition to the `double` versions of the math functions in `<cmath>`, overloaded versions of these functions, with the same semantics. C++ adds `float` and `long double` overloaded versions of these functions, with the same semantics.

float abs(float);
long double abs(long double);

So you should just make sure to include correctly `<cstdlib>` (`int`, `long`, `long long` overloads)/`<cmath>` (`double`, `float`, `long double` overloads).

Problem

Is the `std::abs()` function well defined for ALL arithmetic types in C++11 and will return `|x|` with no problem of approximation? A weird thing is that with g++4.7, `std::abs(char)`, `std::abs(short int)`, `std::abs(int)`, `std::abs(long int)` and `std::abs(long long int)` seem to return a double (on the contrary of : http://en.cppreference.com/w/cpp/numeric/math/abs). And if the number is casted to a double, we could have some approximation error for very large number (like `-9223372036854775806LL = 2^63-3`). So do I have the guarantee that `std::abs(x)` will always return `|x|` for all arithmetic types ? EDIT : here is an example program to make some tests ``` #include <iostream> #include <iomanip> #include <cmath> #include <typeinfo> template<typename T> void abstest(T x) { static const unsigned int width = 16; const T val = x; if (sizeof(val) == 1) { std::cout<<std::setw(width)<<static_cast<int>(val)<<" "; std::cout<<std::setw(width)<<static_cast<int>(std::abs(val))<<" "; } else { std::cout<<std::setw(width)<<val<<" "; std::cout<<std::setw(width)<<static_cast<T>(std::abs(val))<<" "; } std::cout<<std::setw(width)<<sizeof(val)<<" "; std::cout<<std::setw(width)<<sizeof(std::abs(val))<<" "; std::cout<<std::setw(width)<<typeid(val).name()<<" "; std::cout<<std::setw(width)<<typeid(std::abs(val)).name()<<std::endl; } int main() { double ref = -100000000000; abstest<char>(ref); abstest<short int>(ref); abstest<int>(ref); abstest<long int>(ref); abstest<long long int>(ref); abstest<signed char>(ref); abstest<signed short int>(ref); abstest<signed int>(ref); abstest<signed long int>(ref); abstest<signed long long int>(ref); abstest<unsigned char>(ref); abstest<unsigned short int>(ref); abstest<unsigned int>(ref); abstest<unsigned long int>(ref); abstest<unsigned long long int>(ref); abstest<float>(ref); abstest<double>(ref); abstest<long double>(ref); return 0; } ```

Original source

Related problems