With integers:
As long as there is no overflow, +,-,*
is always exact.
With division, the result is truncated and often not equal to the mathematical answer.
ia,ib,ic
, multiplying before dividing ia*ib/ic
vs ia*(ib/ic)
is better as the quotient is based on more bits of the product ia*ib
than ib
.
With floating point:
Issues are subtle. Again, as long as no over/underflow, the order or *,/
sequence make less impact than with integers. FP */-
is akin to adding/subtracting logs. Typical results are within 0.5 ULP of the mathematically correct answer.
With FP and +,-
the result of fa,fb,fc
can have significant differences than the mathematical correct one when 1) values are far apart in magnitude or 2) subtracting values that are nearly equal and the error in a prior calculation now become significant.
Consider the quadratic equation:
double d = sqrt(b*b - 4*a/c); // assume b*b - 4*a/c >= 0
double root1 = (-b + d)/(2*a);
double root2 = (-b - d)/(2*a);
Versus
double d = sqrt(b*b - 4*a/c); // assume b*b - 4*a/c >= 0
double root1 = (b < 0) ? (-b + d)/(2*a) : (-b - d)/(2*a)
double root2 = c/(a*root1); // assume a*root1 != 0
The 2nd has much better root2
precision result when one root is near 0 and |b|
is nearly d
. This is because the b,d
subtraction cancels many bits of significance allowing the error in the calculation of d
to become significant.