You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2023/07/21 09:57:54 UTC

[commons-numbers] branch master updated: NUMBERS-199: Document inaccurate decimal value representation in Precision.round

This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-numbers.git


The following commit(s) were added to refs/heads/master by this push:
     new 844fa942 NUMBERS-199: Document inaccurate decimal value representation in Precision.round
844fa942 is described below

commit 844fa9423d730136c81ee0a4f27ed63ad8cf8fba
Author: aherbert <ah...@apache.org>
AuthorDate: Fri Jul 21 10:56:55 2023 +0100

    NUMBERS-199: Document inaccurate decimal value representation in Precision.round
---
 .../org/apache/commons/numbers/core/Precision.java | 55 ++++++++++++++++++----
 1 file changed, 47 insertions(+), 8 deletions(-)

diff --git a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java
index a0a19ec6..4fa6fb9e 100644
--- a/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java
+++ b/commons-numbers-core/src/main/java/org/apache/commons/numbers/core/Precision.java
@@ -410,11 +410,16 @@ public final class Precision {
 
     /**
      * Rounds the given value to the specified number of decimal places.
-     * The value is rounded using the {@link RoundingMode#HALF_UP} method.
+     * The value is rounded using {@link RoundingMode#HALF_UP}.
+     *
+     * <p>Note: This method is intended to act on the String representation
+     * of the {@code double} argument. See {@link #round(double, int, RoundingMode)}
+     * for details.
      *
      * @param x Value to round.
      * @param scale Number of digits to the right of the decimal point.
      * @return the rounded value.
+     * @see #round(double, int, RoundingMode)
      */
     public static double round(double x, int scale) {
         return round(x, scale, RoundingMode.HALF_UP);
@@ -422,25 +427,59 @@ public final class Precision {
 
     /**
      * Rounds the given value to the specified number of decimal places.
-     * The value is rounded using the given method which is any method defined
-     * in {@link BigDecimal}.
-     * If {@code x} is infinite or {@code NaN}, then the value of {@code x} is
+     * The value is rounded using the given {@link RoundingMode rounding mode}.
+     *
+     * <p>If {@code x} is infinite or {@code NaN}, then the value of {@code x} is
      * returned unchanged, regardless of the other parameters.
      *
+     * <p><b>Note</b>
+     *
+     * <p>Rounding of a 64-bit base-2 format {@code double} using a decimal representation
+     * may result in rounding during conversion to and/or from a base-10 representation.
+     *
+     * <p>This method is intended to act on the String representation of the {@code double}
+     * argument, i.e. the closest representable decimal value. The argument is converted to
+     * a String (with possible rounding), rounding is performed on the decimal representation,
+     * and the resulting String is returned as the closest representable {@code double}.
+     *
+     * <p>Conversion from base-2 to base-10 format uses the {@link BigDecimal#valueOf(double)}
+     * method. The alternative would be to use
+     * {@link BigDecimal#BigDecimal(double) new BigDecimal(x)} to construct an exact decimal
+     * representation of the value.
+     *
+     * <p>Conversion from base-10 to base-2 format uses the equivalent of
+     * {@link Double#parseDouble(String)} to create the closest representable {@code double}
+     * to the decimal value.
+     *
+     * <p>The following code demonstrates how to eliminate rounding during conversion to a
+     * decimal format. The return conversion to a {@code double} may be inexact:
+     * <pre>
+     * double rounded = new BigDecimal(x).setScale(scale, roundingMode).doubleValue();
+     * </pre>
+     *
+     * <p>Acting on the String representation of the {@code double} allows this method to
+     * return expected output when rounding {@code double} representations of decimal text.
+     * <pre>
+     * Precision.round(39.245, 2) == 39.25
+     * Precision.round(30.095, 2) == 30.1
+     * Precision.round(30.645, 2) == 30.65
+     * </pre>
+     *
      * @param x Value to round.
      * @param scale Number of digits to the right of the decimal point.
-     * @param roundingMethod Rounding method as defined in {@link BigDecimal}.
+     * @param roundingMode Rounding mode as defined in {@link BigDecimal}.
      * @return the rounded value.
-     * @throws ArithmeticException if {@code roundingMethod} is
+     * @see BigDecimal#doubleValue()
+     * @throws ArithmeticException if {@code roundingMode} is
      * {@link RoundingMode#UNNECESSARY} and the specified scaling operation
      * would require rounding.
      */
     public static double round(double x,
                                int scale,
-                               RoundingMode roundingMethod) {
+                               RoundingMode roundingMode) {
         try {
             final double rounded = (new BigDecimal(Double.toString(x))
-                   .setScale(scale, roundingMethod))
+                   .setScale(scale, roundingMode))
                    .doubleValue();
             // MATH-1089: negative values rounded to zero should result in negative zero
             return rounded == POSITIVE_ZERO ? POSITIVE_ZERO * x : rounded;