42

I checked the difference between abs and fabs on python here

As I understand there are some difference regarding the speed and the passed types, but my question related to native c++ on V.S.

Regarding the V.S. I tried the following on Visual Studio 2013 (v120):

float f1= abs(-9.2); // f = 9.2
float f2= fabs(-9); // Compile error [*]

So fabs(-9) it will give me a compiler error, but when I tried to do the following:

double i = -9;
float f2= fabs(i); // This will work fine

What I understand from the first code that it will not compile because fabs(-9) need a double, and the compiler could not convert -9 to -9.0, but in the second code the compiler will convert i=-9 to i=-9.0 at compile time so fabs(i) will work fine.

Any better explanation?

Another thing, why the compiler can't accept fabs(-9) and convert the int value to double automatically like what we have in c#?

[*]:

Error: more than one instance of overloaded function "fabs" matches the argument list:
        function "fabs(double _X)"
        function "fabs(float _X)"
        function "fabs(long double _X)"
        argument types are: (int)   
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
Hazem Abdullah
  • 1,837
  • 4
  • 23
  • 41

3 Answers3

41

In C++, std::abs is overloaded for both signed integer and floating point types. std::fabs only deals with floating point types (pre C++11). Note that the std:: is important; the C function ::abs that is commonly available for legacy reasons will only handle int!

The problem with

float f2= fabs(-9);

is not that there is no conversion from int (the type of -9) to double, but that the compiler does not know which conversion to pick (int -> float, double, long double) since there is a std::fabs for each of those three. Your workaround explicitly tells the compiler to use the int -> double conversion, so the ambiguity goes away.

C++11 solves this by adding double fabs( Integral arg ); which will return the abs of any integer type converted to double. Apparently, this overload is also available in C++98 mode with libstdc++ and libc++.

In general, just use std::abs, it will do the right thing. (Interesting pitfall pointed out by @Shafik Yaghmour. Unsigned integer types do funny things in C++.)

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • 4
    *In general, just use std::abs, it will do the right thing.* ... see [Is std::abs(0u) ill-formed?](http://stackoverflow.com/q/29750946/1708801) – Shafik Yaghmour Nov 16 '15 at 15:20
  • @ShafikYaghmour Interesting, I never ran into that. It's amazing how much havoc unsigned integers cause in C++. The "correct" implementation that converts the unsigned integer to `double` is not what I would expect that code to do TBH. – Baum mit Augen Nov 16 '15 at 15:32
  • 1
    Don't get my wrong this is a good answer, I ran into this accidentally and it is good to be aware of especially since there is implementation variance and it is still open. – Shafik Yaghmour Nov 16 '15 at 15:35
  • @ShafikYaghmour Agreed, I added a remark to the answer, thanks. – Baum mit Augen Nov 16 '15 at 15:39
17

With C++ 11, using abs() alone is very dangerous:

#include <iostream>
#include <cmath>

int main() {
    std::cout << abs(-2.5) << std::endl;
    return 0;
}

This program outputs 2 as a result. (See it live)

Always use std::abs():

#include <iostream>
#include <cmath>

int main() {
    std::cout << std::abs(-2.5) << std::endl;
    return 0;
}

This program outputs 2.5.

You can avoid the unexpected result with using namespace std; but I would adwise against it, because it is considered bad practice in general, and because you have to search for the using directive to know if abs() means the int overload or the double overload.

alain
  • 11,939
  • 2
  • 31
  • 51
  • I've found the same problem. For me both abs() and std::abs() loses the decimal part. fabs() works though. Any idea why? – jmoraal Jul 10 '20 at 08:27
  • @jmoraal Sorry, no, I don't know about something that could cause this... Old compiler, maybe? You could post this as a question and include all details, like the code, and the compiler used. – alain Jul 10 '20 at 10:45
3

My Visual C++ 2008 didn't know which to choice from long double fabs(long double), float fabs(float), or double fabs(double).

In the statement double i = -9;, the compiler will know that -9 should be converted to double because the type of i is double.


abs() is declared in stdlib.h and it will deal with int value.

fabs() is declared in math.h and it will deal with double value.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70