 Why is pow() function giving wrong answer

60 Views

I'm trying to multiply 2, 3 digit numbers. I used 2 for loops (nested) and multiplied each digit of num1 with num2, and shifted each result to the appropriate place using pow(). So the problem is pow(10,3) is coming out to be 299 instead of 300.

I haven't tried much as but used printf to find what is actually happening in the runtime and this is what I have found. the values of tempR after shift should be
5,40,300,100,800,6000,1500,12000,90000
but are coming as
5,40,299,100,799,6000,1500,12000,89999

int main(void)
{
int result; // final result
int  tempR; // temporary for each iteration
char a[] = "345"; // number 1
char b[] = "321"; // number 2
for(int i = 2;i>= 0 ; i --)
{
for(int j = 2;j >= 0 ; j --)
{
int shift = abs(i-2 + j -2);
printf("%d
",shift);  //used to see the values of shift.
//and it is coming as expected
tempR = (int)(b[i] - '0') * (int)(a[j] - '0');
printf("%d
",tempR);    // value to tempR is perfect
tempR = tempR*pow(10,shift);
printf("%d
",tempR);  // here the problem starts
result += tempR;
}
}

printf("%d",result);
} The pow function operates on doubles. Doubles use finite precision. Conversion back to integer chops rather than rounding.

Finite precision is like representing 1/3 as 0.333333. If you do 9 * 1/3 and chop to an integer, you'll get 2 instead of 3 because 9 * 1/3 will give 2.999997 which chops to two.

This same kind of rounding and chopping is causing you to be off by one. You could also round by adding 0.5 before chopping to an integer, but I wouldn't suggest it.

Don't pass integers through doubles and back if you expect exact answers.

Although IEEE754 (ubiquitous on desktop systems) is required to return the best possible floating point value for certain operators such as addition, multiplication, division, and subtraction, and certain functions such as sqrt, this does not apply to pow.

pow(x, y) can and often is implemented as exp(y * ln (x)). Hopefully you can see that this can cause the powresult to "go off" spectacularly when used with seemingly trivial integral arguments. In your case, the rot truly sets in when you truncate the result to an int.

The moral of the story is to borrow an implementation of pow that takes integral arguments from a respected mathematics library (they use a technique called exponention by squaring), or roll your own. Using roundis also a technique, if a little kludgy if you get my meaning.