C++ 关于std::abs函数

C++ 关于std::abs函数,c++,c++11,standards-compliance,absolute-value,C++,C++11,Standards Compliance,Absolute Value,对于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-long int)似乎返回一个双精度(与:)相反。如果这个数被转换成一个双精度数,我们可能会有一些非常大的近似误差(比如-9223372036854775806LL=2^63-3) 那么,我是

对于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-long int)
似乎返回一个双精度(与:)相反。如果这个数被转换成一个双精度数,我们可能会有一些非常大的近似误差(比如
-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;
}
#包括
#包括
#包括
#包括
模板
真空度测试(T x)
{
静态常量无符号整数宽度=16;
常数T val=x;
if(sizeof(val)==1){

std::cout检查您是否确实在使用
中的
std::abs
,而不是
中的
std::abs

哦,刚才看到了示例程序,好了,你正在使用
std::abs的一个浮点重载

.

对于所有算术类型,您不能保证
std::abs(x)
始终返回
|x |
。例如,大多数有符号整数实现都有比正数多一个负数的空间,因此
abs(numeric_limits::min()的结果)
不等于
|x |

保证在
/
中存在正确的重载:

C++11,[C.math]:

<> >除<代码> int >代码> <代码> <代码>中的某些数学函数的版本外,C++还添加了<代码>长< /COD>和长Lo/<代码>这些函数的重载版本,具有相同的语义。
float abs(float);
long double abs(long double);
新增的签名为:

long abs(long);            // labs()
long long abs(long long);  // llabs()
[……]

除了
中数学函数的
双版本之外,这些函数的重载版本具有相同的语义。
C++添加了<代码>浮点< /COD>和长双双这些函数的重载版本,具有相同的语义。

float abs(float);
long double abs(long double);
因此,您应该确保正确地包含
int
long
long
重载)/
double
float
long double
重载)。

g++(使用C++11标准)并不奇怪如果将
中的
std::abs
与整数类型一起使用,则返回一个双精度: 发件人:

自C++11以来,此标头(
)中为整数类型提供了额外的重载:这些重载在计算之前有效地将x转换为双精度(定义为T为任何整数类型)

这实际上是像
/usr/include/c++/cmath
中那样实现的:

模板
内联_GLIBCXX_CONSTEXPR
typename\uuu gnu\u cxx::\uu启用\u如果::\uu类型
防抱死制动系统
{return uuu内置晶圆厂(uuux)}

是什么让您认为g++实现返回了一个双精度?也许您可以提供一个示例,说明您正在执行的操作指示返回了一个双精度?请注意,在不同的头中有几个
std::abs
,如
。当然
std::abs(x)
返回
|x |
。也许你想知道
decltype(std::abs(x))
是否匹配
decltype(x)
?我只是对你所说的“std::abs(x)是否总是返回| x |?”的确切含义有点困惑我不知道C++标准是什么意思,但是这样的保证是不可能的,因为每当代码“int /Cuth>”是一个“两个补符号整数”时,最小可能的<代码> int <代码>的绝对值不能表示为<代码> int <代码>。(例如,如果我们有32位整数,则最小可能值为-2147483648,但最大可能值仅为2147483647。)我不知道您的GCC4.7,但我的GCC4.7调用了
\uu gnu cxx::abs
,它是
\uux>=0?\uuuux:-\uuuux;
第26.8.7-9节的内联包装器,以防有人关心。为什么重载是分开的?为什么不将所有重载放在一个头文件中?它们遵循相应C函数的位置(
abs
fabs
),我不确定这是否是个好主意,因为我不止一次没有导入
,因此在FP值上使用integer-abs。这似乎是唯一一种情况,对
NaN
来说是安全的。这是OP命中的情况,因为他将double-10000000000转换为其他类型,将值截断到许多ca中的最小限制塞斯。