001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 package org.apache.commons.math3.stat.descriptive; 018 019 import java.io.Serializable; 020 021 import org.apache.commons.math3.exception.MathIllegalStateException; 022 import org.apache.commons.math3.exception.NullArgumentException; 023 import org.apache.commons.math3.exception.util.LocalizedFormats; 024 import org.apache.commons.math3.stat.descriptive.moment.GeometricMean; 025 import org.apache.commons.math3.stat.descriptive.moment.Mean; 026 import org.apache.commons.math3.stat.descriptive.moment.SecondMoment; 027 import org.apache.commons.math3.stat.descriptive.moment.Variance; 028 import org.apache.commons.math3.stat.descriptive.rank.Max; 029 import org.apache.commons.math3.stat.descriptive.rank.Min; 030 import org.apache.commons.math3.stat.descriptive.summary.Sum; 031 import org.apache.commons.math3.stat.descriptive.summary.SumOfLogs; 032 import org.apache.commons.math3.stat.descriptive.summary.SumOfSquares; 033 import org.apache.commons.math3.util.MathUtils; 034 import org.apache.commons.math3.util.Precision; 035 import org.apache.commons.math3.util.FastMath; 036 037 /** 038 * <p> 039 * Computes summary statistics for a stream of data values added using the 040 * {@link #addValue(double) addValue} method. The data values are not stored in 041 * memory, so this class can be used to compute statistics for very large data 042 * streams. 043 * </p> 044 * <p> 045 * The {@link StorelessUnivariateStatistic} instances used to maintain summary 046 * state and compute statistics are configurable via setters. For example, the 047 * default implementation for the variance can be overridden by calling 048 * {@link #setVarianceImpl(StorelessUnivariateStatistic)}. Actual parameters to 049 * these methods must implement the {@link StorelessUnivariateStatistic} 050 * interface and configuration must be completed before <code>addValue</code> 051 * is called. No configuration is necessary to use the default, commons-math 052 * provided implementations. 053 * </p> 054 * <p> 055 * Note: This class is not thread-safe. Use 056 * {@link SynchronizedSummaryStatistics} if concurrent access from multiple 057 * threads is required. 058 * </p> 059 * @version $Id: SummaryStatistics.java 1416643 2012-12-03 19:37:14Z tn $ 060 */ 061 public class SummaryStatistics implements StatisticalSummary, Serializable { 062 063 /** Serialization UID */ 064 private static final long serialVersionUID = -2021321786743555871L; 065 066 /** count of values that have been added */ 067 private long n = 0; 068 069 /** SecondMoment is used to compute the mean and variance */ 070 private SecondMoment secondMoment = new SecondMoment(); 071 072 /** sum of values that have been added */ 073 private Sum sum = new Sum(); 074 075 /** sum of the square of each value that has been added */ 076 private SumOfSquares sumsq = new SumOfSquares(); 077 078 /** min of values that have been added */ 079 private Min min = new Min(); 080 081 /** max of values that have been added */ 082 private Max max = new Max(); 083 084 /** sumLog of values that have been added */ 085 private SumOfLogs sumLog = new SumOfLogs(); 086 087 /** geoMean of values that have been added */ 088 private GeometricMean geoMean = new GeometricMean(sumLog); 089 090 /** mean of values that have been added */ 091 private Mean mean = new Mean(secondMoment); 092 093 /** variance of values that have been added */ 094 private Variance variance = new Variance(secondMoment); 095 096 /** Sum statistic implementation - can be reset by setter. */ 097 private StorelessUnivariateStatistic sumImpl = sum; 098 099 /** Sum of squares statistic implementation - can be reset by setter. */ 100 private StorelessUnivariateStatistic sumsqImpl = sumsq; 101 102 /** Minimum statistic implementation - can be reset by setter. */ 103 private StorelessUnivariateStatistic minImpl = min; 104 105 /** Maximum statistic implementation - can be reset by setter. */ 106 private StorelessUnivariateStatistic maxImpl = max; 107 108 /** Sum of log statistic implementation - can be reset by setter. */ 109 private StorelessUnivariateStatistic sumLogImpl = sumLog; 110 111 /** Geometric mean statistic implementation - can be reset by setter. */ 112 private StorelessUnivariateStatistic geoMeanImpl = geoMean; 113 114 /** Mean statistic implementation - can be reset by setter. */ 115 private StorelessUnivariateStatistic meanImpl = mean; 116 117 /** Variance statistic implementation - can be reset by setter. */ 118 private StorelessUnivariateStatistic varianceImpl = variance; 119 120 /** 121 * Construct a SummaryStatistics instance 122 */ 123 public SummaryStatistics() { 124 } 125 126 /** 127 * A copy constructor. Creates a deep-copy of the {@code original}. 128 * 129 * @param original the {@code SummaryStatistics} instance to copy 130 * @throws NullArgumentException if original is null 131 */ 132 public SummaryStatistics(SummaryStatistics original) throws NullArgumentException { 133 copy(original, this); 134 } 135 136 /** 137 * Return a {@link StatisticalSummaryValues} instance reporting current 138 * statistics. 139 * @return Current values of statistics 140 */ 141 public StatisticalSummary getSummary() { 142 return new StatisticalSummaryValues(getMean(), getVariance(), getN(), 143 getMax(), getMin(), getSum()); 144 } 145 146 /** 147 * Add a value to the data 148 * @param value the value to add 149 */ 150 public void addValue(double value) { 151 sumImpl.increment(value); 152 sumsqImpl.increment(value); 153 minImpl.increment(value); 154 maxImpl.increment(value); 155 sumLogImpl.increment(value); 156 secondMoment.increment(value); 157 // If mean, variance or geomean have been overridden, 158 // need to increment these 159 if (meanImpl != mean) { 160 meanImpl.increment(value); 161 } 162 if (varianceImpl != variance) { 163 varianceImpl.increment(value); 164 } 165 if (geoMeanImpl != geoMean) { 166 geoMeanImpl.increment(value); 167 } 168 n++; 169 } 170 171 /** 172 * Returns the number of available values 173 * @return The number of available values 174 */ 175 public long getN() { 176 return n; 177 } 178 179 /** 180 * Returns the sum of the values that have been added 181 * @return The sum or <code>Double.NaN</code> if no values have been added 182 */ 183 public double getSum() { 184 return sumImpl.getResult(); 185 } 186 187 /** 188 * Returns the sum of the squares of the values that have been added. 189 * <p> 190 * Double.NaN is returned if no values have been added. 191 * </p> 192 * @return The sum of squares 193 */ 194 public double getSumsq() { 195 return sumsqImpl.getResult(); 196 } 197 198 /** 199 * Returns the mean of the values that have been added. 200 * <p> 201 * Double.NaN is returned if no values have been added. 202 * </p> 203 * @return the mean 204 */ 205 public double getMean() { 206 return meanImpl.getResult(); 207 } 208 209 /** 210 * Returns the standard deviation of the values that have been added. 211 * <p> 212 * Double.NaN is returned if no values have been added. 213 * </p> 214 * @return the standard deviation 215 */ 216 public double getStandardDeviation() { 217 double stdDev = Double.NaN; 218 if (getN() > 0) { 219 if (getN() > 1) { 220 stdDev = FastMath.sqrt(getVariance()); 221 } else { 222 stdDev = 0.0; 223 } 224 } 225 return stdDev; 226 } 227 228 /** 229 * Returns the (sample) variance of the available values. 230 * 231 * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in 232 * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected 233 * population variance.</p> 234 * 235 * <p>Double.NaN is returned if no values have been added.</p> 236 * 237 * @return the variance 238 */ 239 public double getVariance() { 240 return varianceImpl.getResult(); 241 } 242 243 /** 244 * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance"> 245 * population variance</a> of the values that have been added. 246 * 247 * <p>Double.NaN is returned if no values have been added.</p> 248 * 249 * @return the population variance 250 */ 251 public double getPopulationVariance() { 252 Variance populationVariance = new Variance(secondMoment); 253 populationVariance.setBiasCorrected(false); 254 return populationVariance.getResult(); 255 } 256 257 /** 258 * Returns the maximum of the values that have been added. 259 * <p> 260 * Double.NaN is returned if no values have been added. 261 * </p> 262 * @return the maximum 263 */ 264 public double getMax() { 265 return maxImpl.getResult(); 266 } 267 268 /** 269 * Returns the minimum of the values that have been added. 270 * <p> 271 * Double.NaN is returned if no values have been added. 272 * </p> 273 * @return the minimum 274 */ 275 public double getMin() { 276 return minImpl.getResult(); 277 } 278 279 /** 280 * Returns the geometric mean of the values that have been added. 281 * <p> 282 * Double.NaN is returned if no values have been added. 283 * </p> 284 * @return the geometric mean 285 */ 286 public double getGeometricMean() { 287 return geoMeanImpl.getResult(); 288 } 289 290 /** 291 * Returns the sum of the logs of the values that have been added. 292 * <p> 293 * Double.NaN is returned if no values have been added. 294 * </p> 295 * @return the sum of logs 296 * @since 1.2 297 */ 298 public double getSumOfLogs() { 299 return sumLogImpl.getResult(); 300 } 301 302 /** 303 * Returns a statistic related to the Second Central Moment. Specifically, 304 * what is returned is the sum of squared deviations from the sample mean 305 * among the values that have been added. 306 * <p> 307 * Returns <code>Double.NaN</code> if no data values have been added and 308 * returns <code>0</code> if there is just one value in the data set.</p> 309 * <p> 310 * @return second central moment statistic 311 * @since 2.0 312 */ 313 public double getSecondMoment() { 314 return secondMoment.getResult(); 315 } 316 317 /** 318 * Generates a text report displaying summary statistics from values that 319 * have been added. 320 * @return String with line feeds displaying statistics 321 * @since 1.2 322 */ 323 @Override 324 public String toString() { 325 StringBuilder outBuffer = new StringBuilder(); 326 String endl = "\n"; 327 outBuffer.append("SummaryStatistics:").append(endl); 328 outBuffer.append("n: ").append(getN()).append(endl); 329 outBuffer.append("min: ").append(getMin()).append(endl); 330 outBuffer.append("max: ").append(getMax()).append(endl); 331 outBuffer.append("mean: ").append(getMean()).append(endl); 332 outBuffer.append("geometric mean: ").append(getGeometricMean()) 333 .append(endl); 334 outBuffer.append("variance: ").append(getVariance()).append(endl); 335 outBuffer.append("sum of squares: ").append(getSumsq()).append(endl); 336 outBuffer.append("standard deviation: ").append(getStandardDeviation()) 337 .append(endl); 338 outBuffer.append("sum of logs: ").append(getSumOfLogs()).append(endl); 339 return outBuffer.toString(); 340 } 341 342 /** 343 * Resets all statistics and storage 344 */ 345 public void clear() { 346 this.n = 0; 347 minImpl.clear(); 348 maxImpl.clear(); 349 sumImpl.clear(); 350 sumLogImpl.clear(); 351 sumsqImpl.clear(); 352 geoMeanImpl.clear(); 353 secondMoment.clear(); 354 if (meanImpl != mean) { 355 meanImpl.clear(); 356 } 357 if (varianceImpl != variance) { 358 varianceImpl.clear(); 359 } 360 } 361 362 /** 363 * Returns true iff <code>object</code> is a 364 * <code>SummaryStatistics</code> instance and all statistics have the 365 * same values as this. 366 * @param object the object to test equality against. 367 * @return true if object equals this 368 */ 369 @Override 370 public boolean equals(Object object) { 371 if (object == this) { 372 return true; 373 } 374 if (object instanceof SummaryStatistics == false) { 375 return false; 376 } 377 SummaryStatistics stat = (SummaryStatistics)object; 378 return Precision.equalsIncludingNaN(stat.getGeometricMean(), getGeometricMean()) && 379 Precision.equalsIncludingNaN(stat.getMax(), getMax()) && 380 Precision.equalsIncludingNaN(stat.getMean(), getMean()) && 381 Precision.equalsIncludingNaN(stat.getMin(), getMin()) && 382 Precision.equalsIncludingNaN(stat.getN(), getN()) && 383 Precision.equalsIncludingNaN(stat.getSum(), getSum()) && 384 Precision.equalsIncludingNaN(stat.getSumsq(), getSumsq()) && 385 Precision.equalsIncludingNaN(stat.getVariance(), getVariance()); 386 } 387 388 /** 389 * Returns hash code based on values of statistics 390 * @return hash code 391 */ 392 @Override 393 public int hashCode() { 394 int result = 31 + MathUtils.hash(getGeometricMean()); 395 result = result * 31 + MathUtils.hash(getGeometricMean()); 396 result = result * 31 + MathUtils.hash(getMax()); 397 result = result * 31 + MathUtils.hash(getMean()); 398 result = result * 31 + MathUtils.hash(getMin()); 399 result = result * 31 + MathUtils.hash(getN()); 400 result = result * 31 + MathUtils.hash(getSum()); 401 result = result * 31 + MathUtils.hash(getSumsq()); 402 result = result * 31 + MathUtils.hash(getVariance()); 403 return result; 404 } 405 406 // Getters and setters for statistics implementations 407 /** 408 * Returns the currently configured Sum implementation 409 * @return the StorelessUnivariateStatistic implementing the sum 410 * @since 1.2 411 */ 412 public StorelessUnivariateStatistic getSumImpl() { 413 return sumImpl; 414 } 415 416 /** 417 * <p> 418 * Sets the implementation for the Sum. 419 * </p> 420 * <p> 421 * This method must be activated before any data has been added - i.e., 422 * before {@link #addValue(double) addValue} has been used to add data; 423 * otherwise an IllegalStateException will be thrown. 424 * </p> 425 * @param sumImpl the StorelessUnivariateStatistic instance to use for 426 * computing the Sum 427 * @throws MathIllegalStateException if data has already been added (i.e if n >0) 428 * @since 1.2 429 */ 430 public void setSumImpl(StorelessUnivariateStatistic sumImpl) 431 throws MathIllegalStateException { 432 checkEmpty(); 433 this.sumImpl = sumImpl; 434 } 435 436 /** 437 * Returns the currently configured sum of squares implementation 438 * @return the StorelessUnivariateStatistic implementing the sum of squares 439 * @since 1.2 440 */ 441 public StorelessUnivariateStatistic getSumsqImpl() { 442 return sumsqImpl; 443 } 444 445 /** 446 * <p> 447 * Sets the implementation for the sum of squares. 448 * </p> 449 * <p> 450 * This method must be activated before any data has been added - i.e., 451 * before {@link #addValue(double) addValue} has been used to add data; 452 * otherwise an IllegalStateException will be thrown. 453 * </p> 454 * @param sumsqImpl the StorelessUnivariateStatistic instance to use for 455 * computing the sum of squares 456 * @throws MathIllegalStateException if data has already been added (i.e if n > 0) 457 * @since 1.2 458 */ 459 public void setSumsqImpl(StorelessUnivariateStatistic sumsqImpl) 460 throws MathIllegalStateException { 461 checkEmpty(); 462 this.sumsqImpl = sumsqImpl; 463 } 464 465 /** 466 * Returns the currently configured minimum implementation 467 * @return the StorelessUnivariateStatistic implementing the minimum 468 * @since 1.2 469 */ 470 public StorelessUnivariateStatistic getMinImpl() { 471 return minImpl; 472 } 473 474 /** 475 * <p> 476 * Sets the implementation for the minimum. 477 * </p> 478 * <p> 479 * This method must be activated before any data has been added - i.e., 480 * before {@link #addValue(double) addValue} has been used to add data; 481 * otherwise an IllegalStateException will be thrown. 482 * </p> 483 * @param minImpl the StorelessUnivariateStatistic instance to use for 484 * computing the minimum 485 * @throws MathIllegalStateException if data has already been added (i.e if n > 0) 486 * @since 1.2 487 */ 488 public void setMinImpl(StorelessUnivariateStatistic minImpl) 489 throws MathIllegalStateException { 490 checkEmpty(); 491 this.minImpl = minImpl; 492 } 493 494 /** 495 * Returns the currently configured maximum implementation 496 * @return the StorelessUnivariateStatistic implementing the maximum 497 * @since 1.2 498 */ 499 public StorelessUnivariateStatistic getMaxImpl() { 500 return maxImpl; 501 } 502 503 /** 504 * <p> 505 * Sets the implementation for the maximum. 506 * </p> 507 * <p> 508 * This method must be activated before any data has been added - i.e., 509 * before {@link #addValue(double) addValue} has been used to add data; 510 * otherwise an IllegalStateException will be thrown. 511 * </p> 512 * @param maxImpl the StorelessUnivariateStatistic instance to use for 513 * computing the maximum 514 * @throws MathIllegalStateException if data has already been added (i.e if n > 0) 515 * @since 1.2 516 */ 517 public void setMaxImpl(StorelessUnivariateStatistic maxImpl) 518 throws MathIllegalStateException { 519 checkEmpty(); 520 this.maxImpl = maxImpl; 521 } 522 523 /** 524 * Returns the currently configured sum of logs implementation 525 * @return the StorelessUnivariateStatistic implementing the log sum 526 * @since 1.2 527 */ 528 public StorelessUnivariateStatistic getSumLogImpl() { 529 return sumLogImpl; 530 } 531 532 /** 533 * <p> 534 * Sets the implementation for the sum of logs. 535 * </p> 536 * <p> 537 * This method must be activated before any data has been added - i.e., 538 * before {@link #addValue(double) addValue} has been used to add data; 539 * otherwise an IllegalStateException will be thrown. 540 * </p> 541 * @param sumLogImpl the StorelessUnivariateStatistic instance to use for 542 * computing the log sum 543 * @throws MathIllegalStateException if data has already been added (i.e if n > 0) 544 * @since 1.2 545 */ 546 public void setSumLogImpl(StorelessUnivariateStatistic sumLogImpl) 547 throws MathIllegalStateException { 548 checkEmpty(); 549 this.sumLogImpl = sumLogImpl; 550 geoMean.setSumLogImpl(sumLogImpl); 551 } 552 553 /** 554 * Returns the currently configured geometric mean implementation 555 * @return the StorelessUnivariateStatistic implementing the geometric mean 556 * @since 1.2 557 */ 558 public StorelessUnivariateStatistic getGeoMeanImpl() { 559 return geoMeanImpl; 560 } 561 562 /** 563 * <p> 564 * Sets the implementation for the geometric mean. 565 * </p> 566 * <p> 567 * This method must be activated before any data has been added - i.e., 568 * before {@link #addValue(double) addValue} has been used to add data; 569 * otherwise an IllegalStateException will be thrown. 570 * </p> 571 * @param geoMeanImpl the StorelessUnivariateStatistic instance to use for 572 * computing the geometric mean 573 * @throws MathIllegalStateException if data has already been added (i.e if n > 0) 574 * @since 1.2 575 */ 576 public void setGeoMeanImpl(StorelessUnivariateStatistic geoMeanImpl) 577 throws MathIllegalStateException { 578 checkEmpty(); 579 this.geoMeanImpl = geoMeanImpl; 580 } 581 582 /** 583 * Returns the currently configured mean implementation 584 * @return the StorelessUnivariateStatistic implementing the mean 585 * @since 1.2 586 */ 587 public StorelessUnivariateStatistic getMeanImpl() { 588 return meanImpl; 589 } 590 591 /** 592 * <p> 593 * Sets the implementation for the mean. 594 * </p> 595 * <p> 596 * This method must be activated before any data has been added - i.e., 597 * before {@link #addValue(double) addValue} has been used to add data; 598 * otherwise an IllegalStateException will be thrown. 599 * </p> 600 * @param meanImpl the StorelessUnivariateStatistic instance to use for 601 * computing the mean 602 * @throws MathIllegalStateException if data has already been added (i.e if n > 0) 603 * @since 1.2 604 */ 605 public void setMeanImpl(StorelessUnivariateStatistic meanImpl) 606 throws MathIllegalStateException { 607 checkEmpty(); 608 this.meanImpl = meanImpl; 609 } 610 611 /** 612 * Returns the currently configured variance implementation 613 * @return the StorelessUnivariateStatistic implementing the variance 614 * @since 1.2 615 */ 616 public StorelessUnivariateStatistic getVarianceImpl() { 617 return varianceImpl; 618 } 619 620 /** 621 * <p> 622 * Sets the implementation for the variance. 623 * </p> 624 * <p> 625 * This method must be activated before any data has been added - i.e., 626 * before {@link #addValue(double) addValue} has been used to add data; 627 * otherwise an IllegalStateException will be thrown. 628 * </p> 629 * @param varianceImpl the StorelessUnivariateStatistic instance to use for 630 * computing the variance 631 * @throws MathIllegalStateException if data has already been added (i.e if n > 0) 632 * @since 1.2 633 */ 634 public void setVarianceImpl(StorelessUnivariateStatistic varianceImpl) 635 throws MathIllegalStateException { 636 checkEmpty(); 637 this.varianceImpl = varianceImpl; 638 } 639 640 /** 641 * Throws IllegalStateException if n > 0. 642 * @throws MathIllegalStateException if data has been added 643 */ 644 private void checkEmpty() throws MathIllegalStateException { 645 if (n > 0) { 646 throw new MathIllegalStateException( 647 LocalizedFormats.VALUES_ADDED_BEFORE_CONFIGURING_STATISTIC, n); 648 } 649 } 650 651 /** 652 * Returns a copy of this SummaryStatistics instance with the same internal state. 653 * 654 * @return a copy of this 655 */ 656 public SummaryStatistics copy() { 657 SummaryStatistics result = new SummaryStatistics(); 658 // No try-catch or advertised exception because arguments are guaranteed non-null 659 copy(this, result); 660 return result; 661 } 662 663 /** 664 * Copies source to dest. 665 * <p>Neither source nor dest can be null.</p> 666 * 667 * @param source SummaryStatistics to copy 668 * @param dest SummaryStatistics to copy to 669 * @throws NullArgumentException if either source or dest is null 670 */ 671 public static void copy(SummaryStatistics source, SummaryStatistics dest) 672 throws NullArgumentException { 673 MathUtils.checkNotNull(source); 674 MathUtils.checkNotNull(dest); 675 dest.maxImpl = source.maxImpl.copy(); 676 dest.minImpl = source.minImpl.copy(); 677 dest.sumImpl = source.sumImpl.copy(); 678 dest.sumLogImpl = source.sumLogImpl.copy(); 679 dest.sumsqImpl = source.sumsqImpl.copy(); 680 dest.secondMoment = source.secondMoment.copy(); 681 dest.n = source.n; 682 683 // Keep commons-math supplied statistics with embedded moments in synch 684 if (source.getVarianceImpl() instanceof Variance) { 685 dest.varianceImpl = new Variance(dest.secondMoment); 686 } else { 687 dest.varianceImpl = source.varianceImpl.copy(); 688 } 689 if (source.meanImpl instanceof Mean) { 690 dest.meanImpl = new Mean(dest.secondMoment); 691 } else { 692 dest.meanImpl = source.meanImpl.copy(); 693 } 694 if (source.getGeoMeanImpl() instanceof GeometricMean) { 695 dest.geoMeanImpl = new GeometricMean((SumOfLogs) dest.sumLogImpl); 696 } else { 697 dest.geoMeanImpl = source.geoMeanImpl.copy(); 698 } 699 700 // Make sure that if stat == statImpl in source, same 701 // holds in dest; otherwise copy stat 702 if (source.geoMean == source.geoMeanImpl) { 703 dest.geoMean = (GeometricMean) dest.geoMeanImpl; 704 } else { 705 GeometricMean.copy(source.geoMean, dest.geoMean); 706 } 707 if (source.max == source.maxImpl) { 708 dest.max = (Max) dest.maxImpl; 709 } else { 710 Max.copy(source.max, dest.max); 711 } 712 if (source.mean == source.meanImpl) { 713 dest.mean = (Mean) dest.meanImpl; 714 } else { 715 Mean.copy(source.mean, dest.mean); 716 } 717 if (source.min == source.minImpl) { 718 dest.min = (Min) dest.minImpl; 719 } else { 720 Min.copy(source.min, dest.min); 721 } 722 if (source.sum == source.sumImpl) { 723 dest.sum = (Sum) dest.sumImpl; 724 } else { 725 Sum.copy(source.sum, dest.sum); 726 } 727 if (source.variance == source.varianceImpl) { 728 dest.variance = (Variance) dest.varianceImpl; 729 } else { 730 Variance.copy(source.variance, dest.variance); 731 } 732 if (source.sumLog == source.sumLogImpl) { 733 dest.sumLog = (SumOfLogs) dest.sumLogImpl; 734 } else { 735 SumOfLogs.copy(source.sumLog, dest.sumLog); 736 } 737 if (source.sumsq == source.sumsqImpl) { 738 dest.sumsq = (SumOfSquares) dest.sumsqImpl; 739 } else { 740 SumOfSquares.copy(source.sumsq, dest.sumsq); 741 } 742 } 743 }