Main Content

Recognize and Avoid Round-Off Errors

When approximating a value numerically, remember that floating-point results can be sensitive to the precision used. Also, floating-point results are prone to round-off errors. The following approaches can help you recognize and avoid incorrect results.

Use Symbolic Computations When Possible

Performing computations symbolically is recommended because exact symbolic computations are not prone to round-off errors. For example, standard mathematical constants have their own symbolic representations in Symbolic Math Toolbox™:

ans =

ans =

Avoid unnecessary use of numeric approximations. A floating-point number approximates a constant; it is not the constant itself. Using this approximation, you can get incorrect results. For example, the heaviside special function returns different results for the sine of sym(pi) and the sine of the numeric approximation of pi:

ans =

ans =

Perform Calculations with Increased Precision

The Riemann hypothesis states that all nontrivial zeros of the Riemann Zeta function ζ(z) have the same real part ℜ(z) = 1/2. To locate possible zeros of the Zeta function, plot its absolute value |ζ(1/2 + iy)|. The following plot shows the first three nontrivial roots of the Zeta function |ζ(1/2 + iy)|.

syms y
fplot(abs(zeta(1/2 + i*y)), [0 30])

Use the numeric solver vpasolve to approximate the first three zeros of this Zeta function:

vpasolve(zeta(1/2 + i*y), y, 15)
vpasolve(zeta(1/2 + i*y), y, 20)
vpasolve(zeta(1/2 + i*y), y, 25)
ans =
ans =
ans =

Now, consider the same function, but slightly increase the real part, ζ(10000000012000000000+iy). According to the Riemann hypothesis, this function does not have a zero for any real value y. If you use vpasolve with the 10 significant decimal digits, the solver finds the following (nonexisting) zero of the Zeta function:

old = digits;
vpasolve(zeta(1000000001/2000000000 + i*y), y, 15)
ans =

Increasing the number of digits shows that the result is incorrect. The Zeta function ζ(10000000012000000000+iy) does not have a zero for any real value 14 < y < 15:

vpasolve(zeta(1000000001/2000000000 + i*y), y, 15)
ans =
14.1347251417347 + 0.000000000499989207306345i

For further computations, restore the default number of digits:


Compare Symbolic and Numeric Results

Bessel functions with half-integer indices return exact symbolic expressions. Approximating these expressions by floating-point numbers can produce very unstable results. For example, the exact symbolic expression for the following Bessel function is:

B = besselj(53/2, sym(pi))
B =
(351*2^(1/2)*(119409675/pi^4 - 20300/pi^2 - 315241542000/pi^6...
 + 445475704038750/pi^8 - 366812794263762000/pi^10 +...
 182947881139051297500/pi^12 - 55720697512636766610000/pi^14...
 + 10174148683695239020903125/pi^16 - 1060253389142977540073062500/pi^18...
 + 57306695683177936040949028125/pi^20 - 1331871030107060331702688875000/pi^22...
 + 8490677816932509614604641578125/pi^24 + 1))/pi^2

Use vpa to approximate this expression with the 10-digit accuracy:

vpa(B, 10)
ans =

Now, call the Bessel function with the floating-point parameter. Significant difference between these two approximations indicates that one or both results are incorrect:

besselj(53/2, pi)
ans =

Increase the numeric working precision to obtain a more accurate approximation for B:

vpa(B, 50)
ans =

Plot the Function or Expression

Plotting the results can help you recognize incorrect approximations. For example, the numeric approximation of the following Bessel function returns:

B = besselj(53/2, sym(pi));
vpa(B, 10)
ans =

Plot this Bessel function for the values of x around 53/2. The function plot shows that the approximation is incorrect:

syms x
fplot(besselj(x, sym(pi)), [26 27])