104

I assume that abs and fabs are behaving different when using math.h. But when I use just cmath and std::abs, do I have to use std::fabs or fabs? Or isn't this defined?

Software Craftsman
  • 2,999
  • 2
  • 31
  • 47
math
  • 8,514
  • 10
  • 53
  • 61

4 Answers4

129

In C++, it's always sufficient to use std::abs; it's overloaded for all the numerical types.

In C, abs only works on integers, and you need fabs for floating point values. These are available in C++ (along with all of the C library), but there's no need to use them.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Is this on every platform the case? Esp. Windows and Mac OS X? Or is it at least in the C++ standard? – math Jun 25 '10 at 13:09
  • 3
    @brubelsabs: yes. There is no need for a separate fabs function in C++ since C++ has function overloading (abs can be defined for numerous types and it is in C++). It is also guaranteed by the standard. Of course if you dig around find some outdated compiler over 10 years old, you might find one that doesn't support it. – stinky472 Jun 25 '10 at 13:13
  • 1
    It's in the C++ Standard, so it's the case on every platform with a decent compiler, including Windows and Mac OS X. Clause 26.5 says that, in addition to the `int` version from the C library, there are overloads for `long`, `float`, `double` and `long double`. Clause 26.2.7 also defines an overload for `complex`. – Mike Seymour Jun 25 '10 at 13:18
  • 6
    If you forget the `std::` and just use `abs`, your code will work as expected on windows but will use the `int` version on linux, which can be incredibly hard to debug. – Adversus Nov 03 '15 at 08:52
  • "*all* the numerical types" [citation needed]. I can see int, long, long long, std::intmax_t, float, double, long double. No short or char versions (or unsigned versions) that I can see. – user673679 Mar 02 '20 at 17:41
25

It's still okay to use fabs for double and float arguments. I prefer this because it ensures that if I accidentally strip the std:: off the abs, that the behavior remains the same for floating point inputs.

I just spent 10 minutes debugging this very problem, due to my own mistake of using abs instead of std::abs. I assumed that the using namespace std;would infer std::abs but it did not, and instead was using the C version.

Anyway, I believe it's good to use fabs instead of abs for floating-point inputs as a way of documenting your intention clearly.

Alan Turing
  • 12,223
  • 16
  • 74
  • 116
  • 2
    That's weird. Your call should've been ambiguous (and thus an error) right? – Nick Jan 12 '13 at 15:57
  • Shouldn't you be using fabsf for float? So I don't think they are identical. – Nick Jan 26 '13 at 19:53
  • 1
    Beware of Android NDK g++, it also cedes to c abs() function instead of std::abs(). In Visual Studio c++ compiler however abs always points to std::abs() though. – Kurovsky Nov 05 '15 at 11:06
  • @Nick, I think I agree with you: I don't seem to get that behaviour of Alan Turing i.e. for me the overloaded `std::abs` always seems to be invoked (and not the C-version of `abs`) when calling `abs` as long as `using namespace std;` is explicated at the beginning. I don't know if this is compiler specific though. – MaviPranav Dec 26 '16 at 22:31
  • @Nick is not an error as there is a function name that matches. It is implementation defined which one will be chosen. – Pato Sandaña Aug 30 '19 at 13:38
13

There is one more reason to recommend std::fabs for floating-point inputs explicitly.

If you forget to include <cmath>, your std::abs(my_float_num) can be std::abs(int) instead of std::abs(float). It's hard to notice.

1

"abs" and "fabs" are only identical for C++ float types, when they can be translated without ambiguous overload messages.

I'm using g++ (g++-7). Together with template usage and especially when using mpreal there are cases with hard "ambiguous overload" messages - abs(static_cast<T>(x)) isn't always solving that. When abs is ambiguous, there are chances that fabs is working as expected. For sqrt I found no such simple escape.

Since weeks I'm hard struggling on C++ "not existing problems". I'm updating an old C++ program to C++14 for more and better template usage than possible before. Often the same template parameter may be actual any standard float or complex type or a class type. Why ever, long double acted somewhat more sensible than other types. All was working, and I had included mpreal before. Then I was setting my default float type to mpreal and got a deluge of syntax errors. That gave thousands of ambiguous overloads e.g. for abs and sqrt, crying for different solutions. Some were needing overloaded help functions, but outside of a template. Had to replace individually a thousand usages of 0.0L and 1.0L with the exact constant type using Zero or One or a type_cast - automatic conversion definition impossible because of ambiguities.

Up to May I found the existing of implicit conversions very nice. But much simpler it would be without any, and to have typesave constants with safe explicit type_casts to any other standard constant type.

BS3
  • 11
  • 3