Reputation: 477
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
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
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
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
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