< prev index next >

## src/java.base/share/classes/java/lang/Math.java

```*** 23,32 ****
--- 23,33 ----
* questions.
*/

package java.lang;

+ import java.math.BigDecimal;
import java.util.Random;
import jdk.internal.math.FloatConsts;
import jdk.internal.math.DoubleConsts;
import jdk.internal.HotSpotIntrinsicCandidate;

*** 1448,1457 ****
--- 1449,1621 ----
}
return (a <= b) ? a : b;
}

/**
+      * Returns the fused multiply-accumulate of the three arguments;
+      * that is, returns the exact product of the first two arguments
+      * summed with the third argument and then rounded once to the
+      * nearest {@code double}.
+      *
+      * The rounding is done using the {@linkplain
+      * java.math.RoundingMode#HALF_EVEN round to nearest even
+      * rounding mode}.
+      *
+      * In contrast, if {@code a * b + c} is evaluated as a regular
+      * floating-point expression, two rounding errors are involved,
+      * the first for the multiply operation, the second for the
+      *
+      * <p>Special cases:
+      * <ul>
+      * <li> If any argument is NaN, the result is NaN.
+      *
+      * <li> If one of the first two arguments is infinite and the
+      * other is zero, the result is NaN.
+      *
+      * <li> If the exact product of the first two arguments is infinite
+      * (in other words, at least one of the arguments is infinite and
+      * the other is neither zero nor NaN) and the third argument is an
+      * infinity of the opposite sign, the result is NaN.
+      *
+      * </ul>
+      *
+      * <p>Note that {@code fusedMac(a, 1.0, c)} returns the same
+      * result as ({@code a + c}).  However,
+      * {@code fusedMac(a, b, +0.0)} does <em>not</em> always return the
+      * same result as ({@code a * b}) since
+      * {@code fusedMac(-0.0, +0.0, +0.0)} is {@code +0.0} while
+      * ({@code 0.0 * +0.0}) is {@code -0.0}; {@code fusedMac(a, b, -0.0)} is
+      * equivalent to ({@code a * b}) however.
+      *
+      * @param a a value
+      * @param b a value
+      * @param c a value
+      *
+      * @return (<i>a</i>&nbsp;&times;&nbsp;<i>b</i>&nbsp;+&nbsp;<i>c</i>)
+      * computed, as if with unlimited range and precision, and rounded
+      * once to the nearest {@code double} value
+      */
+     // @HotSpotIntrinsicCandidate
+     public static double fusedMac(double a, double b, double c) {
+         if (!Double.isFinite(a) ||
+             !Double.isFinite(b) ||
+             !Double.isFinite(c)) {
+             // Infinite and NaN arithmetic is not quite the same with
+             // two roundings as opposed to just one. With two
+             // roundings, the product and overflow and if the addend
+             // is infinite, a spurious NaN can be produced.
+
+             if (Double.isNaN(a) || Double.isNaN(b) || Double.isNaN(c)) {
+                 return Double.NaN;
+             } else { // One or more infinities in the input
+                 if ((Double.isInfinite(a) && b == 0.0) ||
+                     (Double.isInfinite(b) && a == 0.0)) {
+                     return Double.NaN;
+                 } else {
+                     double product = a * b;
+                     double result = product + c;
+                     if (Double.isInfinite(product) &&
+                         (!Double.isInfinite(a) && !Double.isInfinite(b))) {
+                         // Intermediate overflow; might cause a
+                         // spurious NaN with added to infinite c.
+                         return c;
+                     }
+                     return result;
+                 }
+             }
+         } if (a == 1.0 || // Could just return b + c
+               b == 1.0 || // Could just return a + c
+               a == 0.0 || // Handle any signed zero issues
+               b == 0.0 || // Handle any signed zero issues
+               c == 0.0) { // Could be +0.0 or -0.0)
+             // The special cases of a == 1.0, b == 1.0, and c == 0.0
+             // are handled as double operations rather than falling
+             // back on BigDecimal. The case where a == 1.0 or b == 1.0
+             // would be handled correctly by the BigDecimal code
+             // below, unlike the signed zero case where the exact
+             // product is -0.0 and c is -0.0.
+
+             // As noted above, if c is zero, it must still be added in
+             // since a negative zero can change the sign of the final
+             // result if the product is zero. At the cost of
+             // additional checks on a and b, the addition of a zero c
+             // could be avoided.
+
+             return a * b + c;
+         } else {
+             // The set of values representable in BigDecimal includes
+             // neither signed zero nor infinities nor NaN. The logic
+             // above handles those cases. All finite double values are
+             // representable in BigDecimal. The code below exactly
+             // converts a, b, and c to their equivalent BigDecimal
+             // numbers, exactly computes the product and sum as
+             // appropriate, and then performs a single rounding to
+             // double using the round to nearest rounding mode.
+             return (((new BigDecimal(a)).multiply(new BigDecimal(b))).
+         }
+     }
+
+     /**
+      * Returns the fused multiply-accumulate of the three arguments;
+      * that is, returns the exact product of the first two arguments
+      * summed with the third argument and then rounded once to the
+      * nearest {@code float}.
+      *
+      * The rounding is done using the {@linkplain
+      * java.math.RoundingMode#HALF_EVEN round to nearest even
+      * rounding mode}.
+      *
+      * In contrast, if {@code a * b + c} is evaluated as a regular
+      * floating-point expression, two rounding errors are involved,
+      * the first for the multiply operation, the second for the
+      *
+      * <p>Special cases:
+      * <ul>
+      * <li> If any argument is NaN, the result is NaN.
+      *
+      * <li> If one of the first two arguments is infinite and the
+      * other is zero, the result is NaN.
+      *
+      * <li> If the exact product of the first two arguments is infinite
+      * (in other words, at least one of the arguments is infinite and
+      * the other is neither zero nor NaN) and the third argument is an
+      * infinity of the opposite sign, the result is NaN.
+      *
+      * </ul>
+      *
+      * <p>Note that {@code fusedMac(a, 1.0f, c)} returns the same
+      * result as ({@code a + c}).  However,
+      * {@code fusedMac(a, b, +0.0f)} does <em>not</em> always return the
+      * same result as ({@code a * b}) since
+      * {@code fusedMac(-0.0f, +0.0f, +0.0f)} is {@code +0.0f} while
+      * ({@code 0.0f * +0.0f}) is {@code -0.0f}; {@code fusedMac(a, b, -0.0f)} is
+      * equivalent to ({@code a * b}) however.
+      *
+      * @param a a value
+      * @param b a value
+      * @param c a value
+      *
+      * @return (<i>a</i>&nbsp;&times;&nbsp;<i>b</i>&nbsp;+&nbsp;<i>c</i>)
+      * computed, as if with unlimited range and precision, and rounded
+      * once to the nearest {@code float} value
+      */
+     // @HotSpotIntrinsicCandidate
+     public static float fusedMac(float a, float b, float c) {
+         // Since double has more than twice the precision of float,
+         // the multiply of a * b is exact in double. The add of c to
+         // the product then has one rounded error. Since double
+         // moreover has more than 2p + 2 precision compared to float,
+         // the double rounding of (a*b + c) from the double format to
+         // the float format is equivalent to rounding the result
+         // directly to float precision.
+         return (float)(((double) a * (double) b ) + (double) c);
+     }
+
+     /**
* Returns the size of an ulp of the argument.  An ulp, unit in
* the last place, of a {@code double} value is the positive
* distance between this floating-point value and the {@code
* double} value next larger in magnitude.  Note that for non-NaN
* <i>x</i>, <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>.
```
< prev index next >