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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:21:10  来源:igfitidea点击:

On the std::abs function

c++c++11standards-complianceabsolute-value

提问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 intversions of certain math functions in <cstdlib>, C++ adds longand long longoverloaded 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 doubleversions of the math functions in <cmath>, overloaded versions of these functions, with the same semantics. C++ adds floatand long doubleoverloaded versions of these functions, with the same semantics.

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

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

添加的签名是:

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

[...]

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

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

So you should just make sure to include correctly <cstdlib>(int, long, long longoverloads)/<cmath>(double, float, long doubleoverloads).

因此,您应该确保正确包含<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::absfrom <cstdlib>and not std::absfrom <cmath>.

检查您实际上使用的是std::absfrom<cstdlib>而不是std::absfrom <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::absfrom <cmath>with an integral type: From http://www.cplusplus.com/reference/cmath/abs/:

当您将std::absfrom<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); }