Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

On the std::abs function

Tags:

Is the std::abs() function well defined for ALL arithmetic types in C++11 and will return |x| with no problem of approximation?

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

So do I have the guarantee that std::abs(x) will always return |x| for all arithmetic types ?

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;
}
like image 301
Vincent Avatar asked Nov 19 '12 19:11

Vincent


People also ask

What does std :: abs do?

std::abs(float), std::fabs, std::fabsf, std::fabsl. 1-8) Computes the absolute value of a floating point value arg .

How do you take the absolute value of a vector in C++?

valarray abs() function in C++ The abs() function is defined in valarray header file. This function is used to calculate the absolute value of each element in the valarray and returns a valarray containing the absolute values of all the elements. Syntax: abs(varr);

Does abs work on float?

If the value entered cannot be represented as an integer, the abs(), absf(), and absl() functions return the same value. Note: These functions work in both IEEE Binary Floating-Point and hexadecimal floating-point formats.

How do you take the absolute value of a double in C++?

Syntax: double fabs(double a); float fabs(float a); int fabs(int a); Parameter: The fabs() function takes a single argument, a whose absolute value has to be returned.


2 Answers

The correct overloads are guaranteed to be present in <cmath>/<cstdlib>:

C++11, [c.math]:

In addition to the int versions of certain math functions in <cstdlib>, C++ adds long and long 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++ adds float and long double overloaded versions of these functions, with the same semantics.

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

like image 172
Matteo Italia Avatar answered Oct 22 '22 19:10

Matteo Italia


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|.

like image 33
Robert Cooper Avatar answered Oct 22 '22 20:10

Robert Cooper