4.4 Summing Addends with Different Signs

   

 
Java Number Cruncher: The Java Programmer's Guide to Numerical Computing
By Ronald  Mak

Table of Contents
Chapter  4.   Summing Lists of Numbers

4.4 Summing Addends with Different Signs

The previous example involved addends that were all of the same sign. What happens when we sum both positive and negative numbers?

Our next two programs experiment with the following series:

graphics/04equ03.gif


which has alternating signs. [2]

[2] This equation is due to the Indian mathematician Ramanujan. We'll see more of his formulas in Chapter 13.

Program 4-7 performs a simple straight summation of the series. See Listing 4-7. The summation stops as soon as the fractions are too small to change the value of the running sum.

Listing 4-7 Summing numbers with mixed signs.
 package numbercruncher.program4_7; import numbercruncher.mathutils.AlignRight; /**  * Program 4-7: Sum Numbers with Mixed Signs  *  * Sum a sequence numbers with alternating signs.  The sum should be 0.  */ public class SumMixedSigns {     private static AlignRight ar = new AlignRight();     public static void main(String args[])     {         int     k          = 0;         int     odd        = 1;      // odd number         float   kFactorial = 1;      // k!         boolean subtract   = false;  // true if subtract, false if add         float   sum        = 0;      // running sum         float   prevSum    = -1;     // previous value of running sum         ar.print("k", 2);         ar.print("Numerator", 11);         ar.print("Factorial", 16);         ar.print("Fraction", 16);         ar.print("Running sum", 16);         ar.underline();         // Loop until the running sum stops changing.         do {             float numerator = odd*odd;             numerator += odd*numerator;             float fraction = numerator/kFactorial;             prevSum = sum;             // Add or subtract the next fraction.             if (subtract) fraction = -fraction;             sum += fraction;             ar.print(k, 2);             ar.print(numerator, 11);             ar.print(kFactorial, 16);             ar.print(fraction, 16);             ar.print(sum, 16);             ar.println();             ++k;             kFactorial *= k;             odd += 2;             subtract = !subtract;         } while (sum != prevSum);     } } 

Output:

 k  Numerator       Factorial        Fraction     Running sum -------------------------------------------------------------  0        2.0             1.0             2.0             2.0  1       36.0             1.0           -36.0           -34.0  2      150.0             2.0            75.0            41.0  3      392.0             6.0      -65.333336      -24.333336  4      810.0            24.0           33.75        9.416664  5     1452.0           120.0           -12.1      -2.6833363  6     2366.0           720.0        3.286111      0.60277486  7     3600.0          5040.0     -0.71428573     -0.11151087  8     5202.0         40320.0      0.12901786     0.017506987  9     7220.0        362880.0    -0.019896384   -0.0023893975 10     9702.0       3628800.0     0.002673611    2.8421357E-4 11    12696.0       3.99168E7   -3.1806156E-4   -3.3847988E-5 12    16250.0      4.790016E8     3.392473E-5     7.674316E-8 13    20412.0     6.2270208E9    -3.277972E-6   -3.2012288E-6 14    25230.0    8.7178289E10    2.8940693E-7   -2.9118219E-6 15    30752.0   1.30767428E12    -2.351656E-8   -2.9353384E-6 16    37026.0   2.09227885E13    1.7696494E-9   -2.9335688E-6 17    44100.0   3.55687415E14  -1.2398527E-10   -2.9336927E-6 18    52022.0    6.4023735E15    8.125424E-12   -2.9336845E-6 19    60840.0   1.21645096E17   -5.001435E-13    -2.933685E-6 20    70602.0   2.43290202E18   2.9019664E-14    -2.933685E-6 

The values of the running sum are supposed to oscillate about 0, alternating between positive and negative in step with the signs of the fractions. After the first couple of values, the running sum values should steadily decrease in magnitude. However, the pattern breaks when k = 12. The running sum's value seems smaller than expected, the next value has a greater magnitude, and all subsequent values are negative.

The pattern breaks when the exponents of the fraction and of the running sum are the same. Because the fraction and the running sum have opposite signs, cancellation error is the culprit. When k = 12, we subtract

graphics/04equ04.gif


Losing the leading significant digits throws off the remaining values of the running sum. It is also at this point that the factorial values (and hence the fraction values) begin to lose accuracy due to insufficient digits of precision.

Program 4-8 uses double arithmetic to show one solution to the cancellation problem. See Listing 4-8. It computes separate subtotals for the positive fractions and for the negative fractions, thus removing the cancellation problem. Then, it computes the correct final sum by adding together the two subtotals. So we see that, when summing numbers with mixed signs, it is better to sum the positive numbers and the negative numbers separately.

Listing 4-8 Summing numbers with mixed signs using separate positive and negative subtotals.
 package numbercruncher.program4_8; import numbercruncher.mathutils.AlignRight; /**  * Program 4-8: Sum Numbers with Mixed Signs,  *              Positive and Negative Subtotals  *  * Sum a sequence of double numbers with alternating signs.  * Compute separate positive and negative subtotals.  The final sum  * should be 0.  */ public class SumMixedSignsPosNeg {     public static void main(String args[])     {         AlignRight ar = new AlignRight();         int    k          = 0;         int    odd        = 1;   // odd number         double kFactorial = 1;   // k!         double posSum     = 0;   // running subtotal of pos fractions         double negSum     = 0;   // running subtotal of neg fractions         double prevPosSum = -1;  // previous value of positive sum         double prevNegSum = 1;   // previous value of negative sum         ar.print("k", 2);         ar.print("Fraction", 25);         ar.print("Positive subtotal", 20);         ar.print("Negative subtotal", 21);         ar.underline();         // Loop until the positive and negative subtotals         // no longer change.         do {             // Positive fraction and subtotal.             double posNumerator = odd*odd;             posNumerator += odd*posNumerator;             double posFraction = posNumerator/kFactorial;             prevPosSum = posSum;             posSum += posFraction;             ar.print(k, 2);             ar.print(posFraction, 25);             ar.print(posSum, 20);             ar.println();             ++k;             kFactorial *= k;             odd += 2;             // Negative fraction and subtotal.             double negNumerator = odd*odd;             negNumerator += odd*negNumerator;             double negFraction = -negNumerator/kFactorial;             prevNegSum = negSum;             negSum += negFraction;             ar.print(k, 2);             ar.print(negFraction, 25);             ar.print(" ", 20);             ar.print(negSum, 21);             ar.println();             ++k;             kFactorial *= k;             odd += 2;         } while ((posSum != prevPosSum)  (negSum != prevNegSum));         System.out.println("\nFinal sum = " + (posSum + negSum));     } } 

Output:

 k                 Fraction   Positive subtotal    Negative subtotal --------------------------------------------------------------------  0                      2.0                 2.0  1                    -36.0                                    -36.0  2                     75.0                77.0  3       -65.33333333333333                      -101.33333333333333  4                    33.75              110.75  5                    -12.1                      -113.43333333333332  6        3.286111111111111  114.03611111111111  7      -0.7142857142857143                      -114.14761904761903  8      0.12901785714285716  114.16512896825397  9    -0.019896384479717814                      -114.16751543209875 10     0.002673611111111111  114.16780257936507 11   -3.1806156806156807E-4                      -114.16783349366682 12     3.392473010528566E-5  114.16783650409518 13    -3.277972027972028E-6                      -114.16783677163885 14      2.89406911430721E-7  114.16783679350209 15     -2.35165579080923E-8                      -114.16783679515541 16    1.7696492770897533E-9  114.16783679527174 17  -1.2398526491663746E-10                       -114.1678367952794 18    8.125423849197927E-12  114.16783679527987 19   -5.001434484046243E-13                       -114.1678367952799 20    2.901966448410855E-14   114.1678367952799 21  -1.5923761931532594E-15                       -114.1678367952799 22    8.287361182067708E-17   114.1678367952799 23   -4.101498195323127E-18                       -114.1678367952799 Final sum = 0.0 

   
Top
 


Java Number Cruncher. The Java Programmer's Guide to Numerical Computing
Java Number Cruncher: The Java Programmers Guide to Numerical Computing
ISBN: 0130460419
EAN: 2147483647
Year: 2001
Pages: 141
Authors: Ronald Mak

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net