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 float
s, double
s, and long double
s, 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 instd::
. Practically, onlyexport
was less respected, and different compilers did very
different things. If you included<cmath>
, you usedstd::
everywhere, or what you got varied from compiler to compiler.C didn't provide any overloads:
abs
took anint
, and was
declared in<stdlib.h>
,fabs
tookdouble
, 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 toabs
, but only
tofabs
.) 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
Recursive Lambda Functions in C++14
Converting Between C++ Std::Vector and C Array Without Copying
Safely Override C++ Virtual Functions
C++ How to Allocate Memory Dynamically on Stack
How to Use Sendinput Function C++
Dead Code Identification (C++)
How to Enumerate/List All Installed Applications in Windows Xp
What Use Are Const Pointers (As Opposed to Pointers to Const Objects)
Exception Running Boost Asio Ssl Example
How to Convert Rgb -> Yuv -> Rgb (Both Ways)
Why Can't I Inherit from Int in C++
Debug and Release Library Linking with Cmake (Visual Studio)
Friend Declaration Declares a Non-Template Function
How to Forward Declare a Template Class in Namespace Std
Under What Circumstances Are C++ Destructors Not Going to Be Called