C++ 在 std::abs 函数上
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13460750/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
On the std::abs function
提问by Vincent
Is the std::abs()
function well defined for ALL arithmetic types in C++11 and will return |x|
with no problem of approximation?
该std::abs()
函数是否为 C++11 中的所有算术类型定义良好,并且返回|x|
时不会出现近似问题?
A weird thing is that with g++4.7, std::abs(char)
, std::abs(short int)
, std::abs(int)
, std::abs(long int)
and std::abs(long long int)
seem to return a double (on the contrary of : http://en.cppreference.com/w/cpp/numeric/math/abs). And if the number is casted to a double, we could have some approximation error for very large number (like -9223372036854775806LL = 2^63-3
).
一个奇怪的事情是,使用 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
)产生一些近似误差。
So do I have the guarantee that std::abs(x)
will always return |x|
for all arithmetic types ?
那么我是否有保证std::abs(x)
将始终返回|x|
所有算术类型?
EDIT : here is an example program to make some tests
编辑:这是一个进行一些测试的示例程序
#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;
}
采纳答案by Matteo Italia
The correct overloads are guaranteed to be present in <cmath>
/<cstdlib>
:
保证正确的重载存在于<cmath>
/ 中<cstdlib>
:
C++11, [c.math]:
C++11, [c.math]:
In addition to the
int
versions of certain math functions in<cstdlib>
, C++ addslong
andlong long
overloaded versions of these functions, with the same semantics.The added signatures are:
long abs(long); // labs() long long abs(long long); // llabs()
[...]
In addition to the
double
versions of the math functions in<cmath>
, overloaded versions of these functions, with the same semantics. C++ addsfloat
andlong double
overloaded versions of these functions, with the same semantics.float abs(float); long double abs(long double);
除了
int
中某些数学函数的版本之外<cstdlib>
,C++ 还添加long
和long long
重载了这些函数的版本,具有相同的语义。添加的签名是:
long abs(long); // labs() long long abs(long long); // llabs()
[...]
除了 中
double
数学函数的<cmath>
版本之外,这些函数的重载版本具有相同的语义。C++ 添加float
和long double
重载这些函数的版本,具有相同的语义。float abs(float); long double abs(long double);
So you should just make sure to include correctly <cstdlib>
(int
, long
, long long
overloads)/<cmath>
(double
, float
, long double
overloads).
因此,您应该确保正确包含<cstdlib>
( int
, long
,long long
重载)/ <cmath>
( double
, float
,long double
重载)。
回答by Robert Cooper
You cannot guarantee that std::abs(x)
will always return |x|
for all arithmetic types. For example, most signed integer implementations have room for one more negative number than positive number, so the results of abs(numeric_limits<int>::min())
will not equal |x|
.
您不能保证对于所有算术类型std::abs(x)
总是返回|x|
。例如,大多数有符号整数实现的负数比正数多一个,因此 的结果abs(numeric_limits<int>::min())
将不等于|x|
。
回答by chill
Check that you're in fact using std::abs
from <cstdlib>
and not std::abs
from <cmath>
.
检查您实际上使用的是std::abs
from<cstdlib>
而不是std::abs
from <cmath>
。
PS. Oh, just saw the example program, well, there you go, you are using one of the floating point overloads of std::abs
.
附注。哦,刚刚看到示例程序,好吧,你去了,你正在使用std::abs
.
回答by user1448926
It's not weird that g++ (with C++11 standard) returns a double when you use std::abs
from <cmath>
with an integral type:
From http://www.cplusplus.com/reference/cmath/abs/:
当您将std::abs
from<cmath>
与整数类型一起使用时,g++(使用 C++11 标准)返回双精度值并不奇怪:来自http://www.cplusplus.com/reference/cmath/abs/:
Since C++11, additional overloads are provided in this header (
<cmath>
) for the integral types: These overloads effectively cast x to a double before calculations (defined for T being any integral type).
自 C++11 起,在此标头 (
<cmath>
) 中为整数类型提供了额外的重载:这些重载在计算之前有效地将 x 强制转换为 double(为 T 定义为任何整数类型)。
This is actually implemented like that in /usr/include/c++/cmath
:
这实际上是这样实现的/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); }