Akhil Raj
Akhil Raj

Reputation: 477

Programming in C, Using pow function

This is a part of code I wrote in a C program---

else if((pow(b,2.0)-4*a*c)>0) {
    printf("\nRoots=%.2f and %.2f\n",
           (-b+pow(b*b-4*a*c,0.5))/(2*a),
           (-b-pow(b*b-4*a*c,0.5))/(2*a));
} else
    printf("\nBoth roots are %.2f\n",-b/(2*a));

In the console, if I write a as 1, b as 14 and c as 49, If says "Roots =-7.00 and -7.00" ... instead of saying "Both roots are -7.00" But it shows latter result if I replace pow(b,2) by b*b in else if condition.... Why is this so? Please explain.

Upvotes: 0

Views: 522

Answers (4)

chqrlie
chqrlie

Reputation: 144520

This probably a precision issue. The algorithm used by pow(b, 2.0) for b positive could be something like exp(2.0 * log(b)) and may produce a number that is very close to 196.0 but not exactly 196. The comparison fails but the results still look the same when rounded to 2 decimal places for printing. Try %g instead.

Conversely b * b for b = 14.0 computes exactly as 196.

Incidentally, I get the proper result for your code on my laptop, what OS and compiler do you use?

Upvotes: 2

Jay
Jay

Reputation: 9646

Please include a minimum working example with your code.

Anyway, it works on my system (Debian GNU/Linux testing, gcc 5.2.1):

#include <math.h>
#include <stdio.h>
int main() {

    float a,b,c;
    scanf("%f",&a);
    scanf("%f",&b);
    scanf("%f",&c);

    if ((pow(b,2.0)-4*a*c)<0)
        printf("\nNo roots!\n");
    else if((pow(b,2.0)-4*a*c)>0) {
        printf("\nRoots=%.2f and %.2f\n",
               (-b+pow(b*b-4*a*c,0.5))/(2*a),
               (-b-pow(b*b-4*a*c,0.5))/(2*a));
    } else
        printf("\nBoth roots are %.2f\n",-b/(2*a));
    return 0;
}

If I enter 1, 14, 49, the program answers Both roots are -7.0. But this may vary among systems, because you are using floating point arithmetic and I don't know how your pow() function was implemented. Not all real numbers can be represented on a computer -- here's a good description of how it works for single precision floats. And each compiler/runtime environment will have a possibly different implementation of the math library (which includes pow, that you have used).

So, I would avoid pow at all if possible. Use b*b instead, and save pow for when you really need it. And as Tom Karzes mentioned, sqrt is also better than using pow for calculating square roots.

One last thing: calculating the discriminant only once would make your program more readable:

#include <math.h>
#include <stdio.h>

int main() {

    float a,b,c;
    float delta;
    scanf("%f",&a);
    scanf("%f",&b);
    scanf("%f",&c);

    delta = b*b-4*a*c;

    if (delta<0)
        printf("\nNo roots!\n");
    else if(delta>0)
        printf("\nRoots=%.2f and %.2f\n",
               (-b+sqrt(delta))/(2*a),
               (-b-sqrt(delta))/(2*a));
    else
        printf("\nBoth roots are %.2f\n",-b/(2*a));
    return 0;
}

One more thing you may try is to use double instead of float, so you'll have more precision (not relevant depending on the numbers you'll be using, but it's a good idea to use doubles if you don't have huge matrices of numbers that could take too much memory -- a double takes twice as memory as a float to represent).

Upvotes: 3

thepace
thepace

Reputation: 2221

This article would guide you why the results differ : https://randomascii.wordpress.com/2013/07/16/floating-point-determinism/

I would suggest if you try this and see if that works.

((int)pow(b,2) - (4*a*c))>0 // Assuming computation is based on integers.

If not, try these suggestions (with analogous functions in C):

What is the best way to compare floats for almost-equality in Python?

Upvotes: 0

Tom Karzes
Tom Karzes

Reputation: 24052

Using pow(b, 2.0) will generally be less accurate than b*b. While they're mathematically the same, the pow function is going to do something like exp(2.0 * log(b)). It also needs to make special checks for negative b etc. Also, when taking the square root, use sqrt(x) rather than pow(x, 0.5), for similar reasons: It will be faster and more accurate.

Your code will also be improved by computing the discriminant once and saving it rather than replicating the code.

Upvotes: 2

Related Questions