This always comes up. In English, ^ if often used to mean 'raised to
the power of'. The rest of the context makes this clear. In fact only
in C code is ^ used for exclusive-or.
I noticed yesterday that even otherwise respected book authors
get this wrong. Steve McConnell's _Code Complete_ contains the
following code on page 194 labeled as a "C Example":
/* Compute roots of a quadratic equation.
This assumes that (b^2-4*a*c) is positive. */
Temp = sqrt( b^2 - 4*a*c );
root[0] = ( -b + Temp ) / ( 2 * a );
root[1] = ( -b - Temp ) / ( 2 * a );
It will, of course, compute nothing of the sort and in fact b^2
is a constraint violation if 'b' is declared as a floating-point
type.
Even if this were done:
Temp = sqrt( b*b - 4*a*c );
instead of this:
Temp = sqrt( b^2 - 4*a*c );
it's still a very, very poor way to calculate the quadratic formula
(if b*b is about equal to 4*a*c then up to half of the digits of
precision are lost).
See:
http://www.physics.ohio-state.edu/~dws/grouplinks/floating_point_math.pdf
pages 180-182
Still plenty of room for improvement with this method, but it is
better than the naive:
#include <stdio.h>
#include <math.h>
void rootcalc(double a, double b, double c, double *br1,
double *br2, double *gr1, double *gr2)
{
double four_a_c = 4.0 * a * c;
double temp = sqrt(b * b - four_a_c);
*br1 = (-b + temp) / (2.0 * a);
*br2 = (-b - temp) / (2.0 * a);
*gr1 = -2.0 * c / (b + temp);
*gr2 = -2.0 * c / (b - temp);
printf("y = %23.18gx^2 + %23.18gx + %23.18g\n", a, b, c);
printf("naive roots=%23.18g %23.18g\ncareful roots=%23.18g %23.18g
\n",
*br1, *br2, *gr1, *gr2);
printf("relative errors = %23.18g %23.18g, 4*a*c = %23.18g\n\n",
(*gr1 - *br1) / *gr1, (*br2 - *gr2) / *br2, four_a_c);
}
int main(void)
{
double a,
b,
c;
double br1=0,
br2=0;
double gr1=0,
gr2=0;
double temp;
double four_a_c;
int n;
a = 1.0;
b = 1.0;
c = 1.0;
for (n = 1; n <= 18; n++) {
c /= 10.0;
rootcalc(a, b, c, &br1, &br2, &gr1, &gr2);
}
rootcalc(1.0, 5000000.0, 0.00001, &br1, &br2, &gr1, &gr2);
rootcalc(6.0, 5.0, -4.0, &br1, &br2, &gr1, &gr2);
rootcalc(6.0e30, 5.0e30, -4.0e30, &br1, &br2, &gr1, &gr2);
rootcalc(1.0, -1.0e5, 1.0, &br1, &br2, &gr1, &gr2);
rootcalc(1.0, -4.0, 3.999999, &br1, &br2, &gr1, &gr2);
rootcalc(1.0e-30, -1.0e30, 1.0e30, &br1, &br2, &gr1, &gr2);
/* Linear degenerate case left as an exercise for the reader: */
rootcalc(0.0, 1.0, 1.0, &br1, &br2, &gr1, &gr2);
/* Constant degenerate case left as an exercise for the reader: */
rootcalc(0.0, 0.0, 1.0, &br1, &br2, &gr1, &gr2);
return 0;
}