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