DoubleAdder.java
001 /*
002  * Java GPX Library (jpx-3.1.0).
003  * Copyright (c) 2016-2023 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.jpx.geom;
021 
022 import static java.lang.Double.isInfinite;
023 import static java.lang.Double.isNaN;
024 import static java.util.Objects.requireNonNull;
025 
026 import java.io.Serial;
027 
028 /**
029  * This class implements the the
030  * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
031  * summation algorithm</a>, which significantly reduces the numerical error when
032  * adding double values.
033  *
034  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
035  @since 1.0
036  @version 1.0
037  */
038 final class DoubleAdder
039     extends Number
040     implements Comparable<DoubleAdder>
041 {
042     @Serial
043     private static final long serialVersionUID = 1L;
044 
045     private double _sum = 0.0;
046     private double _simpleSum = 0.0;
047     private double _compensation = 0.0;
048 
049     /**
050      * Create a new adder with the initial value of {@code 0.0}.
051      */
052 
053     DoubleAdder() {
054     }
055 
056     /**
057      * Reset the adder to the initial value of {@code 0.0}.
058      *
059      @return {@code this} adder, for command chaining
060      */
061     private DoubleAdder reset() {
062         _sum = 0.0;
063         _simpleSum = 0.0;
064         _compensation = 0.0;
065         return this;
066     }
067 
068     /**
069      * Set the adder to the given {@code value}.
070      *
071      @param value the new adder value
072      @return {@code this} adder, for command chaining
073      @throws java.lang.NullPointerException if the given {@code value} is
074      *         {@code null}
075      */
076     public DoubleAdder set(final DoubleAdder value) {
077         return reset().add(requireNonNull(value));
078     }
079 
080     /**
081      * Add the given {@code value} to this adder, using the
082      * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
083      * summation algorithm</a>
084      *
085      @param value the {@code value} to add
086      @return {@code this} adder, for command chaining
087      */
088     public DoubleAdder add(final double value) {
089         addWithCompensation(value);
090         _simpleSum += value;
091         return this;
092     }
093 
094     /**
095      * Add the given values to this adder.
096      *
097      @param values the values to add.
098      @return {@code this} adder, for command chaining
099      */
100     public DoubleAdder add(final double[] values) {
101         for (int i = values.length; --i >= 0;) {
102             add(values[i]);
103         }
104 
105         return this;
106     }
107 
108     private void addWithCompensation(final double value) {
109         final double y = value - _compensation;
110         final double t = _sum + y;
111         _compensation = (t - _sum- y;
112         _sum = t;
113     }
114 
115     /**
116      * Add the given {@code value} to this adder, using the
117      * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
118      * summation algorithm</a>
119      *
120      @param value the {@code value} to add
121      @return {@code this} adder, for command chaining
122      @throws java.lang.NullPointerException if the given {@code value} is
123      *         {@code null}
124      */
125     public DoubleAdder add(final DoubleAdder value) {
126         addWithCompensation(value._sum);
127         addWithCompensation(value._compensation);
128         _simpleSum += value._simpleSum;
129         return this;
130     }
131 
132     /**
133      * Add the given {@code value} to this adder, using the
134      * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
135      * summation algorithm</a>
136      *
137      @param other the {@code value} to add
138      @return {@code this} adder, for command chaining
139      @throws java.lang.NullPointerException if the given {@code value} is
140      *         {@code null}
141      */
142     public DoubleAdder combine(final DoubleAdder other) {
143         return add(other);
144     }
145 
146     public double value() {
147         final double result =  _sum + _compensation;
148         return isNaN(result&& isInfinite(_simpleSum? _simpleSum : result;
149     }
150 
151     @Override
152     public int intValue() {
153         return (int)value();
154     }
155 
156     @Override
157     public long longValue() {
158         return (long)value();
159     }
160 
161     @Override
162     public float floatValue() {
163         return (float)value();
164     }
165 
166     @Override
167     public double doubleValue() {
168         return value();
169     }
170 
171     @Override
172     public int compareTo(final DoubleAdder other) {
173         return Double.compare(doubleValue(), other.doubleValue());
174     }
175 
176     @Override
177     public int hashCode() {
178         return Double.hashCode(doubleValue());
179     }
180 
181     @Override
182     public boolean equals(final Object obj) {
183         return obj instanceof DoubleAdder &&
184             Double.compare(doubleValue()((DoubleAdder)obj).doubleValue()) == 0;
185     }
186 
187     @Override
188     public String toString() {
189         return Double.toString(doubleValue());
190     }
191 
192 
193     /* *************************************************************************
194      * Some static helper methods.
195      **************************************************************************/
196 
197     /**
198      * Return the sum of the given double array.
199      *
200      @param values the values to sum up.
201      @return the sum of the given {@code values}.
202      @throws NullPointerException if the given array is {@code null}.
203      */
204     public static double sum(final double[] values) {
205         return new DoubleAdder().add(values).doubleValue();
206     }
207 }