在 std::abs 函数上
On the std::abs function
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;
}
正确的重载保证存在于 <cmath>
/<cstdlib>
中:
C++11, [c.math]:
除了
<cstdlib>
中某些数学函数的int
版本外,C++还添加了这些函数的long
和long long
重载版本,具有相同的语义。添加的签名包括:
long abs(long); // labs() long long abs(long long); // llabs()
[...]
除了
<cmath>
中数学函数的double
版本外,这些函数的重载版本具有相同的语义。 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|
。
检查您实际上使用的是来自<cstdlib>
的std::abs
,而不是来自<cmath>
std::abs
。
哦,刚刚看到了示例程序,好吧,你去吧,你正在使用std::abs
的浮点重载之一.
当您使用整型的 std::abs
from <cmath>
时,g++(使用 C++11 标准)返回双精度值并不奇怪:从 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); }
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- cpp 使用 abs() 函数和 size_t
- 如何减少 abs 函数的数量
- 无法在 abs 函数 c++ 中使用字符串长度函数
- 标准库函数 abs() 在不同C++编译器上的异常行为
- ABS 函数在 C++ 中没有给出正确的答案
- 在 std::abs 函数上
- 获取绝对值,而不使用 ABS 函数或 if 语句
- iostream为什么定义abs函数,以及如何停止它