When Do I Use Fabs and When Is It Sufficient to Use Std::Abs

When do I use fabs and when is it sufficient to use std::abs?

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.

Is there any difference between std::abs and std::fabs when applied to floating point values?

In standard-conforming code that has included cmath and only calls std::abs on floats, doubles, and long doubles, there is no difference. However, it is instructive to look at the types returned by std::abs on various types when you call it with various sets of header files included.

On my system, std::abs(-42) is a double if I've included cmath but not cstdlib, an int if I've included cstdlib, and it produces a compilation error if I've included neither. Conversely, std::abs(-42.0) produces a compilation error (ambiguous overload) if I've included cstdlib but I haven't included cmath or a different compilation error (never heard of std::abs) if I've included neither.

On my platform, std::abs('x') gives me a double if I've included cmath or an int if I've included cstdlib but not cmath. Similar for a short int. Signedness does not appear to matter.

On my platform, the complex header apparently causes both the integral and the floating-point overloads of std::abs to be declared. I'm not certain this is mandated; perhaps you can find an otherwise reasonable platform on which std::abs(1e222) returns infinity with the wrong set of standard headers included.


The usual consequence of "you forgot a header in your program" is a compilation failure complaining of an undefined symbol, not a silent change in behaviour. With std::abs, however, the result can be std::abs(42) returning a double if you forgot cstdlib or std::abs('x') returning an int if you didn't. (Or perhaps you expected std::abs to give you an integral type when you pass it a short? Then, assuming my compiler got its promotion and overload resolution right, you had better make sure you don't include cmath.)

I have also spent too much time in the past trying to work out why code like double precise_sine = std::sin(myfloat) gives imprecise results. Because I don't like wasting my time on these sorts of surprises, I tend to avoid the overloaded variants of standard C functions in namespace std. That is, I use ::fabs when I want a double to be returned, ::fabsf when I want a float out, and ::fabsl when I want a long double out. Similarly for ::abs when I want an int, ::absl when I want a long, and ::absll when I want a long long.

Why use abs() or fabs() instead of conditional negation?

The "conditional abs" you propose is not equivalent to std::abs (or fabs) for floating point numbers, see e.g.

#include <iostream>
#include <cmath>

int main () {
double d = -0.0;
double a = d < 0 ? -d : d;
std::cout << d << ' ' << a << ' ' << std::abs(d);
}

output:

-0 -0 0

Given -0.0 and 0.0 represent the same real number '0', this difference may or may not matter, depending on how the result is used. However, the abs function as specified by IEEE754 mandates the signbit of the result to be 0, which would forbid the result -0.0. I personally think anything used to calculate some "absolute value" should match this behavior.

For integers, both variants will be equivalent both in runtime and behavior. (Live example)

But as std::abs (or the fitting C equivalents) are known to be correct and easier to read, you should just always prefer those.

abs() vs fabs() speed difference and advantage of fabs()

From an email response from Tim Peters:

Why does math have an fabs function? Both it and the abs builtin function
wind up calling fabs() for floats. abs() is faster to boot.


Nothing deep -- the math module supplies everything in C89's standard
libm (+ a few extensions), fabs() is a std C89 libm function.

There isn't a clear (to me) reason why one would be faster than the
other; sounds accidental; math.fabs() could certainly be made faster
(as currently implemented (via math_1), it endures a pile of
general-purpose "try to guess whether libm should have set errno"
boilerplate that's wasted (there are no domain or range errors
possible for fabs())).

It seems there is no advantageous reason to use fabs. Just use abs for virtually all purposes.

abs vs std::abs, what does the reference say?

The official references say... it's a mess. Pre-C++11 and C11:

  • Officially, including <cmath> introduced nothing in ::;
    all of the functions were in std::. Practically, only
    export was less respected, and different compilers did very
    different things. If you included <cmath>, you used std::
    everywhere, or what you got varied from compiler to compiler.

  • C didn't provide any overloads: abs took an int, and was
    declared in <stdlib.h>, fabs took double, and was
    declared in <math.h>.

  • If you included <math.h> in C++, it's not clear what you
    got, but since none of the implementers seemed to care about
    the standard anyway (see the first point above)...

Roughly speaking, either you included <cmath>, and prefixed
all of the uses with std::, or you included <math.h>, and
used fabs if you wanted support for floating point (and the
various suffixes for types other than int or double).

C++11 and C11 added a few new twists:

  • <cmath> is now allowed (but not required) to introduce the
    symbols in :: as well. One more thing which can vary
    depending on the implementation. (The goal here was to make
    existing implementations conformant.)

  • C has a new header, <tgmath.h>, which uses compiler magic to
    make the functions in <math.h> behave as if they were
    overloaded as in C++. (So it doesn't apply to abs, but only
    to fabs.) This header had not been added to C++, for the
    obvious reason that C++ doesn't need any compiler magic for
    this.

All in all, the situation has become slightly worse, and my
recommendations above still hold. Include either <math.h> and
<stdlib.h>, and use abs/fabs and their derivated (e.g.
labs, fabsf, etc.) exclusively, or include <cmath>, and
use std::abs exclusively. Anything else, and you'll run into
portabiity problems.

Abs and using namespace std

When you use

using namespace std;

you bring the following overloads of abs into scope:

std::abs(int)
std::abs(float)
std::abs(std::complex)

The call abs(f) resolves to std::abs(float).

If you don't use

using namespace std;

there is only one abs function that you are able to use.

abs(int)

Hence, the call abs(f) resolves to abs(int).

You can still remove the using namespace std; line and use std::abs(f) instead of just abs(f).



Related Topics



Leave a reply



Submit