Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

abs() returns a negative value for some very large double values

Tags:

c++

absolute

I was working with some big double values and all mathematical functions were fine. It seems that sqrt, pow and other math functions don't have any problems with big scientific double values, but abs can't handle these numbers. for example, this is ok:

double s = sqrt(3.9 * 1e32);

but this isn't:

double s = sqrt(abs(3.9 * 1e32));

because abs returns a negative value; I don't understand why this simple function can't handle scientific double operations when all those complex ones are working fine. Am I missing something or it's really this way and I can't use c++ abs function for such values?

MCVE

#include <cstdlib>
#include <cstdio>

int main()
{
    double d = 3.9e32;
    double f = abs(d);

    std::printf("%f\n", f);
}

Results

  • Coliru: 2147483647.000000
  • g++ 4.8.3-cygwin: -2147483648.000000

In this MCVE, changing abs to std::abs causes a compilation error due to overload resolution failure (can't choose between std::abs<int>, std::abs<long>, std::abs<long long>).

like image 337
MSH Avatar asked Dec 15 '22 19:12

MSH


2 Answers

The problem is you're using abs(int) when you need fabs(double) or better in C++, std::abs(). You said you tried std::abs(), but if you had it would have fixed your problem.

This is an unfortunate and common trap in C++. Never use abs() without std:: on the front. It's dangerous.

like image 118
John Zwinck Avatar answered May 05 '23 09:05

John Zwinck


The claim that abs return int in C++ mentioned in other answers is completely incorrect. In C++ standard library function abs is overloaded for different argument (and return) types. Header <stdlib.h> (or <cstdlib>) provides overloads for integral arguments. Header <math.h> (or <cmath>) provides overloads for floating-point arguments.

The question in this case is which header file the OP used in the program. If <math.h> was included, then abs should have called double abs(double) and generated a proper result (barring a broken compiler). If <stdlib.h> was included (and no <math.h>), then the call should have resulted in overload resolution failure due to availablity of both abs(int) and abs(long).

This applies in equal degree to both abs and std::abs. Which one you should use depends only on what header files you include: <stdlib.h>-<math.h> or <cstdlib>-<cmath> respectively. Note that using std::abs instead of abs does not have any effect on this problem at all: the set of overloaded functions is the same in both cases.

If in the OP's case the int version of abs was called, it would be a quirk of the implementation. There's actually a DR that deals with this issue

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2380

like image 39
AnT Avatar answered May 05 '23 07:05

AnT