I'm a bit confused about the round() function in C.
First of all, man says:
SYNOPSIS
#include <math.h>
double round(double x);
RETURN VALUE
These functions return the rounded integer value.
If x is integral, +0, -0, NaN, or infinite, x itself is returned.
The return value is a double / float or an int?
In second place, I've created a function that first rounds, then casts to int. Latter on my code I use it as a mean to compare doubles
int tointn(double in,int n)
{
int i = 0;
i = (int)round(in*pow(10,n));
return i;
}
This function apparently isn't stable throughout my tests. Is there redundancy here? Well... I'm not looking only for an answer, but a better understanding on the subject.
The wording in the man-page is meant to be read literally, that is in its mathematical sense. The wording "x is integral" means that x is an element of Z, not that x has the data type int.
Casting a double to int can be dangerous because the maximum arbitrary integral value a double can hold is 2^52 (assuming an IEEE 754 conforming binary64 ), the maximum value an int can hold might be smaller (it is mostly 32 bit on 32-bit architectures and also 32-bit on some 64-bit architectures).
If you need only powers of ten you can test it with this little program yourself:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(){
int i;
for(i = 0;i < 26;i++){
printf("%d:\t%.2f\t%d\n",i, pow(10,i), (int)pow(10,i));
}
exit(EXIT_SUCCESS);
}
Instead of casting you should use the functions that return a proper integral data type like e.g.: lround(3).
here is an excerpt from the man page.
#include <math.h>
double round(double x);
float roundf(float x);
long double roundl(long double x);
notice: the returned value is NEVER a integer. However, the fractional part of the returned value is set to 0.
notice: depending on exactly which function is called will determine the type of the returned value.
Here is an excerpt from the man page about which way the rounding will be done:
These functions round x to the nearest integer, but round halfway cases
away from zero (regardless of the current rounding direction, see
fenv(3)), instead of to the nearest even integer like rint(3).
For example, round(0.5) is 1.0, and round(-0.5) is -1.0.
If you want a long integer to be returned then please use lround:
long int tolongint(double in)
{
return lround(in));
}
For details please see lround which is available as of the C++ 11 standard.
Related
While writing this answer, I used the mpf_pow function to calculate 12.3 ^ 123, and the result is different from the one given by WolframAlpha (which by the way also uses GMP).
I casted the code to pure C to simplify:
#include <stdio.h>
#include <gmp.h>
int main (void) {
mpf_t a, c;
unsigned long int b = 123UL;
mpf_set_default_prec(100000);
mpf_inits(a, c, NULL);
mpf_set_d(a, 12.3);
mpf_pow_ui(c, a, b);
gmp_printf("c = %.50Ff\n", c);
return 0;
}
Which results in
114374367934618002778643226182707594198913258409535335775583252201365538178632825702225459029661601216944929436371688246107986574246790.32099077871758646985223686110515186972735931183764
While WolframAlpha returns
1.14374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134895919942820874449837212099476648958359023796078549041949007807220625356526926729664064846685758382803707100766740220839267 × 10^134
which starts to disagree with mpf_pow at the 15th digit.
Am I doing something wrong in the code, is this a limitation of GMP, or is WolframAlpha giving an incorrect result?
Am I doing something wrong in the code, is this a limitation of GMP, or is WolframAlpha giving an incorrect result?
You are doing something different from what Wolfram is doing (obviously). Your code is not wrong, per se, but it is not doing what you probably think it is doing. Compare the output of this variation:
#include <stdio.h>
#include <gmp.h>
int main (void) {
mpf_t a, c;
unsigned long int b = 123UL;
mpf_set_default_prec(100000);
mpf_inits(a, c, NULL);
mpf_set_d(a, 12.3);
mpf_pow_ui(c, a, b);
gmp_printf("c = %.50Ff\n", c);
putchar('\n');
mpf_t a1, c1;
mpf_inits(a1, c1, NULL);
mpf_set_str(a1, "12.3", 10);
mpf_pow_ui(c1, a1, b);
gmp_printf("c' = %.50Ff\n", c1);
return 0;
}
...
c = 114374367934618002778643226182707594198913258409535335775583252201365538178632825702225459029661601216944929436371688246107986574246790.32099077871758646985223686110515186972735931183764
c' = 114374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134.89591994282087444983721209947664895835902379607855
The difference between the two output values arises because my C implementation and yours represent values of type double in binary floating point, and 12.3 is not exactly representable in binary floating point (see Is floating point math broken?). C provides the closest approximation available, which, assuming 64-bit IEEE 754 representation, matches to about 15 decimal digits of precision. When you initialize a GMP variable with such a value, you get an exact GMP representation of the actual double value, which is only an approximation to 12.3 decimal.
But GMP can represent 12.3 (decimal) to whatever precision you choose.* You chose a very high precision, so when you use a decimal string to initialize your MP-float variable you get a much closer approximation than when you used a double. Naturally, performing the same operation on those different values produces different results. The GMP result in the latter case appears to agree with the Wolfram result to the full precision in which it is expressed.
Note also that in a general sense, one can also use decimal floating-point, in software or (if you are so equipped) in hardware. The value 12.3 (decimal) can be represented exactly in such a format, but that's not what GMP uses.
* Or indeed, GMP can represent 12.3 exactly as a MP rational, though that's not what the code above does.
This gives a result similar to WolframAlpha's:
from decimal import Decimal
from decimal import getcontext
getcontext().prec = 200
print(Decimal('12.3') ** 123)
So you must be doing something wrong in your GMP configuration.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
main()
{
int x, y;
printf("Enter a number ");
scanf("%d", &x);
y = pow(x,15);
printf("This is your new number %d", y);
}
When I pass x as 2, 3 or 4 it gives the correct result, but when I pass in 5 or any number higher than 5, it gives -2147483648, which is obviously incorrect.
What is the problem here? Any thoughts?
In your environment, the int data type is not large enough to hold the value 515. The int type on your system is likely only 32-bit, and since it is a signed type, you have only 31 bits, so the largest positive integer that it can hold is (232 - 1).
Since 515 > (232 - 1), the result that is stored in y overflows. Since pow returns double type, the behaviour of this overflowing conversion is undefined. As with all undefined behaviour, there is no guarantee about what will happen. Even running the same program twice in a row may produce different results.
The answer is y is an int, and can't hold the large output value, so you get signed overflow into the negative number space, which is undefined behavior and should be considered a bug you need to fix. Choose a larger data type for y, such as long long, or even better, int64_t (included with #include <stdint.h>, or double, which is the type pow() naturally returns. See here: https://en.cppreference.com/w/c/numeric/math/pow.
Note that pow() returns a type double, which uses exponential notation to represent larger numbers, at the cost of losing precision as the number grows away from zero. To go even larger, use powl() to do the math with the long double type, and then make y of type long double as well.
This is a related answer that may be considered by some to be a duplicate, since a very similar problem is happening: Pow() calculates wrong?.
When I use the pow() function, sometimes the results are off by one. For example, this code produces 124, but I know that 5³ should be 125.
#include<stdio.h>
#include<math.h>
int main(){
int i = pow(5, 3);
printf("%d", i);
}
Why is the result wrong?
Your problem is that you are mixing integer variables with floating point math. My bet is that the result of 5^3 is something like 124.999999 due to rounding problems and when cast into integer variable get floored to 124.
There are 3 ways to deal with this:
more safely mix floating math and integers
int x=5,y=3,z;
z=floor(pow(x,y)+0.5);
// or
z=round(pow(x,y));
but using this will always present a possible risk of rounding errors affecting the result especially for higher exponents.
compute on floating variables only
so replace int with float or double. This is a bit safer than #1 but still in some cases is this not usable (depends on the task). and may need occasional floor,ceil,round along the way to get the wanted result correctly.
Use integer math only
This is the safest way (unless you cross the int limit). The pow can be computed on integer math relatively easily see:
Power by squaring for negative exponents
pow(x, y) is most likely implemented as exp(y * log(x)): modern CPUs can evaluate exp and log in a couple of flicks of the wrist.
Although adequate for many scientific applications, when truncating the result to an integer, the result can be off for even trivial arguments. That's what is happening here.
Your best bet is to roll your own version of pow for integer arguments; i.e. find one from a good library. As a starting point, see The most efficient way to implement an integer based power function pow(int, int)
Use Float Data Type
#include <stdio.h>
#include <math.h>
int main()
{
float x=2;
float y=2;
float p= pow(x,y);
printf("%f",p);
return 0;
}
You can use this function instead of pow:
long long int Pow(long long int base, unsigned int exp)
{
if (exp > 0)
return base * Pow(base, exp-1);
return 1;
}
Given the C code:
#include <math.h>
#include <stdio.h>
int main(){
int i;
double f=log(2.0)/log(pow(2.0,1.0/2.0));
printf("double=%f\n",f);
printf("int=%d\n",(int) f);
}
I get the output:
double=2.000000
int=1
f is apparently at least 2.0. Why is the cast value not 2?
Because the value of the double was less than 2
double=1.99999999999999978
int=1
Try it but this time add some precision
#include <math.h>
#include <stdio.h>
int main(){
int i;
double f=log(2.0)/log(pow(2.0,1.0/2.0));
printf("double=%0.17f\n",f);
printf("int=%d\n",(int) f);
}
Confusing as hell the first time you experience it. Now, if you try this
#include <math.h>
#include <stdio.h>
int main(){
int i;
double f=log(2.0)/log(pow(2.0,1.0/2.0));
printf("double=%0.17f\n",f);
printf("int=%d\n",(int) f);
printf("int=%d\n", (int)round(f));
}
It will correctly round the value. If you look in the man page (on a mac at least) you'll see the following comment...
round, lround, llround -- round to integral value, regardless of rounding direction
What do they mean by direction, it's all specified in IEEE 754. If you check the different ways to round to an integer... floor is mentioned as rounding towards -ve infinity which is in this case was towards 1 :)
Floating point types are unable to represent some numbers exactly. Even though mathematically, the calculation should be exactly 2, with IEEE754 floating points, the result turns out to be slightly less than 2. For more information see this question.
If you increase the precision of your output by specifying %.20f instead of just %f, you will see that the number is not exactly 2, and that when printing with less accuracy, the result is simply rounded.
When converting to an int however, the full accuracy of the floating point type is used, and since it comes to just under 2, the result when converting to an integer is 1.
Integer does not take a rounded up value but makes a truncation. So, if f is equal to 1.999999999999[..]9, the int value will be 1.
Also, as the double wants to be the more accurate possible, he will take a rounded up value considering the number of characters he can show, which is 2.000000.
Whenever I input a number in this program the program return a value which is 1 less than the actual result ... What is the problem here??
#include<stdio.h>
#include<math.h>
int main(void)
{
int a,b,c,n;
scanf("%d",&n);
c=pow((5),(n));
printf("%d",c);
}
pow() returns a double, the implicit conversion from double to int is "rounding towards zero".
So it depends on the behavior of the pow() function.
If it's perfect then no problem, the conversion is exact.
If not:
1) the result is slightly larger, then the conversion will round it down to the expected value.
2) if the result is slightly smaller, then the conversion will round down which is what you see.
solution:
Change the conversion to "round to nearest integer" by using rounding functions
c=lround(pow((5),(n)));
In this case, as long as pow() has an error of less than +-0.5 you will get the expected result.
pow() takes double arguments and returns a double.
If you store the return value into an int and print that, you may not get the desired result.
If you need accurate results for big numbers, you should use a arbitrary precision math library like GMP. It's easy:
#include <stdio.h>
#include <math.h>
#include <gmp.h>
int main(void) {
int n;
mpz_t c;
scanf("%d",&n);
mpz_ui_pow_ui(c, 5, n);
gmp_printf("%Zd\n", c);
return 0;
}
You can use the %f format specifier while commanding printf func.You should see your result accurately. In %d format specifier the value tends to the final answer eg. 5^2=24.9999999999 and hence the answer shown is 24.