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.statistics.descriptive; 018 019import java.math.BigInteger; 020import java.util.Objects; 021import java.util.Set; 022import java.util.function.DoubleConsumer; 023import java.util.function.IntConsumer; 024 025/** 026 * Statistics for {@code int} values. 027 * 028 * <p>This class provides combinations of individual statistic implementations in the 029 * {@code org.apache.commons.statistics.descriptive} package. 030 * 031 * <p>Supports up to 2<sup>63</sup> (exclusive) observations. 032 * This implementation does not check for overflow of the count. 033 * 034 * @since 1.1 035 */ 036public final class IntStatistics implements IntConsumer { 037 /** Error message for non configured statistics. */ 038 private static final String NO_CONFIGURED_STATISTICS = "No configured statistics"; 039 /** Error message for an unsupported statistic. */ 040 private static final String UNSUPPORTED_STATISTIC = "Unsupported statistic: "; 041 042 /** Count of values recorded. */ 043 private long count; 044 /** The consumer of values. */ 045 private final IntConsumer consumer; 046 /** The {@link IntMin} implementation. */ 047 private final IntMin min; 048 /** The {@link IntMax} implementation. */ 049 private final IntMax max; 050 /** The moment implementation. May be any instance of {@link FirstMoment}. 051 * This implementation uses only the third and fourth moments. */ 052 private final FirstMoment moment; 053 /** The {@link IntSum} implementation. */ 054 private final IntSum sum; 055 /** The {@link Product} implementation. */ 056 private final Product product; 057 /** The {@link IntSumOfSquares} implementation. */ 058 private final IntSumOfSquares sumOfSquares; 059 /** The {@link SumOfLogs} implementation. */ 060 private final SumOfLogs sumOfLogs; 061 /** Configuration options for computation of statistics. */ 062 private StatisticsConfiguration config; 063 064 /** 065 * A builder for {@link IntStatistics}. 066 */ 067 public static final class Builder { 068 /** An empty double array. */ 069 private static final int[] NO_VALUES = {}; 070 071 /** The {@link IntMin} constructor. */ 072 private RangeFunction<int[], IntMin> min; 073 /** The {@link IntMax} constructor. */ 074 private RangeFunction<int[], IntMax> max; 075 /** The moment constructor. May return any instance of {@link FirstMoment}. */ 076 private RangeFunction<int[], FirstMoment> moment; 077 /** The {@link IntSum} constructor. */ 078 private RangeFunction<int[], IntSum> sum; 079 /** The {@link Product} constructor. */ 080 private RangeFunction<int[], Product> product; 081 /** The {@link IntSumOfSquares} constructor. */ 082 private RangeFunction<int[], IntSumOfSquares> sumOfSquares; 083 /** The {@link SumOfLogs} constructor. */ 084 private RangeFunction<int[], SumOfLogs> sumOfLogs; 085 /** The order of the moment. It corresponds to the power computed by the {@link FirstMoment} 086 * instance constructed by {@link #moment}. This should only be increased from the default 087 * of zero (corresponding to no moment computation). */ 088 private int momentOrder; 089 /** Configuration options for computation of statistics. */ 090 private StatisticsConfiguration config = StatisticsConfiguration.withDefaults(); 091 092 /** 093 * Create an instance. 094 */ 095 Builder() { 096 // Do nothing 097 } 098 099 /** 100 * Add the statistic to the statistics to compute. 101 * 102 * @param statistic Statistic to compute. 103 * @return {@code this} instance 104 */ 105 Builder add(Statistic statistic) { 106 // Exhaustive switch statement 107 switch (statistic) { 108 case GEOMETRIC_MEAN: 109 case SUM_OF_LOGS: 110 sumOfLogs = SumOfLogs::createFromRange; 111 break; 112 case KURTOSIS: 113 createMoment(4); 114 break; 115 case MAX: 116 max = IntMax::createFromRange; 117 break; 118 case MIN: 119 min = IntMin::createFromRange; 120 break; 121 case PRODUCT: 122 product = Product::createFromRange; 123 break; 124 case SKEWNESS: 125 createMoment(3); 126 break; 127 case STANDARD_DEVIATION: 128 case VARIANCE: 129 sum = IntSum::createFromRange; 130 sumOfSquares = IntSumOfSquares::createFromRange; 131 break; 132 case MEAN: 133 case SUM: 134 sum = IntSum::createFromRange; 135 break; 136 case SUM_OF_SQUARES: 137 sumOfSquares = IntSumOfSquares::createFromRange; 138 break; 139 } 140 return this; 141 } 142 143 /** 144 * Creates the moment constructor for the specified {@code order}, 145 * e.g. order=3 is sum of cubed deviations. 146 * 147 * @param order Order. 148 */ 149 private void createMoment(int order) { 150 if (order > momentOrder) { 151 momentOrder = order; 152 if (order == 4) { 153 moment = SumOfFourthDeviations::ofRange; 154 } else { 155 // Assume order == 3 156 moment = SumOfCubedDeviations::ofRange; 157 } 158 } 159 } 160 161 /** 162 * Sets the statistics configuration options for computation of statistics. 163 * 164 * @param v Value. 165 * @return the builder 166 * @throws NullPointerException if the value is null 167 */ 168 public Builder setConfiguration(StatisticsConfiguration v) { 169 config = Objects.requireNonNull(v); 170 return this; 171 } 172 173 /** 174 * Builds an {@code IntStatistics} instance. 175 * 176 * @return {@code IntStatistics} instance. 177 */ 178 public IntStatistics build() { 179 return create(NO_VALUES, 0, 0); 180 } 181 182 /** 183 * Builds an {@code IntStatistics} instance using the input {@code values}. 184 * 185 * <p>Note: {@code IntStatistics} computed using 186 * {@link IntStatistics#accept(int) accept} may be 187 * different from this instance. 188 * 189 * @param values Values. 190 * @return {@code IntStatistics} instance. 191 */ 192 public IntStatistics build(int... values) { 193 Objects.requireNonNull(values, "values"); 194 return create(values, 0, values.length); 195 } 196 197 /** 198 * Builds an {@code IntStatistics} instance using the specified range of {@code values}. 199 * 200 * <p>Note: {@code IntStatistics} computed using 201 * {@link IntStatistics#accept(int) accept} may be 202 * different from this instance. 203 * 204 * @param values Values. 205 * @param from Inclusive start of the range. 206 * @param to Exclusive end of the range. 207 * @return {@code IntStatistics} instance. 208 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 209 * @since 1.2 210 */ 211 public IntStatistics build(int[] values, int from, int to) { 212 Statistics.checkFromToIndex(from, to, values.length); 213 return create(values, from, to); 214 } 215 216 /** 217 * Builds an {@code IntStatistics} instance using the input {@code values}. 218 * 219 * <p>Note: {@code IntStatistics} computed using 220 * {@link IntStatistics#accept(int) accept} may be 221 * different from this instance. 222 * 223 * <p>Warning: No range checks are performed. 224 * 225 * @param values Values. 226 * @param from Inclusive start of the range. 227 * @param to Exclusive end of the range. 228 * @return {@code IntStatistics} instance. 229 */ 230 private IntStatistics create(int[] values, int from, int to) { 231 return new IntStatistics( 232 to - from, 233 create(min, values, from, to), 234 create(max, values, from, to), 235 create(moment, values, from, to), 236 create(sum, values, from, to), 237 create(product, values, from, to), 238 create(sumOfSquares, values, from, to), 239 create(sumOfLogs, values, from, to), 240 config); 241 } 242 243 /** 244 * Creates the object from the {@code values}. 245 * 246 * @param <S> value type 247 * @param <T> object type 248 * @param constructor Constructor. 249 * @param values Values 250 * @param from Inclusive start of the range. 251 * @param to Exclusive end of the range. 252 * @return the instance 253 */ 254 private static <S, T> T create(RangeFunction<S, T> constructor, S values, int from, int to) { 255 if (constructor != null) { 256 return constructor.apply(values, from, to); 257 } 258 return null; 259 } 260 } 261 262 /** 263 * Create an instance. 264 * 265 * @param count Count of values. 266 * @param min IntMin implementation. 267 * @param max IntMax implementation. 268 * @param moment Moment implementation. 269 * @param sum IntSum implementation. 270 * @param product Product implementation. 271 * @param sumOfSquares Sum of squares implementation. 272 * @param sumOfLogs Sum of logs implementation. 273 * @param config Statistics configuration. 274 */ 275 IntStatistics(long count, IntMin min, IntMax max, FirstMoment moment, IntSum sum, 276 Product product, IntSumOfSquares sumOfSquares, SumOfLogs sumOfLogs, 277 StatisticsConfiguration config) { 278 this.count = count; 279 this.min = min; 280 this.max = max; 281 this.moment = moment; 282 this.sum = sum; 283 this.product = product; 284 this.sumOfSquares = sumOfSquares; 285 this.sumOfLogs = sumOfLogs; 286 this.config = config; 287 // The final consumer should never be null as the builder is created 288 // with at least one statistic. 289 consumer = Statistics.composeIntConsumers(min, max, sum, sumOfSquares, 290 composeAsInt(moment, product, sumOfLogs)); 291 } 292 293 /** 294 * Chain the {@code consumers} into a single composite {@code IntConsumer}. 295 * Ignore any {@code null} consumer. 296 * 297 * @param consumers Consumers. 298 * @return a composed consumer (or null) 299 */ 300 private static IntConsumer composeAsInt(DoubleConsumer... consumers) { 301 final DoubleConsumer c = Statistics.composeDoubleConsumers(consumers); 302 if (c != null) { 303 return c::accept; 304 } 305 return null; 306 } 307 308 /** 309 * Returns a new instance configured to compute the specified {@code statistics}. 310 * 311 * <p>The statistics will be empty and so will return the default values for each 312 * computed statistic. 313 * 314 * @param statistics Statistics to compute. 315 * @return the instance 316 * @throws IllegalArgumentException if there are no {@code statistics} to compute. 317 */ 318 public static IntStatistics of(Statistic... statistics) { 319 return builder(statistics).build(); 320 } 321 322 /** 323 * Returns a new instance configured to compute the specified {@code statistics} 324 * populated using the input {@code values}. 325 * 326 * <p>Use this method to create an instance populated with a (variable) array of 327 * {@code int[]} data: 328 * 329 * <pre> 330 * IntStatistics stats = IntStatistics.of( 331 * EnumSet.of(Statistic.MIN, Statistic.MAX), 332 * 1, 1, 2, 3, 5, 8, 13); 333 * </pre> 334 * 335 * @param statistics Statistics to compute. 336 * @param values Values. 337 * @return the instance 338 * @throws IllegalArgumentException if there are no {@code statistics} to compute. 339 */ 340 public static IntStatistics of(Set<Statistic> statistics, int... values) { 341 if (statistics.isEmpty()) { 342 throw new IllegalArgumentException(NO_CONFIGURED_STATISTICS); 343 } 344 final Builder b = new Builder(); 345 statistics.forEach(b::add); 346 return b.build(values); 347 } 348 349 /** 350 * Returns a new instance configured to compute the specified {@code statistics} 351 * populated using the specified range of {@code values}. 352 * 353 * <p>Use this method to create an instance populated with part of an array of 354 * {@code int[]} data, e.g. to use the first half of the data: 355 * 356 * <pre> 357 * int[] data = ... 358 * IntStatistics stats = IntStatistics.of( 359 * EnumSet.of(Statistic.MIN, Statistic.MAX), 360 * data, 0, data.length / 2); 361 * </pre> 362 * 363 * @param statistics Statistics to compute. 364 * @param values Values. 365 * @param from Inclusive start of the range. 366 * @param to Exclusive end of the range. 367 * @return the instance 368 * @throws IllegalArgumentException if there are no {@code statistics} to compute. 369 * @throws IndexOutOfBoundsException if the sub-range is out of bounds 370 * @since 1.2 371 */ 372 public static IntStatistics ofRange(Set<Statistic> statistics, int[] values, int from, int to) { 373 if (statistics.isEmpty()) { 374 throw new IllegalArgumentException(NO_CONFIGURED_STATISTICS); 375 } 376 final Builder b = new Builder(); 377 statistics.forEach(b::add); 378 return b.build(values, from, to); 379 } 380 381 /** 382 * Returns a new builder configured to create instances to compute the specified 383 * {@code statistics}. 384 * 385 * <p>Use this method to create an instance populated with an array of {@code int[]} 386 * data using the {@link Builder#build(int...)} method: 387 * 388 * <pre> 389 * int[] data = ... 390 * IntStatistics stats = IntStatistics.builder( 391 * Statistic.MIN, Statistic.MAX, Statistic.VARIANCE) 392 * .build(data); 393 * </pre> 394 * 395 * <p>The builder can be used to create multiple instances of {@link IntStatistics} 396 * to be used in parallel, or on separate arrays of {@code int[]} data. These may 397 * be {@link #combine(IntStatistics) combined}. For example: 398 * 399 * <pre> 400 * int[][] data = ... 401 * IntStatistics.Builder builder = IntStatistics.builder( 402 * Statistic.MIN, Statistic.MAX, Statistic.VARIANCE); 403 * IntStatistics stats = Arrays.stream(data) 404 * .parallel() 405 * .map(builder::build) 406 * .reduce(IntStatistics::combine) 407 * .get(); 408 * </pre> 409 * 410 * <p>The builder can be used to create a {@link java.util.stream.Collector} for repeat 411 * use on multiple data: 412 * 413 * <pre>{@code 414 * IntStatistics.Builder builder = IntStatistics.builder( 415 * Statistic.MIN, Statistic.MAX, Statistic.VARIANCE); 416 * Collector<int[], IntStatistics, IntStatistics> collector = 417 * Collector.of(builder::build, 418 * (s, d) -> s.combine(builder.build(d)), 419 * IntStatistics::combine); 420 * 421 * // Repeated 422 * int[][] data = ... 423 * IntStatistics stats = Arrays.stream(data).collect(collector); 424 * }</pre> 425 * 426 * @param statistics Statistics to compute. 427 * @return the builder 428 * @throws IllegalArgumentException if there are no {@code statistics} to compute. 429 */ 430 public static Builder builder(Statistic... statistics) { 431 if (statistics.length == 0) { 432 throw new IllegalArgumentException(NO_CONFIGURED_STATISTICS); 433 } 434 final Builder b = new Builder(); 435 for (final Statistic s : statistics) { 436 b.add(s); 437 } 438 return b; 439 } 440 441 /** 442 * Updates the state of the statistics to reflect the addition of {@code value}. 443 * 444 * @param value Value. 445 */ 446 @Override 447 public void accept(int value) { 448 count++; 449 consumer.accept(value); 450 } 451 452 /** 453 * Return the count of values recorded. 454 * 455 * @return the count of values 456 */ 457 public long getCount() { 458 return count; 459 } 460 461 /** 462 * Check if the specified {@code statistic} is supported. 463 * 464 * <p>Note: This method will not return {@code false} if the argument is {@code null}. 465 * 466 * @param statistic Statistic. 467 * @return {@code true} if supported 468 * @throws NullPointerException if the {@code statistic} is {@code null} 469 * @see #getResult(Statistic) 470 */ 471 public boolean isSupported(Statistic statistic) { 472 // Check for the appropriate underlying implementation 473 // Exhaustive switch statement 474 switch (statistic) { 475 case GEOMETRIC_MEAN: 476 case SUM_OF_LOGS: 477 return sumOfLogs != null; 478 case KURTOSIS: 479 return moment instanceof SumOfFourthDeviations; 480 case MAX: 481 return max != null; 482 case MIN: 483 return min != null; 484 case PRODUCT: 485 return product != null; 486 case SKEWNESS: 487 return moment instanceof SumOfCubedDeviations; 488 case STANDARD_DEVIATION: 489 case VARIANCE: 490 return sum != null && sumOfSquares != null; 491 case MEAN: 492 case SUM: 493 return sum != null; 494 case SUM_OF_SQUARES: 495 return sumOfSquares != null; 496 } 497 // Unreachable code 498 throw new IllegalArgumentException(UNSUPPORTED_STATISTIC + statistic); 499 } 500 501 /** 502 * Gets the value of the specified {@code statistic} as a {@code double}. 503 * 504 * @param statistic Statistic. 505 * @return the value 506 * @throws IllegalArgumentException if the {@code statistic} is not supported 507 * @see #isSupported(Statistic) 508 * @see #getResult(Statistic) 509 */ 510 public double getAsDouble(Statistic statistic) { 511 return getResult(statistic).getAsDouble(); 512 } 513 514 /** 515 * Gets the value of the specified {@code statistic} as an {@code int}. 516 * 517 * <p>Use this method to access the {@code int} result for exact integer statistics, 518 * for example {@link Statistic#MIN}. 519 * 520 * <p>Note: This method may throw an {@link ArithmeticException} if the result 521 * overflows an {@code int}. 522 * 523 * @param statistic Statistic. 524 * @return the value 525 * @throws IllegalArgumentException if the {@code statistic} is not supported 526 * @throws ArithmeticException if the {@code result} overflows an {@code int} or is not 527 * finite 528 * @see #isSupported(Statistic) 529 * @see #getResult(Statistic) 530 */ 531 public int getAsInt(Statistic statistic) { 532 return getResult(statistic).getAsInt(); 533 } 534 535 /** 536 * Gets the value of the specified {@code statistic} as a {@code long}. 537 * 538 * <p>Use this method to access the {@code long} result for exact integer statistics, 539 * for example {@link Statistic#SUM} for a {@link #getCount() count} less than or equal to 540 *2<sup>32</sup>. 541 * 542 * <p>Note: This method may throw an {@link ArithmeticException} if the result 543 * overflows an {@code long}. 544 * 545 * @param statistic Statistic. 546 * @return the value 547 * @throws IllegalArgumentException if the {@code statistic} is not supported 548 * @throws ArithmeticException if the {@code result} overflows an {@code long} or is not 549 * finite 550 * @see #isSupported(Statistic) 551 * @see #getResult(Statistic) 552 */ 553 public long getAsLong(Statistic statistic) { 554 return getResult(statistic).getAsLong(); 555 } 556 557 /** 558 * Gets the value of the specified {@code statistic} as a {@code BigInteger}. 559 * 560 * <p>Use this method to access the {@code BigInteger} result for exact integer statistics, 561 * for example {@link Statistic#SUM_OF_SQUARES}. 562 * 563 * <p>Note: This method may throw an {@link ArithmeticException} if the result 564 * is not finite. 565 * 566 * @param statistic Statistic. 567 * @return the value 568 * @throws IllegalArgumentException if the {@code statistic} is not supported 569 * @throws ArithmeticException if the {@code result} is not finite 570 * @see #isSupported(Statistic) 571 * @see #getResult(Statistic) 572 */ 573 public BigInteger getAsBigInteger(Statistic statistic) { 574 return getResult(statistic).getAsBigInteger(); 575 } 576 577 /** 578 * Gets a supplier for the value of the specified {@code statistic}. 579 * 580 * <p>The returned function will supply the correct result after 581 * calls to {@link #accept(int) accept} or 582 * {@link #combine(IntStatistics) combine} further values into 583 * {@code this} instance. 584 * 585 * <p>This method can be used to perform a one-time look-up of the statistic 586 * function to compute statistics as values are dynamically added. 587 * 588 * @param statistic Statistic. 589 * @return the supplier 590 * @throws IllegalArgumentException if the {@code statistic} is not supported 591 * @see #isSupported(Statistic) 592 * @see #getAsDouble(Statistic) 593 */ 594 public StatisticResult getResult(Statistic statistic) { 595 // Locate the implementation. 596 // Statistics that wrap an underlying implementation are created in methods. 597 // The return argument should be an interface reference and not an instance 598 // of IntStatistic. This ensures the statistic implementation cannot 599 // be updated with new values by casting the result and calling accept(int). 600 StatisticResult stat = null; 601 // Exhaustive switch statement 602 switch (statistic) { 603 case GEOMETRIC_MEAN: 604 stat = getGeometricMean(); 605 break; 606 case KURTOSIS: 607 stat = getKurtosis(); 608 break; 609 case MAX: 610 stat = Statistics.getResultAsIntOrNull(max); 611 break; 612 case MEAN: 613 stat = getMean(); 614 break; 615 case MIN: 616 stat = Statistics.getResultAsIntOrNull(min); 617 break; 618 case PRODUCT: 619 stat = Statistics.getResultAsDoubleOrNull(product); 620 break; 621 case SKEWNESS: 622 stat = getSkewness(); 623 break; 624 case STANDARD_DEVIATION: 625 stat = getStandardDeviation(); 626 break; 627 case SUM: 628 stat = Statistics.getResultAsBigIntegerOrNull(sum); 629 break; 630 case SUM_OF_LOGS: 631 stat = Statistics.getResultAsDoubleOrNull(sumOfLogs); 632 break; 633 case SUM_OF_SQUARES: 634 stat = Statistics.getResultAsBigIntegerOrNull(sumOfSquares); 635 break; 636 case VARIANCE: 637 stat = getVariance(); 638 break; 639 } 640 if (stat != null) { 641 return stat; 642 } 643 throw new IllegalArgumentException(UNSUPPORTED_STATISTIC + statistic); 644 } 645 646 /** 647 * Gets the geometric mean. 648 * 649 * @return a geometric mean supplier (or null if unsupported) 650 */ 651 private StatisticResult getGeometricMean() { 652 if (sumOfLogs != null) { 653 // Return a function that has access to the count and sumOfLogs 654 return () -> GeometricMean.computeGeometricMean(count, sumOfLogs); 655 } 656 return null; 657 } 658 659 /** 660 * Gets the kurtosis. 661 * 662 * @return a kurtosis supplier (or null if unsupported) 663 */ 664 private StatisticResult getKurtosis() { 665 if (moment instanceof SumOfFourthDeviations) { 666 return new Kurtosis((SumOfFourthDeviations) moment) 667 .setBiased(config.isBiased())::getAsDouble; 668 } 669 return null; 670 } 671 672 /** 673 * Gets the mean. 674 * 675 * @return a mean supplier (or null if unsupported) 676 */ 677 private StatisticResult getMean() { 678 if (sum != null) { 679 // Return a function that has access to the count and sum 680 final Int128 s = sum.getSum(); 681 return () -> IntMean.computeMean(s, count); 682 } 683 return null; 684 } 685 686 /** 687 * Gets the skewness. 688 * 689 * @return a skewness supplier (or null if unsupported) 690 */ 691 private StatisticResult getSkewness() { 692 if (moment instanceof SumOfCubedDeviations) { 693 return new Skewness((SumOfCubedDeviations) moment) 694 .setBiased(config.isBiased())::getAsDouble; 695 } 696 return null; 697 } 698 699 /** 700 * Gets the standard deviation. 701 * 702 * @return a standard deviation supplier (or null if unsupported) 703 */ 704 private StatisticResult getStandardDeviation() { 705 return getVarianceOrStd(true); 706 } 707 708 /** 709 * Gets the variance. 710 * 711 * @return a variance supplier (or null if unsupported) 712 */ 713 private StatisticResult getVariance() { 714 return getVarianceOrStd(false); 715 } 716 717 /** 718 * Gets the variance or standard deviation. 719 * 720 * @param std Flag to control if the statistic is the standard deviation. 721 * @return a variance/standard deviation supplier (or null if unsupported) 722 */ 723 private StatisticResult getVarianceOrStd(boolean std) { 724 if (sum != null && sumOfSquares != null) { 725 // Return a function that has access to the count, sum and sum of squares 726 final Int128 s = sum.getSum(); 727 final UInt128 ss = sumOfSquares.getSumOfSquares(); 728 final boolean biased = config.isBiased(); 729 return () -> IntVariance.computeVarianceOrStd(ss, s, count, biased, std); 730 } 731 return null; 732 } 733 734 /** 735 * Combines the state of the {@code other} statistics into this one. 736 * Only {@code this} instance is modified by the {@code combine} operation. 737 * 738 * <p>The {@code other} instance must be <em>compatible</em>. This is {@code true} if the 739 * {@code other} instance returns {@code true} for {@link #isSupported(Statistic)} for 740 * all values of the {@link Statistic} enum which are supported by {@code this} 741 * instance. 742 * 743 * <p>Note that this operation is <em>not symmetric</em>. It may be possible to perform 744 * {@code a.combine(b)} but not {@code b.combine(a)}. In the event that the {@code other} 745 * instance is not compatible then an exception is raised before any state is modified. 746 * 747 * @param other Another set of statistics to be combined. 748 * @return {@code this} instance after combining {@code other}. 749 * @throws IllegalArgumentException if the {@code other} is not compatible 750 */ 751 public IntStatistics combine(IntStatistics other) { 752 // Check compatibility 753 Statistics.checkCombineCompatible(min, other.min); 754 Statistics.checkCombineCompatible(max, other.max); 755 Statistics.checkCombineCompatible(sum, other.sum); 756 Statistics.checkCombineCompatible(product, other.product); 757 Statistics.checkCombineCompatible(sumOfSquares, other.sumOfSquares); 758 Statistics.checkCombineCompatible(sumOfLogs, other.sumOfLogs); 759 Statistics.checkCombineAssignable(moment, other.moment); 760 // Combine 761 count += other.count; 762 Statistics.combine(min, other.min); 763 Statistics.combine(max, other.max); 764 Statistics.combine(sum, other.sum); 765 Statistics.combine(product, other.product); 766 Statistics.combine(sumOfSquares, other.sumOfSquares); 767 Statistics.combine(sumOfLogs, other.sumOfLogs); 768 Statistics.combineMoment(moment, other.moment); 769 return this; 770 } 771 772 /** 773 * Sets the statistics configuration. 774 * 775 * <p>These options only control the final computation of statistics. The configuration 776 * will not affect compatibility between instances during a 777 * {@link #combine(IntStatistics) combine} operation. 778 * 779 * <p>Note: These options will affect any future computation of statistics. Supplier functions 780 * that have been previously created will not be updated with the new configuration. 781 * 782 * @param v Value. 783 * @return {@code this} instance 784 * @throws NullPointerException if the value is null 785 * @see #getResult(Statistic) 786 */ 787 public IntStatistics setConfiguration(StatisticsConfiguration v) { 788 config = Objects.requireNonNull(v); 789 return this; 790 } 791}