C++ 关于std::abs函数
对于C++11中的所有算术类型,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) 那么,我是
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中的最小限制塞斯。