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.math4.legacy.stat.descriptive; 018 019import org.apache.commons.math4.legacy.exception.MathIllegalStateException; 020import org.apache.commons.math4.legacy.exception.NullArgumentException; 021import org.apache.commons.math4.legacy.exception.util.LocalizedFormats; 022import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean; 023import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean; 024import org.apache.commons.math4.legacy.stat.descriptive.moment.SecondMoment; 025import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance; 026import org.apache.commons.math4.legacy.stat.descriptive.rank.Max; 027import org.apache.commons.math4.legacy.stat.descriptive.rank.Min; 028import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum; 029import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs; 030import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares; 031import org.apache.commons.math4.core.jdkmath.JdkMath; 032import org.apache.commons.numbers.core.Precision; 033 034/** 035 * <p> 036 * Computes summary statistics for a stream of data values added using the 037 * {@link #addValue(double) addValue} method. The data values are not stored in 038 * memory, so this class can be used to compute statistics for very large data 039 * streams. 040 * </p> 041 * <p> 042 * The {@link StorelessUnivariateStatistic} instances used to maintain summary 043 * state and compute statistics are configurable via setters. For example, the 044 * default implementation for the variance can be overridden by calling 045 * {@link #setVarianceImpl(StorelessUnivariateStatistic)}. Actual parameters to 046 * these methods must implement the {@link StorelessUnivariateStatistic} 047 * interface and configuration must be completed before <code>addValue</code> 048 * is called. No configuration is necessary to use the default, commons-math 049 * provided implementations. 050 * </p> 051 * <p> 052 * Note: This class is not thread-safe. Use 053 * {@link SynchronizedSummaryStatistics} if concurrent access from multiple 054 * threads is required. 055 * </p> 056 */ 057public class SummaryStatistics implements StatisticalSummary { 058 /** count of values that have been added. */ 059 private long n; 060 061 /** SecondMoment is used to compute the mean and variance. */ 062 private SecondMoment secondMoment = new SecondMoment(); 063 064 /** sum of values that have been added. */ 065 private Sum sum = new Sum(); 066 067 /** sum of the square of each value that has been added. */ 068 private SumOfSquares sumsq = new SumOfSquares(); 069 070 /** min of values that have been added. */ 071 private Min min = new Min(); 072 073 /** max of values that have been added. */ 074 private Max max = new Max(); 075 076 /** sumLog of values that have been added. */ 077 private SumOfLogs sumLog = new SumOfLogs(); 078 079 /** geoMean of values that have been added. */ 080 private GeometricMean geoMean = new GeometricMean(sumLog); 081 082 /** mean of values that have been added. */ 083 private Mean mean = new Mean(secondMoment); 084 085 /** variance of values that have been added. */ 086 private Variance variance = new Variance(secondMoment); 087 088 /** Sum statistic implementation - can be reset by setter. */ 089 private StorelessUnivariateStatistic sumImpl = sum; 090 091 /** Sum of squares statistic implementation - can be reset by setter. */ 092 private StorelessUnivariateStatistic sumsqImpl = sumsq; 093 094 /** Minimum statistic implementation - can be reset by setter. */ 095 private StorelessUnivariateStatistic minImpl = min; 096 097 /** Maximum statistic implementation - can be reset by setter. */ 098 private StorelessUnivariateStatistic maxImpl = max; 099 100 /** Sum of log statistic implementation - can be reset by setter. */ 101 private StorelessUnivariateStatistic sumLogImpl = sumLog; 102 103 /** Geometric mean statistic implementation - can be reset by setter. */ 104 private StorelessUnivariateStatistic geoMeanImpl = geoMean; 105 106 /** Mean statistic implementation - can be reset by setter. */ 107 private StorelessUnivariateStatistic meanImpl = mean; 108 109 /** Variance statistic implementation - can be reset by setter. */ 110 private StorelessUnivariateStatistic varianceImpl = variance; 111 112 /** 113 * Construct a SummaryStatistics instance. 114 */ 115 public SummaryStatistics() { 116 } 117 118 /** 119 * A copy constructor. Creates a deep-copy of the {@code original}. 120 * 121 * @param original the {@code SummaryStatistics} instance to copy 122 * @throws NullArgumentException if original is null 123 */ 124 public SummaryStatistics(SummaryStatistics original) throws NullArgumentException { 125 copy(original, this); 126 } 127 128 /** 129 * Return a {@link StatisticalSummaryValues} instance reporting current 130 * statistics. 131 * @return Current values of statistics 132 */ 133 public StatisticalSummary getSummary() { 134 return new StatisticalSummaryValues(getMean(), getVariance(), getN(), 135 getMax(), getMin(), getSum()); 136 } 137 138 /** 139 * Add a value to the data. 140 * @param value the value to add 141 */ 142 public void addValue(double value) { 143 sumImpl.increment(value); 144 sumsqImpl.increment(value); 145 minImpl.increment(value); 146 maxImpl.increment(value); 147 sumLogImpl.increment(value); 148 secondMoment.increment(value); 149 // If mean, variance or geomean have been overridden, 150 // need to increment these 151 if (meanImpl != mean) { 152 meanImpl.increment(value); 153 } 154 if (varianceImpl != variance) { 155 varianceImpl.increment(value); 156 } 157 if (geoMeanImpl != geoMean) { 158 geoMeanImpl.increment(value); 159 } 160 n++; 161 } 162 163 /** 164 * Returns the number of available values. 165 * @return The number of available values 166 */ 167 @Override 168 public long getN() { 169 return n; 170 } 171 172 /** 173 * Returns the sum of the values that have been added. 174 * @return The sum or <code>Double.NaN</code> if no values have been added 175 */ 176 @Override 177 public double getSum() { 178 return sumImpl.getResult(); 179 } 180 181 /** 182 * Returns the sum of the squares of the values that have been added. 183 * <p> 184 * Double.NaN is returned if no values have been added. 185 * </p> 186 * @return The sum of squares 187 */ 188 public double getSumsq() { 189 return sumsqImpl.getResult(); 190 } 191 192 /** 193 * Returns the mean of the values that have been added. 194 * <p> 195 * Double.NaN is returned if no values have been added. 196 * </p> 197 * @return the mean 198 */ 199 @Override 200 public double getMean() { 201 return meanImpl.getResult(); 202 } 203 204 /** 205 * Returns the standard deviation of the values that have been added. 206 * <p> 207 * Double.NaN is returned if no values have been added. 208 * </p> 209 * @return the standard deviation 210 */ 211 @Override 212 public double getStandardDeviation() { 213 double stdDev = Double.NaN; 214 if (getN() > 0) { 215 if (getN() > 1) { 216 stdDev = JdkMath.sqrt(getVariance()); 217 } else { 218 stdDev = 0.0; 219 } 220 } 221 return stdDev; 222 } 223 224 /** 225 * Returns the quadratic mean, a.k.a. 226 * <a href="http://mathworld.wolfram.com/Root-Mean-Square.html"> 227 * root-mean-square</a> of the available values 228 * @return The quadratic mean or {@code Double.NaN} if no values 229 * have been added. 230 */ 231 public double getQuadraticMean() { 232 final long size = getN(); 233 return size > 0 ? JdkMath.sqrt(getSumsq() / size) : Double.NaN; 234 } 235 236 /** 237 * Returns the (sample) variance of the available values. 238 * 239 * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in 240 * the denominator). Use {@link #getPopulationVariance()} for the non-bias-corrected 241 * population variance.</p> 242 * 243 * <p>Double.NaN is returned if no values have been added.</p> 244 * 245 * @return the variance 246 */ 247 @Override 248 public double getVariance() { 249 return varianceImpl.getResult(); 250 } 251 252 /** 253 * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance"> 254 * population variance</a> of the values that have been added. 255 * 256 * <p>Double.NaN is returned if no values have been added.</p> 257 * 258 * @return the population variance 259 */ 260 public double getPopulationVariance() { 261 Variance populationVariance = new Variance(secondMoment); 262 populationVariance.setBiasCorrected(false); 263 return populationVariance.getResult(); 264 } 265 266 /** 267 * Returns the maximum of the values that have been added. 268 * <p> 269 * Double.NaN is returned if no values have been added. 270 * </p> 271 * @return the maximum 272 */ 273 @Override 274 public double getMax() { 275 return maxImpl.getResult(); 276 } 277 278 /** 279 * Returns the minimum of the values that have been added. 280 * <p> 281 * Double.NaN is returned if no values have been added. 282 * </p> 283 * @return the minimum 284 */ 285 @Override 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. 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)) { 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 + Double.hashCode(getGeometricMean()); 409 result = result * 31 + Double.hashCode(getGeometricMean()); 410 result = result * 31 + Double.hashCode(getMax()); 411 result = result * 31 + Double.hashCode(getMean()); 412 result = result * 31 + Double.hashCode(getMin()); 413 result = result * 31 + Double.hashCode(getN()); 414 result = result * 31 + Double.hashCode(getSum()); 415 result = result * 31 + Double.hashCode(getSumsq()); 416 result = result * 31 + Double.hashCode(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 NullArgumentException.check(source); 696 NullArgumentException.check(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}