На std:: функция abs
- это std::abs() функция хорошо определена для всех арифметических типов в C++11 и вернет |x| без проблем аппроксимации?
странно, что с g++4.7,std::abs(char), std::abs(short int), std::abs(int), std::abs(long int) и std::abs(long long int) кажется, возвращает двойной (напротив:http://en.cppreference.com/w/cpp/numeric/math/abs). И если число приведено к двойнику, у нас может быть некоторая ошибка аппроксимации для очень большого числа (например, -9223372036854775806LL = 2^63-3).
так что у меня есть гарантия, что std::abs(x) всегда будет возвращать |x| для всех арифметических типов ?
EDIT: вот пример программы, чтобы сделать некоторые тесты
#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;
}
4 ответов
правильные перегрузки гарантированно присутствуют в <cmath>/<cstdlib>:
в C++11, [С. математика]:
помимо
intверсии некоторых математических функций в<cstdlib>, C++ добавляетlongиlong longперегруженные версии этих функций, с той же семантикой.добавлены подписи:
long abs(long); // labs() long long abs(long long); // llabs()[...]
помимо
doubleверсии математических функций в<cmath>, перегруженные версии этих функций, с той же семантикой. C++ добавляетfloatиlong doubleперегруженные версии этих функций, с той же семантикой.float abs(float); long double abs(long double);
поэтому вы должны просто убедиться, что правильно включить <cstdlib> (int, long, long long перегрузки)/<cmath> (double, float, long double перегрузок).
вы не можете гарантировать, что std::abs(x) всегда будет возвращать |x| для всех арифметических типов. Например, большинство целочисленных реализаций со знаком имеют место для одного отрицательного числа больше положительного числа, поэтому результаты abs(numeric_limits<int>::min()) не равен |x|.
проверьте, что вы на самом деле используете std::abs с <cstdlib>, а не std::abs с <cmath>.
PS. О, просто увидел пример программы, ну вот, вы используете одну из перегрузок с плавающей запятой std::abs
.
не странно, что g++ (со стандартом C++11) возвращает double при использовании std::abs С <cmath> С составной тип:
От http://www.cplusplus.com/reference/cmath/abs/:
начиная с C++11 в этом заголовке (
<cmath>) для интегральных типов: эти перегрузки эффективно приводят x к двойному перед вычислениями (определено для T, являющегося любым интегральным типом).
Это на самом деле реализовано подобное в /usr/include/c++/cmath:
template<typename _Tp>
inline _GLIBCXX_CONSTEXPR
typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
abs(_Tp __x)
{ return __builtin_fabs(__x); }