Edited for test case and compiler inconsistency. Recently I made a change to use the more modern < cmath > instead of < math.h >. While this compiled just fine as expected with no warnings, this one-line change for one file caused my test cases to fail. From my understanding, cmath just puts most of the functions/variables in the std namespace, and I don't make any changes to that namespace.
I'll note I am using
sqrt
abs (since I am using doubles here I would assume the compiler would automatically use the cmath/math.h form, not stdlib)
tan
out of any files potentially affected by this one-line change on one file. I do have a different file that is already using cmath, but does not affect the testing.
A test case with
#include <iostream>
#include <cmath>
int main() {
double x = -0.546;
double y = abs( x / sqrt(x*x + 1.0));
double z = std::abs( x / sqrt(x*x + 1.0));
std::cout << "Variable value is " << x << std::endl;
std::cout << "Value of function using cmath " << z << std::endl;
std::cout << "Value of function using stdlib " << y << std::endl;
return 0;
}
gives output
Value is -0.546
Value of function using cmath 0.479221
Value of function using stdlib 0
on compiler (GCC) 8.3.1 20191121. Curiously, this is not the output on C++ shell, instead keeping the value of the function non-zero.
The C++ standard library has defined overloads for std::abs
that accept floating point types. These are declared in the std
namespace only, as to not pollute the global namespace. More info on cppreference.
The same is not true for abs
in the global namespace. Its origin is on stdlib.h
. Since stdlib.h
is a C library, and C does not support function overloads, the versions for floating point are defined instead as fabs
and fabsf
for double
and float
, respectively.
What you are actually doing when calling abs
(in the global namespace) with a floating point value is casting that value to an integer. Since the value is guaranteed to be smaller than 1
in your example, that means that you are essentially always passing 0
as the argument.
If you turn on warnings (specifically -Wconversion
), the compiler will warn you about this:
<source>: In function 'int main()':
<source>:6:23: warning: conversion from 'double' to 'int' may change value [-Wfloat-conversion]
double y = abs( x / sqrt(x*x + 1.0));
~~^~~~~~~~~~~~~~~~~
Curiously, this is a case where declaring using namespace std;
would "solve the problem". Since std::abs(double)
is a better overload, it would be chosen by overload resolution if the namespace std
is imported into the global namespace. Not that I'm advocating doing this - it will have several other side effects that you may not be aware about. So the best thing to do is to either use std::abs
explicitly, or only importing it specifically, and in a narrower scope (e.g.: placing using std::abs;
in your function's scope).