I checked the difference between abs and fabs on python here
As I understand there are some difference regarding the speed and the passed types, but my question related to native c++ on V.S.
Regarding the V.S.
I tried the following on Visual Studio 2013 (v120):
float f1= abs(-9.2); // f = 9.2
float f2= fabs(-9); // Compile error [*]
So fabs(-9) it will give me a compiler error, but when I tried to do the following:
double i = -9;
float f2= fabs(i); // This will work fine
What I understand from the first code that it will not compile because fabs(-9) need a double, and the compiler could not convert -9 to -9.0, but in the second code the compiler will convert i=-9 to i=-9.0 at compile time so fabs(i) will work fine.
Any better explanation?
Another thing, why the compiler can't accept fabs(-9) and convert the int value to double automatically like what we have in c#?
[*]:
Error: more than one instance of overloaded function "fabs" matches the argument list:
function "fabs(double _X)"
function "fabs(float _X)"
function "fabs(long double _X)"
argument types are: (int)
In C++, std::abs is overloaded for both signed integer and floating point types. std::fabs only deals with floating point types (pre C++11). Note that the std:: is important; the C function ::abs that is commonly available for legacy reasons will only handle int!
The problem with
float f2= fabs(-9);
is not that there is no conversion from int (the type of -9) to double, but that the compiler does not know which conversion to pick (int -> float, double, long double) since there is a std::fabs for each of those three. Your workaround explicitly tells the compiler to use the int -> double conversion, so the ambiguity goes away.
C++11 solves this by adding double fabs( Integral arg ); which will return the abs of any integer type converted to double. Apparently, this overload is also available in C++98 mode with libstdc++ and libc++.
In general, just use std::abs, it will do the right thing. (Interesting pitfall pointed out by #Shafik Yaghmour. Unsigned integer types do funny things in C++.)
With C++ 11, using abs() alone is very dangerous:
#include <iostream>
#include <cmath>
int main() {
std::cout << abs(-2.5) << std::endl;
return 0;
}
This program outputs 2 as a result. (See it live)
Always use std::abs():
#include <iostream>
#include <cmath>
int main() {
std::cout << std::abs(-2.5) << std::endl;
return 0;
}
This program outputs 2.5.
You can avoid the unexpected result with using namespace std; but I would adwise against it, because it is considered bad practice in general, and because you have to search for the using directive to know if abs() means the int overload or the double overload.
My Visual C++ 2008 didn't know which to choice from long double fabs(long double), float fabs(float), or double fabs(double).
In the statement double i = -9;, the compiler will know that -9 should be converted to double because the type of i is double.
abs() is declared in stdlib.h and it will deal with int value.
fabs() is declared in math.h and it will deal with double value.
Related
I want to use exponential function which returns IEEE_FLOAT64 value
Currently I am using expf function, but still I am getting lots of warnings.
value = IEEEPosOne - (IEEE_FLOAT64)expf(value1);
From man 3 exp:
NAME
exp, expf, expl - base-e exponential function
SYNOPSIS
#include <math.h>
double exp(double x);
float expf(float x);
long double expl(long double x);
Link with -lm.
So just use exp().
//c++
#include <cmath>
double x = 7.0;//float64
auto y = std::exp(x);//exp(float64);
C++ standard provides appropriate overloads. No need to reflect operand type in function name.
This does answer does not apply to C only for C++
For C see #iBug's answer.
The C++ standard does not require an implementation to use the IEEE standard. Though this is usually the easiest floating point implementation to use as the chips are relatively standard in modern machines.
The standard provides a way to check using std::numeric_limits.
So if it is a requirement then you should validate.
#include <limits>
#include <iostream>
int main()
{
static_assert(sizeof(double) == 64);
static_assert(std::numeric_limits<double>::is_iec559());
// If the above compiles your double is IEEE 64 bit value.
// Or IEEE_754 compliant https://en.wikipedia.org/wiki/IEEE_754_revision
}
Now that you have established you are using IEEE values you can look at the cmath header to see that the functions there all take and return a double value.
exp
log
etc....
Note: You should note that Windows machines (usually) use an 80 bit floating point register (not 64). So things can get super whaky if you need strict compliance.
Note: Do NOT use:
expf() for float,
expl() for long double
These are for C library users where the language does not do the correct type checking. In C++ the language uses overloading to use the correct version of the function. If you look at the standard for exp:
Defined in header <cmath>
* float exp( float arg );
* double exp( double arg );
* long double exp( long double arg );
* double exp( Integral arg );
The above are all in the standard namespace.
std::cout << std::exp(100000.1) << "\n";
Notice that exp() can take any floating point type float, double or long double and generate the appropriate result type.
I have made a simple code in C++
#include<math.h>
void main()
{
float a,x;
cout<<"Enter value of a"<<endl;
cin>>a;
x = pow(a,0.5);
cout<<x;
}
But it's giving me error:
When I press F12 and go to definition of pow(), these 6 overloads are found:
As we can see, it clearly has one overload for (double, double) and one for (float, float), so why does it give error when I declare a as float and works perfectly when I change its data-type to double?
The issue here is that the literal 0.5 is a double, so you are calling pow with a set of arguments that do not unambiguously match an overload, and for which type conversions cannot be applied to unambiguously match an existing overload. You should use the float literal 0.5f instead.
x = pow(a, 0.5f);
Also note that you need to #include <iostream> for cout, cin and endl, and you have to either refer to them by their full names (std::cout, std::cin, std::endl), or use using declarations
using std::cout;
using std::cin;
using std::endl;
Finally, void main() is not one of the valid signatures for the main function. It must return int, so
int main()
or
auto main()->int
You're calling it with a float and a double. There isn't an overload for that combination, and several that are close enough to be ambiguous.
0.5f would have type float, if you want to use the overload with two float parameters.
Your call doesn't exactly match any of the various definitions of pow, so the compiler is trying to see if it can automatically cast some of your arguments so it will exactly match, but here there are 6 possible definitions of pow that could match. You need to tell the compiler exactly which one you want.
What you tried to call is pow(float, double), because 0.5 is a double literal (not a float!).
If you do for example pow(a, 0.5f) then both arguments are float and it will compile. Of course you could also pick any of the other 5 overloads.
You need to explicitly call an overloaded function of pow()
x = pow(a, 0.5f);
or
double y = pow(static_cast<double>(a), 0.5);
This code compiles without an error in gcc 4.6.1 and 4.8.1 ( eclipse auto compilation says: Candidates are: float pow(float, int) long double pow(long double,
int) double pow(double, int) ):
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
int main(void) {
const int i = 0, x = 2;
double y = pow( i, x );
y = log( i ) / log( x );
cout << y;
return 0;
}
Thank you very much. This code has performed some nice confusing at work. The compiler can be trusted?
You do not get any compilation errors, since the C++ standards says that your integer type is to be accepted and converted to double.
From the standard §26.8/11:
Moreover, there shall be additional overloads sufficient to ensure:
[...]
3. Otherwise, if any argument corresponding to a double parameter has type double or an integer type, then all arguments corresponding to double parameters are effectively cast to double.
Also see cppreference.com/.../pow where it says:
If any argument has integral type, it is cast to double.
I assume that the question is: "Why does function overloading cause ambiguity error?".
The answer is very clear in your case: There is not any version of pow(a, b) that accepts the parameter a as integer. Rather than displaying an error, the compiler tries to find a version of pow where there is a built-in (or custom) type conversion operator that can cast int into the type pow expects. It happens that there are 3 such functions and there is a conversion operator for each such function. That is why the compiler finds it ambiguous.
Because pow acceptes a double or a float as second parameter (your x). Here is the description for pow in C++11.
If your run the same code on VS2010 in will too issue an error.
Why should I get this error
C2668: 'abs' : ambiguous call to overloaded function
For a simple code like this
#include <iostream>
#include <cmath>
int main()
{
unsigned long long int a = 10000000000000;
unsigned long long int b = 20000000000000;
std::cout << std::abs(a-b) << "\n"; // ERROR
return 0;
}
The error still presents after removing std::. However if I use int data type (with smaller values) there is no problem.
The traditional solution is to check that manually
std::cout << (a<b) ? (b-a) : (a-b) << "\n";
Is that the only solution?
The check seem the only really good solution. Alternatives require type bigger than yours and nonstandard extension to use it.
You can go with solutions casting to signed long long if your range fits. I would hardly suggest that way, especially if the implementation is placed in a function that does only that.
You are including <cmath> and thus using the "floating-point abs".
The "integer abs" is declared in <cstdlib>.
However, there is no overload for unsigned long long int (both a and b are, thus a-b is, too), and the overload for long long int only exists since C++11.
First, you need to include the correct header. As pointed out by gx_, <cmath> has a floating-point abs and on my compiler it actually compiles, but the result is probably not the one you expected:
1.84467e+19
Include <cstdlib> instead. Now the error is:
main.cpp:7:30: error: call of overloaded ‘abs(long long unsigned int)’ is ambiguous
main.cpp:7:30: note: candidates are:
/usr/include/stdlib.h:771:12: note: int abs(int)
/usr/include/c++/4.6/cstdlib:139:3: note: long int std::abs(long int)
/usr/include/c++/4.6/cstdlib:173:3: note: long long int __gnu_cxx::abs(long long int)
As you can see, there is no unsigned overload of this function, because computing an absolute value of something which is of type unsigned makes no sense.
I see answers suggesting you to cast an unsigned type to a signed one, but I believe this is dagereous, unless you really know what you are doing!
Let me ask first what is the expected range of the values a and b that you are going to operate on? If both are below 2^63-1 I would strongly suggest to just use long long int. If that is not true however, let me note that your program for the values:
a=0, b=1
and
a=2^64-1, b=0
will produce exactly the same result, because you actually need 65 bits to represent any possible outcome of a difference of 2 64-bit values. If you can confirm that this is not going to be a problem, use the cast as suggested. However, if you don't know, you may need to rethink what you are actually trying to achieve.
Because back before C++ with C you used to have use abs, fabs, labs for each different type, c++ allows overloading of abs, in this case it doesn't understand or isn't happy with your overload.
Use labs(a-b) seeing as you're using longs, this should solve your problem.
while doing some homework in my very strange C++ book, which I've been told before to throw away, had a very peculiar code segment. I know homework stuff always throws in extra "mystery" to try to confuse you like indenting 2 lines after a single-statement for-loop. But this one I'm confused on because it seems to serve some real-purpose.
basically it is like this:
int counter=10;
...
if(pow(floor(sqrt(counter+0.0)),2) == counter)
...
I'm interested in this part especially:
sqrt(counter+0.0)
Is there some purpose to the +0.0? Is this the poormans way of doing a static cast to a double? Does this avoid some compiler warning on some compiler I do not use? The entire program printed the exact same thing and compiled without warnings on g++ whenever I left out the +0.0 part. Maybe I'm not using a weird enough compiler?
Edit:
Also, does gcc just break standard and not make an error for Ambiguous reference since sqrt can take 3 different types of parameters?
[earlz#EarlzBeta-~/projects/homework1] $ cat calc.cpp
#include <cmath>
int main(){
int counter=0;
sqrt(counter);
}
[earlz#EarlzBeta-~/projects/homework1] $ g++ calc.cpp
/usr/lib/libstdc++.so.47.0: warning: strcpy() is almost always misused, please use strlcpy()
/usr/lib/libstdc++.so.47.0: warning: strcat() is almost always misused, please use strlcat()
[earlz#EarlzBeta-~/projects/homework1] $
Also, here is the relevant part of my system libraries cmath I'm not too keen on templates, so I'm not sure what it's doing
using ::sqrt;
inline float
sqrt(float __x)
{ return __builtin_sqrtf(__x); }
inline long double
sqrt(long double __x)
{ return __builtin_sqrtl(__x); }
template<typename _Tp>
inline typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value,
double>::__type
sqrt(_Tp __x)
{ return __builtin_sqrt(__x);
Is this the poormans way of doing a static cast to a double?
Yes.
You can't call sqrt with an int as its parameter, because sqrt takes a float, double, or long double. You have to cast the int to one of those types, otherwise the call is ambiguous.
the reason for the expression counter + 0.0 is to explicitly make it a real number. if we donot add 0.0 the compiler will do implicit conversion
It's just another way to cast to a double. This is because sqrt doesn't accept ints. Because a double is higher it will merge the int into the 0.0. The same way can be done for converting from (int,double,float) to string.
double n = 0;
string m = ""+n;