1: Subtractive Cancellation

Consider the quadratic equation

$$\tag*{1} a x^{2} + b x + c = 0.$$

This has two roots that can be calculated in two different ways

$$\tag*{2} x_{1,2} = \frac{-b \pm \sqrt{b^{2} -4ac}}{2a}\quad\mbox{or}\quad x_{1,2}' = \frac{-2c}{b \pm \sqrt{b^{2} -4ac}}.$$

By keeping a and b constant while decreasing the value of c, and investigating the ability for the computer to evaluate the algorithms above, one can see the effect of subtractive cancellation error propagation. The square root and its preceding term almost cancel out but according to error propagation, the error of this value gets large. Consider the fractional error,

$$\tag*{3} \begin{align} \frac{r_{c} - r} {r} \simeq \frac{s}{r}\; \mbox{max}(|\epsilon_{s}|,|\epsilon_{t}|). \end{align}$$

If r ends up small, but s is relatively large, the fractional error is also large. The first equation (2) is therefore calculating a small number with error order 1 by 1, and therefore doesn't suffer too much from the effects of subtractive cancellation but the second equation involves division of a small number by a smaller number with error order 1 and therefore will diverge.


In [6]:
from prettytable import PrettyTable
import numpy as np

def root_finder():
    a = 1
    b = 1
    crray = np.geomspace(0.1, (10 ** (-200)), num=200, endpoint=False)
    t = PrettyTable(['root1', 'root2', 'root3', 'root4'])
    for c in crray:
        root = np.sqrt((b * b) - (4 * a * c))
        #print(root)
        r1 = (-b + root) / (2 * a)
        r2 = (-b - root) / (2 * a)
        r3 = -2 * c / (b + root)
        if b - root == 0:
            r4 = 'div0'
        else:
            r4 = -2 * c / (b - root)
        t.add_row([r1, r2, r3, r4])
    print(t)

root_finder()


0.774596669241
0.979559503976
0.997951315461
0.999792950132
0.99997905721
0.99999788149
0.999999785696
0.999999978321
0.999999997807
0.999999999778
0.999999999978
0.999999999998
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
1.0
+--------------------+-----------------+---------------------+-----------------+
|       root1        |      root2      |        root3        |      root4      |
+--------------------+-----------------+---------------------+-----------------+
|  -0.112701665379   | -0.887298334621 |   -0.112701665379   | -0.887298334621 |
|  -0.010220248012   | -0.989779751988 |   -0.010220248012   | -0.989779751988 |
| -0.00102434226937  | -0.998975657731 |  -0.00102434226937  | -0.998975657731 |
| -0.00010352493408  | -0.999896475066 |  -0.00010352493408  | -0.999896475066 |
| -1.04713951306e-05 | -0.999989528605 |  -1.04713951306e-05 | -0.999989528607 |
| -1.05925484722e-06 | -0.999998940745 |  -1.0592548472e-06  |  -0.99999894072 |
| -1.07151941986e-07 | -0.999999892848 |  -1.07151942005e-07 | -0.999999893029 |
| -1.08392692599e-08 | -0.999999989161 |  -1.08392692577e-08 | -0.999999988955 |
| -1.09647818602e-09 | -0.999999998904 |  -1.09647819735e-09 |  -1.00000000923 |
| -1.10917497409e-10 | -0.999999999889 |  -1.10917481539e-10 | -0.999999856806 |
| -1.12201914426e-11 | -0.999999999989 |  -1.12201845431e-11 | -0.999999385073 |
| -1.13503650923e-12 | -0.999999999999 |  -1.13501081567e-12 | -0.999977363236 |
| -1.14852571897e-13 |       -1.0      |  -1.1481536215e-13  | -0.999676021641 |
| -1.16018306073e-14 |       -1.0      |  -1.16144861384e-14 |  -1.00109082191 |
| -1.16573417586e-15 |       -1.0      |  -1.17489755494e-15 |  -1.00786060774 |
| -1.11022302463e-16 |       -1.0      |  -1.18850222744e-16 |  -1.07050763772 |
|        0.0         |       -1.0      |  -1.20226443462e-17 |       div0      |
|        0.0         |       -1.0      |  -1.21618600065e-18 |       div0      |
|        0.0         |       -1.0      |  -1.23026877081e-19 |       div0      |
|        0.0         |       -1.0      |  -1.24451461177e-20 |       div0      |
|        0.0         |       -1.0      |  -1.25892541179e-21 |       div0      |
|        0.0         |       -1.0      |  -1.27350308102e-22 |       div0      |
|        0.0         |       -1.0      |  -1.28824955169e-23 |       div0      |
|        0.0         |       -1.0      |  -1.30316677845e-24 |       div0      |
|        0.0         |       -1.0      |  -1.31825673856e-25 |       div0      |
|        0.0         |       -1.0      |  -1.33352143216e-26 |       div0      |
|        0.0         |       -1.0      |  -1.34896288259e-27 |       div0      |
|        0.0         |       -1.0      |  -1.36458313659e-28 |       div0      |
|        0.0         |       -1.0      |  -1.3803842646e-29  |       div0      |
|        0.0         |       -1.0      |  -1.39636836106e-30 |       div0      |
|        0.0         |       -1.0      |  -1.41253754462e-31 |       div0      |
|        0.0         |       -1.0      |  -1.42889395851e-32 |       div0      |
|        0.0         |       -1.0      |  -1.44543977075e-33 |       div0      |
|        0.0         |       -1.0      |  -1.46217717446e-34 |       div0      |
|        0.0         |       -1.0      |  -1.47910838817e-35 |       div0      |
|        0.0         |       -1.0      |  -1.49623565609e-36 |       div0      |
|        0.0         |       -1.0      |  -1.51356124844e-37 |       div0      |
|        0.0         |       -1.0      |  -1.53108746168e-38 |       div0      |
|        0.0         |       -1.0      |  -1.54881661891e-39 |       div0      |
|        0.0         |       -1.0      |  -1.56675107011e-40 |       div0      |
|        0.0         |       -1.0      |  -1.58489319246e-41 |       div0      |
|        0.0         |       -1.0      |  -1.60324539069e-42 |       div0      |
|        0.0         |       -1.0      |  -1.62181009736e-43 |       div0      |
|        0.0         |       -1.0      |  -1.6405897732e-44  |       div0      |
|        0.0         |       -1.0      |  -1.65958690744e-45 |       div0      |
|        0.0         |       -1.0      |  -1.67880401812e-46 |       div0      |
|        0.0         |       -1.0      |  -1.69824365246e-47 |       div0      |
|        0.0         |       -1.0      |  -1.71790838716e-48 |       div0      |
|        0.0         |       -1.0      |  -1.73780082875e-49 |       div0      |
|        0.0         |       -1.0      |  -1.75792361396e-50 |       div0      |
|        0.0         |       -1.0      |  -1.77827941004e-51 |       div0      |
|        0.0         |       -1.0      |  -1.79887091513e-52 |       div0      |
|        0.0         |       -1.0      |  -1.81970085861e-53 |       div0      |
|        0.0         |       -1.0      |  -1.84077200147e-54 |       div0      |
|        0.0         |       -1.0      |  -1.86208713666e-55 |       div0      |
|        0.0         |       -1.0      |  -1.88364908949e-56 |       div0      |
|        0.0         |       -1.0      |  -1.90546071796e-57 |       div0      |
|        0.0         |       -1.0      |  -1.92752491319e-58 |       div0      |
|        0.0         |       -1.0      |  -1.94984459976e-59 |       div0      |
|        0.0         |       -1.0      |  -1.97242273611e-60 |       div0      |
|        0.0         |       -1.0      |  -1.99526231497e-61 |       div0      |
|        0.0         |       -1.0      |  -2.01836636368e-62 |       div0      |
|        0.0         |       -1.0      |  -2.04173794467e-63 |       div0      |
|        0.0         |       -1.0      |  -2.06538015581e-64 |       div0      |
|        0.0         |       -1.0      |  -2.08929613085e-65 |       div0      |
|        0.0         |       -1.0      |  -2.11348903984e-66 |       div0      |
|        0.0         |       -1.0      |  -2.1379620895e-67  |       div0      |
|        0.0         |       -1.0      |  -2.16271852373e-68 |       div0      |
|        0.0         |       -1.0      |  -2.18776162395e-69 |       div0      |
|        0.0         |       -1.0      |  -2.21309470961e-70 |       div0      |
|        0.0         |       -1.0      |  -2.23872113857e-71 |       div0      |
|        0.0         |       -1.0      |  -2.26464430759e-72 |       div0      |
|        0.0         |       -1.0      |  -2.29086765277e-73 |       div0      |
|        0.0         |       -1.0      |  -2.31739464997e-74 |       div0      |
|        0.0         |       -1.0      |  -2.34422881532e-75 |       div0      |
|        0.0         |       -1.0      |  -2.37137370566e-76 |       div0      |
|        0.0         |       -1.0      |  -2.39883291902e-77 |       div0      |
|        0.0         |       -1.0      |  -2.42661009508e-78 |       div0      |
|        0.0         |       -1.0      |  -2.45470891569e-79 |       div0      |
|        0.0         |       -1.0      |  -2.4831331053e-80  |       div0      |
|        0.0         |       -1.0      |  -2.51188643151e-81 |       div0      |
|        0.0         |       -1.0      |  -2.54097270555e-82 |       div0      |
|        0.0         |       -1.0      |  -2.57039578277e-83 |       div0      |
|        0.0         |       -1.0      |  -2.60015956317e-84 |       div0      |
|        0.0         |       -1.0      |  -2.6302679919e-85  |       div0      |
|        0.0         |       -1.0      |  -2.6607250598e-86  |       div0      |
|        0.0         |       -1.0      |  -2.69153480393e-87 |       div0      |
|        0.0         |       -1.0      |  -2.72270130808e-88 |       div0      |
|        0.0         |       -1.0      |  -2.75422870334e-89 |       div0      |
|        0.0         |       -1.0      |  -2.78612116863e-90 |       div0      |
|        0.0         |       -1.0      |  -2.81838293126e-91 |       div0      |
|        0.0         |       -1.0      |  -2.8510182675e-92  |       div0      |
|        0.0         |       -1.0      |  -2.88403150313e-93 |       div0      |
|        0.0         |       -1.0      |   -2.917427014e-94  |       div0      |
|        0.0         |       -1.0      |  -2.95120922667e-95 |       div0      |
|        0.0         |       -1.0      |  -2.98538261892e-96 |       div0      |
|        0.0         |       -1.0      |  -3.0199517204e-97  |       div0      |
|        0.0         |       -1.0      |  -3.05492111322e-98 |       div0      |
|        0.0         |       -1.0      |  -3.09029543251e-99 |       div0      |
|        0.0         |       -1.0      | -3.12607936712e-100 |       div0      |
|        0.0         |       -1.0      | -3.16227766017e-101 |       div0      |
|        0.0         |       -1.0      | -3.19889510969e-102 |       div0      |
|        0.0         |       -1.0      |  -3.2359365693e-103 |       div0      |
|        0.0         |       -1.0      | -3.27340694879e-104 |       div0      |
|        0.0         |       -1.0      | -3.31131121483e-105 |       div0      |
|        0.0         |       -1.0      | -3.34965439158e-106 |       div0      |
|        0.0         |       -1.0      | -3.38844156139e-107 |       div0      |
|        0.0         |       -1.0      | -3.42767786546e-108 |       div0      |
|        0.0         |       -1.0      | -3.46736850453e-109 |       div0      |
|        0.0         |       -1.0      | -3.50751873953e-110 |       div0      |
|        0.0         |       -1.0      | -3.54813389234e-111 |       div0      |
|        0.0         |       -1.0      | -3.58921934645e-112 |       div0      |
|        0.0         |       -1.0      |  -3.6307805477e-113 |       div0      |
|        0.0         |       -1.0      | -3.67282300498e-114 |       div0      |
|        0.0         |       -1.0      | -3.71535229097e-115 |       div0      |
|        0.0         |       -1.0      | -3.75837404288e-116 |       div0      |
|        0.0         |       -1.0      | -3.80189396321e-117 |       div0      |
|        0.0         |       -1.0      | -3.84591782045e-118 |       div0      |
|        0.0         |       -1.0      | -3.89045144994e-119 |       div0      |
|        0.0         |       -1.0      | -3.93550075456e-120 |       div0      |
|        0.0         |       -1.0      | -3.98107170553e-121 |       div0      |
|        0.0         |       -1.0      | -4.02717034325e-122 |       div0      |
|        0.0         |       -1.0      | -4.07380277804e-123 |       div0      |
|        0.0         |       -1.0      | -4.12097519097e-124 |       div0      |
|        0.0         |       -1.0      |  -4.1686938347e-125 |       div0      |
|        0.0         |       -1.0      | -4.21696503429e-126 |       div0      |
|        0.0         |       -1.0      | -4.26579518802e-127 |       div0      |
|        0.0         |       -1.0      | -4.31519076828e-128 |       div0      |
|        0.0         |       -1.0      |  -4.3651583224e-129 |       div0      |
|        0.0         |       -1.0      | -4.41570447353e-130 |       div0      |
|        0.0         |       -1.0      | -4.46683592151e-131 |       div0      |
|        0.0         |       -1.0      | -4.51855944375e-132 |       div0      |
|        0.0         |       -1.0      | -4.57088189615e-133 |       div0      |
|        0.0         |       -1.0      | -4.62381021399e-134 |       div0      |
|        0.0         |       -1.0      | -4.67735141287e-135 |       div0      |
|        0.0         |       -1.0      | -4.73151258961e-136 |       div0      |
|        0.0         |       -1.0      | -4.78630092323e-137 |       div0      |
|        0.0         |       -1.0      | -4.84172367584e-138 |       div0      |
|        0.0         |       -1.0      | -4.89778819368e-139 |       div0      |
|        0.0         |       -1.0      | -4.95450190805e-140 |       div0      |
|        0.0         |       -1.0      | -5.01187233627e-141 |       div0      |
|        0.0         |       -1.0      | -5.06990708275e-142 |       div0      |
|        0.0         |       -1.0      | -5.12861383991e-143 |       div0      |
|        0.0         |       -1.0      | -5.18800038929e-144 |       div0      |
|        0.0         |       -1.0      |  -5.2480746025e-145 |       div0      |
|        0.0         |       -1.0      | -5.30884444231e-146 |       div0      |
|        0.0         |       -1.0      |  -5.3703179637e-147 |       div0      |
|        0.0         |       -1.0      | -5.43250331492e-148 |       div0      |
|        0.0         |       -1.0      | -5.49540873858e-149 |       div0      |
|        0.0         |       -1.0      |  -5.5590425727e-150 |       div0      |
|        0.0         |       -1.0      |  -5.6234132519e-151 |       div0      |
|        0.0         |       -1.0      | -5.68852930844e-152 |       div0      |
|        0.0         |       -1.0      | -5.75439937337e-153 |       div0      |
|        0.0         |       -1.0      | -5.82103217771e-154 |       div0      |
|        0.0         |       -1.0      | -5.88843655356e-155 |       div0      |
|        0.0         |       -1.0      | -5.95662143529e-156 |       div0      |
|        0.0         |       -1.0      | -6.02559586074e-157 |       div0      |
|        0.0         |       -1.0      |  -6.0953689724e-158 |       div0      |
|        0.0         |       -1.0      | -6.16595001861e-159 |       div0      |
|        0.0         |       -1.0      | -6.23734835482e-160 |       div0      |
|        0.0         |       -1.0      |  -6.3095734448e-161 |       div0      |
|        0.0         |       -1.0      | -6.38263486191e-162 |       div0      |
|        0.0         |       -1.0      | -6.45654229035e-163 |       div0      |
|        0.0         |       -1.0      | -6.53130552647e-164 |       div0      |
|        0.0         |       -1.0      | -6.60693448008e-165 |       div0      |
|        0.0         |       -1.0      | -6.68343917569e-166 |       div0      |
|        0.0         |       -1.0      | -6.76082975392e-167 |       div0      |
|        0.0         |       -1.0      | -6.83911647281e-168 |       div0      |
|        0.0         |       -1.0      | -6.91830970919e-169 |       div0      |
|        0.0         |       -1.0      | -6.99841996002e-170 |       div0      |
|        0.0         |       -1.0      | -7.07945784384e-171 |       div0      |
|        0.0         |       -1.0      | -7.16143410213e-172 |       div0      |
|        0.0         |       -1.0      | -7.24435960075e-173 |       div0      |
|        0.0         |       -1.0      | -7.32824533139e-174 |       div0      |
|        0.0         |       -1.0      | -7.41310241301e-175 |       div0      |
|        0.0         |       -1.0      | -7.49894209332e-176 |       div0      |
|        0.0         |       -1.0      | -7.58577575029e-177 |       div0      |
|        0.0         |       -1.0      | -7.67361489362e-178 |       div0      |
|        0.0         |       -1.0      | -7.76247116629e-179 |       div0      |
|        0.0         |       -1.0      |  -7.8523563461e-180 |       div0      |
|        0.0         |       -1.0      | -7.94328234724e-181 |       div0      |
|        0.0         |       -1.0      | -8.03526122186e-182 |       div0      |
|        0.0         |       -1.0      | -8.12830516164e-183 |       div0      |
|        0.0         |       -1.0      | -8.22242649947e-184 |       div0      |
|        0.0         |       -1.0      | -8.31763771103e-185 |       div0      |
|        0.0         |       -1.0      | -8.41395141645e-186 |       div0      |
|        0.0         |       -1.0      | -8.51138038202e-187 |       div0      |
|        0.0         |       -1.0      | -8.60993752185e-188 |       div0      |
|        0.0         |       -1.0      | -8.70963589956e-189 |       div0      |
|        0.0         |       -1.0      | -8.81048873008e-190 |       div0      |
|        0.0         |       -1.0      | -8.91250938134e-191 |       div0      |
|        0.0         |       -1.0      | -9.01571137606e-192 |       div0      |
|        0.0         |       -1.0      | -9.12010839356e-193 |       div0      |
|        0.0         |       -1.0      | -9.22571427155e-194 |       div0      |
|        0.0         |       -1.0      | -9.33254300797e-195 |       div0      |
|        0.0         |       -1.0      | -9.44060876286e-196 |       div0      |
|        0.0         |       -1.0      | -9.54992586021e-197 |       div0      |
|        0.0         |       -1.0      |  -9.6605087899e-198 |       div0      |
|        0.0         |       -1.0      | -9.77237220956e-199 |       div0      |
|        0.0         |       -1.0      | -9.88553094657e-200 |       div0      |
+--------------------+-----------------+---------------------+-----------------+

The code above shows this effect (compare columns 2 and 4). Notice how the the last column diverges. Additionally the second equation appears to be better at calculating the 'non-cancelling' root, returning a small value rather than zero, because of the nature of error propagation when dividing.

Next consider three ways of representing an expression in terms of sums.

$$\tag*{4} S_{N}^{(1)} = \sum_{n=1}^{2N} (-1)^{n} \frac{n}{n+1}.$$$$\tag*{5} S_{N}^{(2)} = - \sum_{n=1}^{N} \frac{2n-1}{2n} + \sum_{n=1}^{N} \frac{2n}{2n+1} .$$$$\tag*{6} S_{N}^{(3)} = \sum_{n=1}^{N} \frac{1}{2n(2n+1)} .$$

If we assume the last one is correct and calculate how the other two differ, we run into subtractive cancellation issues, causing increasingly large errors for large N.


In [10]:
import numpy as np
import matplotlib.pyplot as plt

def sum_1(n):
    outsum = 0
    outarray = np.zeros((n,))
    ii = (i for i in range(1, 2*n+1) if i % 2 != 0)
    for i in ii:
        outsum += ((-1) ** i) * i / (i + 1)
        outsum += ((-1) ** (i+1)) * (i+1) / (i+1 + 1)
        b = (int((i+1)/2))-1
        outarray[b] = outsum
    return outarray

def sum_2(n):
    outsum = 0
    outarray = np.zeros((n,))
    for i in range(1, n+1):
        outsum -= (2 * i - 1) / (2 * i)
        outsum += (2 * i) / (2 * i + 1)
        outarray[(i-1)] = outsum
    return outarray

def sum_3(n):
    outsum = 0
    outarray = np.zeros((n,))
    for i in range(1, n+1):
        outsum += 1 / (2 * i * (2 * i + 1))
        outarray[(i-1)] = outsum
    return outarray


n = 1000000
method_1 = sum_1(n)
method_2 = sum_2(n)
method_3 = sum_3(n)
error_1 = abs(np.subtract(method_1, method_3))
error_2 = abs(np.subtract(method_2, method_3))
#print(method_1)
#print(method_2)
#print(method_3)
relerror_1 = np.divide(error_1, method_3)
relerror_2 = np.divide(error_2, method_3)
mil = np.arange(1, n+1, 1)
#print(mil)
logerror_1 = np.log10(relerror_1)
logerror_2 = np.log10(relerror_2)
logmil = np.log10(mil)
plt.xlabel = ('logN')
plt.ylabel = ('SN')
#plt.plot(logmil, logerror_1, '-b', lw=1)
plt.plot(logmil, logerror_2, '-r', lw=1)
plt.grid(True)
plt.show()


[ 0.16666667  0.21666667  0.24047619 ...,  0.30685257  0.30685257
  0.30685257]
[ 0.16666667  0.21666667  0.24047619 ...,  0.30685257  0.30685257
  0.30685257]
[ 0.16666667  0.21666667  0.24047619 ...,  0.30685257  0.30685257
  0.30685257]
[      1       2       3 ...,  999998  999999 1000000]
/home/matthew/anaconda3/envs/physics/lib/python3.6/site-packages/ipykernel_launcher.py:46: RuntimeWarning: divide by zero encountered in log10
/home/matthew/anaconda3/envs/physics/lib/python3.6/site-packages/ipykernel_launcher.py:47: RuntimeWarning: divide by zero encountered in log10

The code above generates log-log graphs for N against relative error for the first two sums. Plotting them together makes it hard to distinguish between the two so I kept them separate (one is currently commented out). Generally both graphs show that the log error is linearly dependent on log N. The error seems to be more unstable for large N for the second sum. This demonstrates the dangers that come with calculating expressions via large sums. If the summation includes an alternating sign, we are effectively calculating the sum of many differences, each difference with a relative error discussed before. As N increases, we are taking the difference between larger and larger numbers.

This is most easily seen in the first sum. The difference is small, however the fractional error is equal to the product of the errors in storing the input numbers and from equation (3),

$$ \frac{s}{r}$$

s is of order 1 and r is small.


In [ ]: