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;
}
You cannot guarantee that
std::abs(x)
will always return|x|
for all arithmetic types. For example, most signed integer implementations have room for one more negative number than positive number, so the results ofabs(numeric_limits<int>::min())
will not equal|x|
.It's not weird that g++ (with C++11 standard) returns a double when you use
std::abs
from<cmath>
with an integral type: From http://www.cplusplus.com/reference/cmath/abs/:This is actually implemented like that in
/usr/include/c++/cmath
:The correct overloads are guaranteed to be present in
<cmath>
/<cstdlib>
:C++11, [c.math]:
So you should just make sure to include correctly
<cstdlib>
(int
,long
,long long
overloads)/<cmath>
(double
,float
,long double
overloads).Check that you're in fact using
std::abs
from<cstdlib>
and notstd::abs
from<cmath>
.PS. Oh, just saw the example program, well, there you go, you are using one of the floating point overloads of
std::abs
.