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.
Related
Continuing the question, which was closed:
C++: "auto" keyword affects math calculations?
As people suggested I modified the code by adding "f" suffix to floating-point values.
#include <cmath>
unsigned int nump=12u;
auto inner=2.5f;
auto outer=6.0f;
auto single=2.f*3.14159265359f/nump;
auto avg=0.5f*inner+0.5f*outer;
for (auto i=0u;i<nump;++i){
auto theta=i*single;
auto px=avg*sin(theta);
auto py=avg*cos(theta);
auto tw=17.f;
int v1=std::round(1.f+px-tw/2.0f);
int v2=std::round(2.f+py-tw/2.0f);
std::cout<<"#"<<i<<":"<<v1<<";"<<v2<<std::endl;
}
versus
#include <cmath>
unsigned int nump=12u;
float inner=2.5f;
float outer=6.0f;
float single=2.f*3.14159265359f/nump;
float avg=0.5f*inner+0.5f*outer;
for (unsigned int i=0u;i<nump;++i){
float theta=i*single;
float px=avg*sin(theta);
float py=avg*cos(theta);
float tw=17.f;
int v1=std::round(1.f+px-tw/2.0f);
int v2=std::round(2.f+py-tw/2.0f);
std::cout<<"#"<<i<<":"<<v1<<";"<<v2<<std::endl;
}
The result is exactly the same - output differs between two versions.
So does it mean that "auto" always evaluates floating point value to "double" type?
The issue is that your code is using ::sin instead of std::sin (and the same for cos). That is, you’re using the sin function found in the global namespace.
std::sin is overloaded for float. But ::sin isn’t, and it always returns a double (because ::sin is the legacy C function, and C doesn’t have function overloading).
Use std::sin and std::cos in your code to fix the issue.
When you use the literal 2.5f you are already suggesting that the value is a float.
You'll see that if you try using 2.5 as literal when assigning value to an auto variable, it deduces this as double.
auto var1 = 2.5 // deduced as type double
auto var2 = 2.5f // deduced as type float as suggested in literal
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.
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);
I have a call to
long long a = sqrt(n/2);
Both a and n are long long's but it won't let me compile because it says my use of sqrt() is an ambiguous call. I don't see how it's possibly ambiguous here at all. How do I resolve this? I have the same problem with floor().
My includes
#include "stdafx.h"
#include <iostream>
#include <cmath>
using namespace std;
There are several overloads of sqrt() and floor(), there's no "best match" for a call to sqrt(long long) according to the overload resolution rules. Just cast the argument to the appropriate type -- i.e.,
long long a = sqrt(static_cast<double>(n/2));
//use
sqrt(static_cast<double>(n/2));
//instead of
sqrt(n/2);
The sqrt functions expects a float, a double or a long double:
long long a = sqrt(n * 0.5);
You may lose some precision converting a long long to a double, but the value will be very close.
According to the reference
http://www.cplusplus.com/reference/clibrary/cmath/sqrt/
I would propose to convert to long double first.
No overload of sqrt accepts an integral value
integral parameter could always result in a "real" value (float, double, long double)
Is there a g++ warning or other tool that can identify integer division (truncation toward zero)? I have thousands of lines of code with calculations that inevitably will have numerical errors typically due to "float = int/int" that need to be located. I need a reasonable method for finding these.
Try -Wconversion.
From gcc's man page:
Warn for implicit conversions that may
alter a value. This includes
conversions between real and integer,
like "abs (x)" when "x" is "double";
conversions between signed and
unsigned, like "unsigned ui = -1"; and
conversions to smaller types, like
"sqrtf (M_PI)". Do not warn for
explicit casts like "abs ((int) x)"
and "ui = (unsigned) -1", or if the
value is not changed by the conversion
like in "abs (2.0)". Warnings about
conversions between signed and
unsigned integers can be disabled by
using -Wno-sign-conversion.
For C++, also warn for conversions
between "NULL" and non-pointer types;
confusing overload resolution for
user-defined conversions; and
conversions that will never use a type
conversion operator: conversions to
"void", the same type, a base class or
a reference to them. Warnings about
conversions between signed and
unsigned integers are disabled by
default in C++ unless
-Wsign-conversion is explicitly enabled.
For the following sample program (test.cpp), I get the error test.cpp: In function ‘int main()’:
test.cpp:7: warning: conversion to ‘float’ from ‘int’ may alter its value.
#include <iostream>
int main()
{
int a = 2;
int b = 3;
float f = a / b;
std::cout << f;
return 0;
}
I have a hard time calling these numerical errors. You asked for integer calculations, and got the correct numbers for integer calculations. If those numbers aren't acceptable, then ask for floating point calculations:
int x = 3;
int y = 10;
int z = x / y;
// "1." is the same thing as "1.0", you may want to read up on
// "the usual arithmetic conversions." You could add some
// parentheses here, but they aren't needed for this specific
// statement.
double zz = 1. * x / y;
This page contains info about g++ warnings. If you've already tried -Wall then the only thing left could be the warnings in this link. On second look -Wconversion might do the trick.
Note: Completely edited the response.
Remark on -Wconversion of gcc:
Changing the type of the floating point variable from float to double makes the warning vanish:
$ cat 'file.cpp'
#include <iostream>
int main()
{
int a = 2;
int b = 3;
double f = a / b;
std::cout << f;
}
Compiling with $ g++-4.7 -Wconversion 'file.cpp' returns no warnings (as $ clang++ -Weverything 'file.cpp').
Explanation:
The warning when using the type float is not returned because of the totally valid integer arithmetics, but because float cannot store all possible values of int (larger ones cannot be captured by float but by double). So there might be a change of value when assigning RHS to f in the case of float but not in the case of double. To make it clear: The warning is not returned because of int/int but because of the assignment float = int.
For this see following questions: what the difference between the float and integer data type when the size is same in java, Storing ints as floats and Rounding to use for int -> float -> int round trip conversion
However, when using float -Wconversion could still be useful to identify possible lines which are affected but is not comprehensive and is actually not intended for that. For the purpose of -Wconversion see docs/gcc/Warning-Options.html and here gcc.gnu.org/wiki/NewWconversion
Possibly of interest is also following discussion 'Implicit casting Integer calculation to float in C++'
The best way to find such error is to have really good unit tests. All alternatives are not good enough.
Have a look at this clang-tidy detection.
It catches cases like this:
d = 32 * 8 / (2 + i);
d = 8 * floatFunc(1 + 7 / 2);
d = i / (1 << 4);