001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-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 */ 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}