21

std::abs()関数はC++11のすべての算術型に対して明確に定義されており、近似の問題なく返され|x|ますか?

奇妙なことは、g ++ 4.7 、、、、でstd::abs(char)std::abs(short int)doubleを返すように見えることです(逆に:std::abs(int)http ://en.cppreference.com/w/cpp/numeric/math/abs)。また、数値がdoubleにキャストされると、非常に大きな数値(のように)に対して近似誤差が発生する可能性があります。std::abs(long int)std::abs(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;
}
4

4 に答える 4

16

正しいオーバーロードが<cmath>/に存在することが保証されています<cstdlib>

C ++ 11、[c.math]:

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);

したがって、正しく<cstdlib>int、、オーバーロード)/ (、、オーバーロード)を含めるようにしてください。longlong long<cmath>doublefloatlong double

于 2012-11-19T19:41:04.830 に答える
5

すべての算術タイプでstd::abs(x)常に返されることを保証することはできません。|x|たとえば、ほとんどの符号付き整数の実装には、正の数よりも負の数が1つ多い余地があるため、の結果はabs(numeric_limits<int>::min())に等しくなりません|x|

于 2012-11-19T19:40:47.287 に答える
1

fromではなくstd::absfromを実際に使用していることを確認してください。<cstdlib>std::abs<cmath>

PS。ああ、ちょうどサンプルプログラムを見ました、まあ、あなたは行き​​ます、あなたはの浮動小数点オーバーロードの1つを使用していますstd::abs

于 2012-11-19T19:36:21.013 に答える
0

整数型でstd::absfromを使用すると、g ++(C ++ 11標準)がdoubleを返すのは奇妙なことではありません。Fromhttp : //www.cplusplus.com/reference/cmath/abs/<cmath>

C ++ 11以降、このヘッダー(<cmath>)には、整数型の追加のオーバーロードが提供されています。これらのオーバーロードは、計算前にxをdoubleに効果的にキャストします(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); }
于 2015-03-20T13:09:39.460 に答える