在的std :: ABS功能(On the std::abs function)

2019-08-02 23:28发布

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| 所有的算术类型?

编辑:这里有一个例子程序做一些测试

#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;
}

Answer 1:

正确的过载值被保证是存在于<cmath> / <cstdlib>

C ++ 11,[c.math]:

除了int的某些数学函数在版本<cstdlib> ,C ++增加longlong long的这些功能重载版本,具有相同的语义。

添加的签名是:

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

[...]

除了double的数学函数中的版本<cmath>重载的这些功能的版本中,用相同的语义。 C ++增加了floatlong double这些函数重载版本,具有相同的语义。

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

所以,你应该确保正确包括<cstdlib> intlonglong long的重载)/ <cmath> doublefloatlong double过载)。



Answer 2:

你不能保证std::abs(x)将始终返回|x| 所有的算术类型。 例如,大多数带符号整数的实现有余地比正数多一个负数,所以结果abs(numeric_limits<int>::min())将不等于|x|



Answer 3:

请检查您实际上是使用std::abs<cstdlib>而不是std::abs<cmath>

PS。 哦,刚才看到的例子程序,好了,你去那里,你正在使用的浮点重载之一std::abs



Answer 4:

这是不奇怪,当您使用克++(以C ++ 11标准)返回一个双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); }


文章来源: On the std::abs function