001/*
002 * Java Genetic Algorithm Library (jenetics-8.0.0).
003 * Copyright (c) 2007-2024 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 */
020package io.jenetics.internal.math;
021
022import static java.lang.Double.isInfinite;
023import static java.lang.Double.isNaN;
024import static java.util.Objects.requireNonNull;
025import static io.jenetics.internal.util.Hashes.hash;
026
027import java.io.Serial;
028
029/**
030 * This class implements the the
031 * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
032 * summation algorithm</a>, which significantly reduces the numerical error when
033 * adding double values.
034 *
035 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
036 * @since 3.0
037 * @version 3.0
038 */
039public final class DoubleAdder
040        extends Number
041        implements Comparable<DoubleAdder>
042{
043        @Serial
044        private static final long serialVersionUID = 1L;
045
046        private double _sum = 0.0;
047        private double _simpleSum = 0.0;
048        private double _compensation = 0.0;
049
050        /**
051         * Create a new adder with the given default {@code value}.
052         *
053         * @param value the initial {@code value} of this adder.
054         */
055        public DoubleAdder(final double value) {
056                add(value);
057        }
058
059        /**
060         * Create a new adder with the initial value of {@code 0.0}.
061         */
062        public DoubleAdder() {
063        }
064
065        /**
066         * Reset the adder to the initial value of {@code 0.0}.
067         *
068         * @return {@code this} adder, for command chaining
069         */
070        private DoubleAdder reset() {
071                _sum = 0.0;
072                _simpleSum = 0.0;
073                _compensation = 0.0;
074                return this;
075        }
076
077        /**
078         * Set the adder to the given {@code value}.
079         *
080         * @param value the new adder value
081         * @return {@code this} adder, for command chaining
082         */
083        public DoubleAdder set(final double value) {
084                return reset().add(value);
085        }
086
087        /**
088         * Set the adder to the given {@code value}.
089         *
090         * @param value the new adder value
091         * @return {@code this} adder, for command chaining
092         * @throws java.lang.NullPointerException if the given {@code value} is
093         *         {@code null}
094         */
095        public DoubleAdder set(final DoubleAdder value) {
096                return reset().add(requireNonNull(value));
097        }
098
099        /**
100         * Add the given {@code value} to this adder, using the
101         * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
102         * summation algorithm</a>
103         *
104         * @param value the {@code value} to add
105         * @return {@code this} adder, for command chaining
106         */
107        public DoubleAdder add(final double value) {
108                addWithCompensation(value);
109                _simpleSum += value;
110                return this;
111        }
112
113        /**
114         * Add the given values to this adder.
115         *
116         * @param values the values to add.
117         * @return {@code this} adder, for command chaining
118         */
119        public DoubleAdder add(final double[] values) {
120                for (int i = values.length; --i >= 0;) {
121                        add(values[i]);
122                }
123
124                return this;
125        }
126
127        private void addWithCompensation(final double value) {
128                final double y = value - _compensation;
129                final double t = _sum + y;
130                _compensation = t - _sum - y;
131                _sum = t;
132        }
133
134        /**
135         * Add the given {@code value} to this adder, using the
136         * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
137         * summation algorithm</a>
138         *
139         * @param value the {@code value} to add
140         * @return {@code this} adder, for command chaining
141         * @throws java.lang.NullPointerException if the given {@code value} is
142         *         {@code null}
143         */
144        public DoubleAdder add(final DoubleAdder value) {
145                addWithCompensation(value._sum);
146                addWithCompensation(value._compensation);
147                _simpleSum += value._simpleSum;
148                return this;
149        }
150
151        /**
152         * Add the given {@code value} to this adder, using the
153         * <a href="http://en.wikipedia.org/wiki/Kahan_summation_algorithm">Kahan
154         * summation algorithm</a>
155         *
156         * @param other the {@code value} to add
157         * @return {@code this} adder, for command chaining
158         * @throws java.lang.NullPointerException if the given {@code value} is
159         *         {@code null}
160         */
161        public DoubleAdder combine(final DoubleAdder other) {
162                return add(other);
163        }
164
165        public double value() {
166                final double result =  _sum + _compensation;
167                return isNaN(result) && isInfinite(_simpleSum) ? _simpleSum : result;
168        }
169
170        @Override
171        public int intValue() {
172                return (int)value();
173        }
174
175        @Override
176        public long longValue() {
177                return (long)value();
178        }
179
180        @Override
181        public float floatValue() {
182                return (float)value();
183        }
184
185        @Override
186        public double doubleValue() {
187                return value();
188        }
189
190        @Override
191        public int compareTo(final DoubleAdder other) {
192                return Double.compare(doubleValue(), other.doubleValue());
193        }
194
195        /**
196         * Check if {@code this} and the {@code other} {@code DoubleAdder} maintain
197         * the same internal state.
198         *
199         * @param other the other object
200         * @return {@code true} if {@code this} and the {@code other} adder have
201         *         the same state, {@code false otherwise}
202         */
203        public boolean sameState(final DoubleAdder other) {
204                return Double.compare(_sum, other._sum) == 0 &&
205                        Double.compare(_simpleSum, other._simpleSum) == 0 &&
206                        Double.compare(_compensation, other._compensation) == 0;
207        }
208
209        @Override
210        public int hashCode() {
211                return hash(doubleValue());
212        }
213
214        @Override
215        public boolean equals(final Object obj) {
216                return obj == this ||
217                        obj instanceof DoubleAdder other &&
218                        Double.compare(doubleValue(), other.doubleValue()) == 0;
219        }
220
221        @Override
222        public String toString() {
223                return Double.toString(doubleValue());
224        }
225
226
227        /* *************************************************************************
228         * Some static helper methods.
229         **************************************************************************/
230
231        /**
232         * Return the sum of the given double array.
233         *
234         * @param values the values to sum up.
235         * @return the sum of the given {@code values}.
236         * @throws NullPointerException if the given array is {@code null}.
237         */
238        public static double sum(final double[] values) {
239                return new DoubleAdder().add(values).doubleValue();
240        }
241}