Class Sum

  • All Implemented Interfaces:
    java.util.function.DoubleConsumer, java.util.function.DoubleSupplier

    public final class Sum
    extends java.lang.Object
    implements java.util.function.DoubleSupplier, java.util.function.DoubleConsumer
    Class providing accurate floating-point sums and linear combinations. This class uses techniques to mitigate round off errors resulting from standard floating-point operations, increasing the overall accuracy of results at the cost of a moderate increase in the number of computations. This functionality can be viewed as filling the gap between standard floating point operations (fast but prone to round off errors) and BigDecimal (perfectly accurate but slow).

    Usage

    This class use a builder pattern in order to maximize the flexibility of the API. Typical use involves constructing an instance from one of the factory methods, adding any number of single value terms and/or products, and then extracting the computed sum. Convenience methods exist for adding multiple values or products at once. The examples below demonstrate some simple use cases.

     // compute the sum a1 + a2 + a3 + a4
     Sum sum = Sum.of(a1);
          .add(a2)
          .add(a3)
          .add(a4);
     double result = sum.getAsDouble();
    
     // same as above but using the varargs factory method
     double result = Sum.of(a1, a2, a3, a4).getAsDouble();
    
     // compute the dot product of two arrays of the same length, a and b
     Sum sum = Sum.create();
     for (int i = 0; i < a.length; ++i) {
          sum.addProduct(a[i], b[i]);
     }
     double result = sum.getAsDouble();
    
     // same as above but using a convenience factory method
     double result = Sum.ofProducts(a, b).getAsDouble();
     

    It is worth noting that this class is designed to reduce floating point errors across a sequence of operations and not just a single add or multiply. The standard IEEE floating point operations already produce the most accurate results possible given two arguments and this class does not improve on them. Rather, it tracks the errors inherent with each operation and uses them to reduce the error of the overall result. Therefore, this class is only beneficial in cases involving 3 or more floating point operations. Code such as Sum.of(a, b).getAsDouble() and Sum.create().addProduct(a, b).getAsDouble() only adds overhead with no benefit.

    Implementation Notes

    This class internally uses the Sum2S and Dot2S algorithms described in Accurate Sum and Dot Product by Takeshi Ogita, Siegfried M. Rump, and Shin'ichi Oishi (SIAM J. Sci. Comput, 2005). These are compensated summation and multiplication algorithms chosen here for their good balance of precision and performance. Future releases may choose to use different algorithms.

    Results follow the IEEE 754 rules for addition: For example, if any input value is Double.NaN, the result is Double.NaN.

    Instances of this class are mutable and not safe for use by multiple threads.

    • Field Summary

      Fields 
      Modifier and Type Field Description
      private double comp
      Compensation value.
      private double sum
      Standard sum.
    • Constructor Summary

      Constructors 
      Modifier Constructor Description
      private Sum​(double initialValue)
      Constructs a new instance with the given initial value.
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      void accept​(double value)
      Adds a single term to this sum.
      Sum add​(double t)
      Adds a single term to this sum.
      Sum add​(double... terms)
      Adds values from the given array to the sum.
      private Sum add​(double s, double c)
      Adds the sum and compensation to this sum.
      Sum add​(Sum other)
      Adds another sum to this sum.
      Sum addProduct​(double a, double b)
      Adds the high-accuracy product \( a b \) to this sum.
      Sum addProducts​(double[] a, double[] b)
      Adds \( \sum_i a_i b_i \) to this sum.
      static Sum create()
      Creates a new instance with an initial value of zero.
      double getAsDouble()
      Gets the sum value.
      static Sum of​(double a)
      Creates an instance initialized to the given value.
      static Sum of​(double... values)
      Creates an instance containing the sum of the given values.
      static Sum ofProducts​(double[] a, double[] b)
      Creates a new instance containing \( \sum_i a_i b_i \).
      Sum subtract​(Sum other)
      Subtracts another sum from this sum.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
      • Methods inherited from interface java.util.function.DoubleConsumer

        andThen
    • Field Detail

      • sum

        private double sum
        Standard sum.
      • comp

        private double comp
        Compensation value.
    • Constructor Detail

      • Sum

        private Sum​(double initialValue)
        Constructs a new instance with the given initial value.
        Parameters:
        initialValue - Initial value.
    • Method Detail

      • add

        public Sum add​(double t)
        Adds a single term to this sum.
        Parameters:
        t - Value to add.
        Returns:
        this instance.
      • add

        public Sum add​(double... terms)
        Adds values from the given array to the sum.
        Parameters:
        terms - Terms to add.
        Returns:
        this instance.
      • addProduct

        public Sum addProduct​(double a,
                              double b)
        Adds the high-accuracy product \( a b \) to this sum.
        Parameters:
        a - Factor
        b - Factor.
        Returns:
        this instance
      • addProducts

        public Sum addProducts​(double[] a,
                               double[] b)
        Adds \( \sum_i a_i b_i \) to this sum.
        Parameters:
        a - Factors.
        b - Factors.
        Returns:
        this instance.
        Throws:
        java.lang.IllegalArgumentException - if the arrays do not have the same length.
      • add

        public Sum add​(Sum other)
        Adds another sum to this sum.
        Parameters:
        other - Sum to add.
        Returns:
        this instance.
      • subtract

        public Sum subtract​(Sum other)
        Subtracts another sum from this sum.
        Parameters:
        other - Sum to subtract.
        Returns:
        this instance.
        Since:
        1.2
      • add

        private Sum add​(double s,
                        double c)
        Adds the sum and compensation to this sum.

        This is a utility method to extract both values from a sum before addition to ensure there are no issues when adding a sum to itself.

        This method sums the values in double-double precision. This enforces symmetry when combining sums and maximises the available precision.

        Parameters:
        s - Sum.
        c - Compensation.
        Returns:
        this instance.
      • accept

        public void accept​(double value)
        Adds a single term to this sum. This is equivalent to add(double).
        Specified by:
        accept in interface java.util.function.DoubleConsumer
        Parameters:
        value - Value to add.
        See Also:
        add(double)
      • getAsDouble

        public double getAsDouble()
        Gets the sum value.
        Specified by:
        getAsDouble in interface java.util.function.DoubleSupplier
        Returns:
        the sum value.
      • create

        public static Sum create()
        Creates a new instance with an initial value of zero.
        Returns:
        a new instance.
      • of

        public static Sum of​(double a)
        Creates an instance initialized to the given value.
        Parameters:
        a - Initial value.
        Returns:
        a new instance.
      • of

        public static Sum of​(double... values)
        Creates an instance containing the sum of the given values.
        Parameters:
        values - Values to add.
        Returns:
        a new instance.
      • ofProducts

        public static Sum ofProducts​(double[] a,
                                     double[] b)
        Creates a new instance containing \( \sum_i a_i b_i \).
        Parameters:
        a - Factors.
        b - Factors.
        Returns:
        a new instance.