Opeartion on a variable and constant giving different result in c - c

A simple calculation: 3^20%15.
The answer, according to a calculator, is 6.
The following code generates answer 7.
#include <stdio.h>
#include <math.h>
int main() {
int i = 20;
printf("%d\n", ((int)pow(3,20)%15));
return 0;
}
If I replace 20 in the printf statement with the variable i, it gives -8 as output.
Assuming that the calculator is corrent (or not?), what is the problem in the program?
Thank you.

The result of pow(3,20) can't fit in an int on your platform (or mine for that matter). Because of that, you're experiencing unexpected results.
Changing to a larger integer type such as long long will do the job.
Moreover, pow works with floating-point numbers which aren't represented exactly in memory (look that up). During conversion to an integer, that can cause certain errors. For example, for printf("%fl\n", (pow(3,20))); I get 3486784401.000000l which is not a precise integer value.

What likely happened here is:
In your C implementation, int is 32 bits, with a minimum of −2,147,483,648 and a maximum of 2,147,483,647.
The result of pow(3, 20) is 3486784401. (See note 1 below.)
3486784401 is too large for an int, so there is an overflow. In case of integer overflow, the C standard permits an implementation to do anything.
In (int) pow(3, 20), the conversion to int may have been computed at a compile time by producing the maximum, 2,147,483,647. Then the remainder of that divided by 15 is 7.
In (int) pow(3, i), the conversion to int may have been computed at run time by producing the minimum, −2,147,483,648. (Some processors produce such a result for integer overflows.) Then the remainder of that divided by 15 is −8.
In summary:
Your code overflows, so the C standard does not define the behavior.
The compiler likely behaves differently for pow(3, 20) and pow(3, i) because it evaluates the former at compile time and the latter at execution time.
Note
Good implementations of pow return exactly 3486784401 for pow(3, 20). Unfortunately, poor implementations may return inaccurate values such as 3486784401.000000476837158203125 or 3486784400.999999523162841796875.

Related

`pow(x, 15)` function in C giving wrong (large negative) result for values of x >= 5

#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?.

C macro produces different result using literal vs variable

I have the following C program:
#include <stdio.h>
#include <math.h>
#define LOG2(x) ((int)( log((double)(x)) / log(2) ))
int main() {
int num = 64;
int val1 = LOG2(num);
int val2 = LOG2(64);
printf("val1: %d, val2 %d\n", val1, val2);
return 0;
}
Which outputs:
val1: 5, val2: 6
Why does this macro produce a different (and wrong) answer when I use it with a variable, but works correctly when I just type 64 directly?
Regardless of whether or not this is actually a good way to get the log base 2, what is causing this behavior? Is there any way I can get this macro to work properly with variables? (all my inputs will be exact powers of 2)
This is, mathematically, a fine way of computing base-2 logs, but since log(val) and log(2) are both going to be long, messy fractions, it's not unlikely that the result of the division will end up being 5.999, which will truncate down to 5. I recommend rounding, especially if you know the inputs will always be powers of 2.
(But why did you get different answers for constant vs. variable? That's a good question, and I'm not sure of the answer. Usually the answer is that when there are constants involved the compiler is able to perform some/all of the calculation at compile time, but often the compiler ends up using subtly or significantly different floating-point arithmetic than the run-time environment. But I wouldn't have thought the compiler would be interpreting functions like log() while doing compile-time constant folding.)
Also, some C libraries have a log2() function which should give you perfect answers, but I don't know how standard that function is.

pow numeric error in c

I'm wondering where does the numeric error happen, in what layer.
Let me explain using an example:
int p = pow(5, 3);
printf("%d", p);
I've tested this code on various HW and compilers (VS and GCC) and some of them print out 124, and some 125.
On the same HW (OS) i get different results in different compilers (VS and GCC).
On the different HW(OS) I get different results in the same compiler (cc (GCC) 4.8.1).
AFAIK, pow computes to 124.99999999 and that gets truncated to int, but where does this error happen?
Or, in other words, where does the correction happen (124.99->125)
Is it a compiler-HW interaction?
//****** edited:
Here's an additional snippet to play with (keep an eye on p=5, p=18, ...):
#include <stdio.h>
#include <math.h>
int main(void) {
int p;
for (p = 1; p < 20; p++) {
printf("\n%d %d %f %f", (int) pow(p, 3), (int) exp(3 * log(p)), pow(p, 3), exp(3 * log(p)));
}
return 0;
}
(First note that for an IEEE754 double precision floating point type, all integers up to the 53rd power of 2 can be represented exactly. Blaming floating point precision for integral pow inaccuracies is normally incorrect).
pow(x, y) is normally implemented in C as exp(y * log(x)). Hence it can "go off" for even quite small integral cases.
For small integral cases, I normally write the computation long-hand, and for other integral arguments I use a 3rd party library. Although a do-it-yourself solution using a for loop is tempting, there are effective optimisations that can be done for integral powers that such a solution might not exploit.
As for the observed different results, it could be down to some of the platforms using an 80 bit floating point intermediary. Perhaps some of the computations then are above 125 and others are below that.

Why does pow(n,2) return 24 when n=5, with my compiler and OS?

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int n,i,ele;
n=5;
ele=pow(n,2);
printf("%d",ele);
return 0;
}
The output is 24.
I'm using GNU/GCC in Code::Blocks.
What is happening?
I know the pow function returns a double , but 25 fits an int type so why does this code print a 24 instead of a 25? If n=4; n=6; n=3; n=2; the code works, but with the five it doesn't.
Here is what may be happening here. You should be able to confirm this by looking at your compiler's implementation of the pow function:
Assuming you have the correct #include's, (all the previous answers and comments about this are correct -- don't take the #include files for granted), the prototype for the standard pow function is this:
double pow(double, double);
and you're calling pow like this:
pow(5,2);
The pow function goes through an algorithm (probably using logarithms), thus uses floating point functions and values to compute the power value.
The pow function does not go through a naive "multiply the value of x a total of n times", since it has to also compute pow using fractional exponents, and you can't compute fractional powers that way.
So more than likely, the computation of pow using the parameters 5 and 2 resulted in a slight rounding error. When you assigned to an int, you truncated the fractional value, thus yielding 24.
If you are using integers, you might as well write your own "intpow" or similar function that simply multiplies the value the requisite number of times. The benefits of this are:
You won't get into the situation where you may get subtle rounding errors using pow.
Your intpow function will more than likely run faster than an equivalent call to pow.
You want int result from a function meant for doubles.
You should perhaps use
ele=(int)(0.5 + pow(n,2));
/* ^ ^ */
/* casting and rounding */
Floating-point arithmetic is not exact.
Although small values can be added and subtracted exactly, the pow() function normally works by multiplying logarithms, so even if the inputs are both exact, the result is not. Assigning to int always truncates, so if the inexactness is negative, you'll get 24 rather than 25.
The moral of this story is to use integer operations on integers, and be suspicious of <math.h> functions when the actual arguments are to be promoted or truncated. It's unfortunate that GCC doesn't warn unless you add -Wfloat-conversion (it's not in -Wall -Wextra, probably because there are many cases where such conversion is anticipated and wanted).
For integer powers, it's always safer and faster to use multiplication (division if negative) rather than pow() - reserve the latter for where it's needed! Do be aware of the risk of overflow, though.
When you use pow with variables, its result is double. Assigning to an int truncates it.
So you can avoid this error by assigning result of pow to double or float variable.
So basically
It translates to exp(log(x) * y) which will produce a result that isn't precisely the same as x^y - just a near approximation as a floating point value,. So for example 5^2 will become 24.9999996 or 25.00002

Weird behaviour on c arithmetics

I have this code
#include <stdio.h>
#include <math.h>
static double const x = 665857;
static double const y = 470832;
int main(){
double z = x*x*x*x -y*y*y*y*4 - y*y*4;
printf("%f \n",z);
return 0;
}
The real solution of this is equation is 1. As already answered on a previous question by myself, this code fails because of catastrophic cancellation. However, now I've found an even more strange thing. It works if you use long longs, while, as far as I know, they have less range than doubles. Why?
long long has less range, but more precision than double.
However, that's not what's at work here. Your computation actually exceeds the range of long long as well, but because of the way in which integer overflow is handled on your system, the correct result falls out anyway. (Note that the behavior of signed integer overflow is not pinned down by the C standard, but "usually" behaves as you see here).
If you look instead at the intermediate result x*x*x*x, you will see that if you compute it using double, it has a sensible value; not exact, but rounded and good enough for most purposes. However, if you compute it in long long, you will find a number that appears at first to be absolutely bonkers, due to overflow.
In a double there are bits for the mantissa and exponent. For large doubles the distance between two doubles (same exponent, 1 added to the mantissa) results, is much larger than 1. Hence you are in the same situation as infinity + 1 = infinity.
long long's will overflow, calculate modulo 2”, and hence the result when it should be 1 can indeed be one.
An overflow for a floating point type can either be considered undefined or an error, depending on language and environment. An overflow for an integral type simply wraps around (sometimes still yielding correct results, and sometimes not).

Resources