Why does sqrt() work fine on an int variable if it is not defined for an int?
Update 2
This question was merged with an exact duplicate, on taking a look at this, the actual answer is much simpler than anyone originally thought. The current version of std_lib_facilities.h includes the following line:
inline double sqrt(int x) { return sqrt(double(x)); } // to match C++0x
which creates a specific overload for the int case to match what modern compilers should be be doing which is cast integer arguments to double, although this version does not cover all the cases.
If std_lib_facilities.h was not being used than the original logic still applies, although gcc-4.2
is rather old compared to Visual Studio 2012 from the original question but a 4.1.2
version have uses __builtin_sqrt
specifically for the integer case.
Original
Since around 2005 the draft standard required integer argument to be cast to double this is covered in the draft C++ standard. If we look in section 26
Numerics library and then go to section 26.8
C library which covers the <cmath>
header, it specifies overloads of the math functions for float, double and long double which is covered in paragraph 8:
In addition to the double versions of the math functions in , C++ adds float and long double overloaded versions of these functions, with the same semantics.
which would be ambiguous
for the int
case but the standard requires that sufficient overload are provided so that integer arguments are cast to double. It is covered in paragraph 11 which says(emphasis mine):
Moreover, there shall be additional overloads sufficient to ensure:
- If any arithmetic argument corresponding to a double parameter has type long double, then all arithmetic arguments corresponding to double parameters are effectively cast to long double.
- Otherwise, if any arithmetic argument corresponding to a double parameter has type double or an integer type, then all arithmetic arguments corresponding to double parameters are effectively cast to double.
- Otherwise, all arithmetic arguments corresponding to double parameters have type float.
Update
As @nos points out it is possible that the version of sqrt
being called is from math.h
header as opposed to the overloads from cmath
, if that is the case and there is likely a implementation defined caveat here then we may be reverting to old C style behavior if the only version available is sqrt(double)
which would mean that int would be converted to double implicitly.
One way I found to test this on gcc
and clang
would be to use long type for a
which along with -Wconversion
flag triggers a warning for a potentially value altering conversion on my platform if we only have sqrt(double)
available. Indeed if I include math.h
instead of cmath
we can produce this warning. Although I can not trigger this behavior in clang which seems to indicate this is implementation dependent.
sqrt() - Why am I allowed to provide an argument of int and not only double and the output is also right?
This is not undefined behavior.
The function is defined to accept an argument of type double
. Because the type of the argument is known, you can pass an int
because it may be implicitly converted to a double
. It's the same as if you did:
int i = 4;
double d = i;
The rules for conversion of function arguments are spelled out in section 6.5.2.2p7 of the C standard regarding the function call operator ()
:
If the expression that denotes the called function has a type that
does include a prototype, the arguments are implicitly converted, as
if by assignment, to the types of the corresponding parameters, taking
the type of each parameter to be the unqualified version of its
declared type. The ellipsis notation in a function prototype
declarator causes argument type conversion to stop after the last
declared parameter. The default argument promotions are performed on
trailing arguments
In contrast, if you passed an int
to printf
when the format string expects a double
, i.e.:
printf("%f\n", 4);
Then you have undefined behavior. This is because the types of the arguments are not known at compile time so the implicit conversion can't happen.
Why does sqrt function not work for values taken through user input?
Like was mentioned in the comments, you haven't linked against libm
so sqrt
is undefined at link-time.
Why would a constant value work for
sqrt
, while a variable user input value won't?
Because GCC recognizes sqrt
as a builtin function and is able to evaluate the square root of a compile-time constant at compilation time, and forgoes the call to sqrt
altogether, thus avoiding the subsequent linker error.
The ISO C90 functions ...
sqrt
, ... are all recognized as built-in functions unless-fno-builtin
is specified (or-fno-builtin-
function
is specified for an individual function).
If you were to add -fno-builtin-sqrt
, you would see the linker error regardless of what you pass to sqrt
.
C: datatypes. sqrt function working with int why?
Why are all these [two initializations] work?
The first initialization float b = sqrt(1234)
works because the language "upcasts" the integer literal 1234
to double
before calling sqrt
, and then converting the result to float
.
The second initialization int b = sqrt(1234.22)
works for the same reason, except this time the compiler does not have to upcast 1234.22
literal before the call, because it is already of type double
.
This is discussed in C99 standard:
6.3.1.4.1: When a finite value of real floating type is converted to an integer type other than
_Bool
, the fractional part is discarded.6.7.8.11: The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion) (emphasis added).
-
why do we need this [cast
int a = (int) b;
]?
You may insert a cast for readability, but the standard does not require it (demo).
sqrt() of int type in C
Type conversions which do not cause a loss in precision might not throw warnings. They are cast implicitly.
int --> double //no loss in precision (e.g 3 became 3.00)
double --> int //loss in precision (e.g. 3.01222 became 3)
What triggers a warning and what doesn't is depends largely upon the compiler and the flags supplied to it, however, most compilers (atleast the ones I've used) don't consider implicit type-conversions dangerous
enough to warrant a warning, as it is a feature in the language specification.
To warn or not to warn:
C99 Rationale states it like a guideline
One of the important outcomes of exploring this (implicit casting) problem is the understanding that high-quality compilers might do well to look
for such questionable code and offer (optional) diagnostics, and that
conscientious instructors might do well to warn programmers of the
problems of implicit type conversions.
C99 Rationale (Apr 2003) : Page 45
sqrt() function not working with variable arguments
You need to link with the math library (use a '-lm' on the command line). In the constant case, the compiler is probably being smart and precomputing sqrt(2.0) (so the code that is compiled is essentially 'b = 1.414...;')
Using (int) sqrt(N) causes 'array bound is not an integer constant'
int arr[size];
This defines an array with a constant size. But size
was computed by a call to sqrt
, so it's not a constant according to how C programs are executed.
The compiler needs to know how big the array is to create the global memory layout of the program. So the sqrt
can't be deferred until runtime. And C doesn't have any concept of a "math" function that can be resolved at compile time.
The only way through this is to perform the calculation yourself and put the result (2
) directly into the source code.
Why am I getting undefined reference to sqrt error even though I include math.h header?
The math library must be linked in when building the executable. How to do this varies by environment, but in Linux/Unix, just add -lm
to the command:
gcc test.c -o test -lm
The math library is named libm.so
, and the -l
command option assumes a lib
prefix and .a
or .so
suffix.
Related Topics
When Is C++ Covariance the Best Solution
How to Load a Bmp on Glut to Use It as a Texture
Conversion from Void* to the Pointer of the Base Class
C++ Static_Cast Runtime Overhead
C++: Read from Text File and Separate into Variable
Memset Structure with Std::String Contained
Strange "Unsigned Long Long Int" Behaviour
When to Use C++ Private Inheritance Over Composition
Pass Arrays from C/C++ to Fortran and Return a Calculated Array
Visual C++ "For Each" Portability
"Cannot Evaluate Function -- May Be In-Lined" Error in Gdb for Stl Template Container
Traceback a Pointer in C++ Code Gdb
Calculate A*A Mod N Without Overflow
Cut Set of a Graph, Boost Graph Library
Understanding Std::Atomic::Compare_Exchange_Weak() in C++11
Enumdisplaydevices VS Wmi Win32_Desktopmonitor, How to Detect Active Monitors