0

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.

Jay
  • 9,585
  • 6
  • 49
  • 72
Akhil Raj
  • 457
  • 1
  • 4
  • 14

4 Answers4

3

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).

Jay
  • 9,585
  • 6
  • 49
  • 72
  • 1
    Using `float` instead of `double` is pushing for more precision issues. – chqrlie Dec 10 '15 at 10:26
  • @chqrlie: yes, I used `float` because I was trying to reproduce the OP's result. But even with `float`, the program worked. :-) – Jay Dec 10 '15 at 10:31
2

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?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Yes, I too would like to know OS and compiler. – Martin James Dec 10 '15 at 09:58
  • @MartinJames: Compiling with `clang` on OS/X. if I use `exp(log(b)*2.0)`, I get a very small floating point value and the program says there are no roots `;-)`. Definitely not a good idea to use math functions for this. – chqrlie Dec 10 '15 at 10:24
  • OH, I'm sure that YOU compiled/linked/tested it. The thing is, the longer this goes on, the more I get this feeling that that the OP did not:( – Martin James Dec 10 '15 at 13:03
  • @MartinJames I am using Windows 10 pro and GNU GCC compiler .... Sorry for late reply ... – Akhil Raj Dec 10 '15 at 19:51
  • @AkhilRaj: do you know which C library you link to? The code would also depend on the optimisation settings and some other flags controlling floating point code generation. What are your commands for compiling and linking? Also edit your post to show the rest of the function, with the definitions of all variables. – chqrlie Dec 11 '15 at 07:34
2

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.

Tom Karzes
  • 22,815
  • 2
  • 22
  • 41
0

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?

Community
  • 1
  • 1
thepace
  • 2,221
  • 1
  • 13
  • 21