繁体   English   中英

在std :: abs函数上

[英]On the std::abs function

是否为C ++ 11中的所有算术类型定义了std::abs()函数,并返回|x| 没有近似问题?

奇怪的是,使用g ++ 4.7, std::abs(char)std::abs(short int)std::abs(int)std::abs(long int)std::abs(long long int)似乎返回一个double(相反于: http//en.cppreference.com/w/cpp/numeric/math/abs )。 如果数字被转换为double,我们可能会对非常大的数字有一些近似误差(例如-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;
}

<cmath> / <cstdlib>中保证正确的重载:

C ++ 11,[c.math]:

除了<cstdlib>中某些数学函数的int版本之外,C ++还添加了这些函数的longlong long重载版本,具有相同的语义。

添加的签名是:

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

[...]

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

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

所以你应该确保正确包含<cstdlib>intlonglong long overloads)/ <cmath>doublefloatlong double overload)。

您不能保证std::abs(x)将始终返回|x| 适用于所有算术类型。 例如,大多数有符号整数实现的空间比正数多一个,所以abs(numeric_limits<int>::min())不等于|x|

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

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

当您使用带有整数类型的<cmath> std::abs时,g ++(使用C ++ 11标准)返回double并不奇怪:来自http://www.cplusplus.com/reference/cmath/abs/

从C ++ 11开始,此标题( <cmath> )中为整数类型提供了额外的重载:这些重载在计算之前有效地将x转换为double(定义为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); }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM