Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

cmath

Beware, I am talking about ::abs(), not std::abs()

According to the cplusplus.com website, abs is supposed to behave differently for the stdlib.h C version, if you include <cmath>

Here is an extract from the this page (which deals with ::abs, not std::abs):

double abs (double x);  float abs (float x);  long double abs (long double x); Compute absolute value /* Returns the absolute value of x: |x|. These convenience abs overloads are exclusive of C++. In C, abs is only declared in  <cstdlib> (and operates on int values).  The additional overloads are provided in this header (<cmath>) for the integral types:  These overloads effectively cast x to a double before calculations  (defined for T being any integral type). */ 

Really???

I have been bitten by this when porting a program to a new platform, since different compilers and standard libraries implementation differ here.

Here is my sample program:

#include <iostream> //#include <stdlib.h>//Necessary inclusion compil under linux //You can include either cmath or math.h, the result is the same //#include <cmath> #include <math.h> int main(int argc, const char * argv[]) {   double x = -1.5;   double ax = std::abs(x);   std::cout << "x=" << x << " ax=" << ax << std::endl;   return 0; } 

And here is the result under MSVC 2010:

  • No compilation warning is emitted under MSVC 2010, and the program will compile even if you do not include neither math.h nor stdlib.h: it seems like math.h and stdlib.h are always included whatever you do
  • The program output is: x=-1.5 ax=1.5 (seemingly correct according to the reference)

Now here is the result under OSX:

  • No compilation warning is emitted, even with the -Wall flag (the double to int cast is not signaled)! The result is the same if you replace g++ by llvm-g++. The inclusion of math.h or cmath is not required for the compilation.
  • The program output is: x=-1.5 ax=1

And finally the result under Linux:

  • The program will not compile if stdlib.h is not included (at last, one compiler that does not include stdlib automatically). No compilation warning is emitted for the double -> int cast.
  • The program output is: x=-1.5 ax=1

No clear winner here. I know that an obvious answer is "prefer std::abs to ::abs", but I wonder:

  • Is the cplusplus.com website right here when it says that abs should automatically provide double version outside of the std namespace?
  • Are all compiler and their standard libraries wrong here except MSVC (although it includes math.h silently)?
like image 525
Pascal T. Avatar asked Jan 27 '14 22:01

Pascal T.


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 .

What does abs mean in C++?

The abs() function in C++ returns the absolute value of an integer number. This function is defined in the cstdlib header file. Mathematically, abs(num) = |num| .

How to declare abs in C++?

The abs() function in C++ returns the absolute value of the argument. It is defined in the cmath header file. Mathematically, abs(num) = |num| .

What is the difference between abs () and fabs () functions?

Python | fabs() vs abs() Both will return the absolute value of a number. The difference is that math. fabs(number) will always return a floating-point number even if the argument is an integer, whereas abs() will return a floating-point or an integer depending upon the argument.


1 Answers

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.

like image 84
James Kanze Avatar answered Sep 21 '22 15:09

James Kanze