Skip to content
This repository was archived by the owner on Sep 2, 2022. It is now read-only.

Commit b7470f4

Browse files
committed
8253409: Double-rounding possibility in float fma
Backport-of: e5304b3a994b1e291e4ac5258f473dd7874f163f
1 parent b7b2f61 commit b7470f4

File tree

2 files changed

+21
-28
lines changed

2 files changed

+21
-28
lines changed

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

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,32 +1830,21 @@ public static double fma(double a, double b, double c) {
18301830
*/
18311831
@IntrinsicCandidate
18321832
public static float fma(float a, float b, float c) {
1833-
/*
1834-
* Since the double format has more than twice the precision
1835-
* of the float format, the multiply of a * b is exact in
1836-
* double. The add of c to the product then incurs one
1837-
* rounding error. Since the double format moreover has more
1838-
* than (2p + 2) precision bits compared to the p bits of the
1839-
* float format, the two roundings of (a * b + c), first to
1840-
* the double format and then secondarily to the float format,
1841-
* are equivalent to rounding the intermediate result directly
1842-
* to the float format.
1843-
*
1844-
* In terms of strictfp vs default-fp concerns related to
1845-
* overflow and underflow, since
1846-
*
1847-
* (Float.MAX_VALUE * Float.MAX_VALUE) << Double.MAX_VALUE
1848-
* (Float.MIN_VALUE * Float.MIN_VALUE) >> Double.MIN_VALUE
1849-
*
1850-
* neither the multiply nor add will overflow or underflow in
1851-
* double. Therefore, it is not necessary for this method to
1852-
* be declared strictfp to have reproducible
1853-
* behavior. However, it is necessary to explicitly store down
1854-
* to a float variable to avoid returning a value in the float
1855-
* extended value set.
1856-
*/
1857-
float result = (float)(((double) a * (double) b ) + (double) c);
1858-
return result;
1833+
if (Float.isFinite(a) && Float.isFinite(b) && Float.isFinite(c)) {
1834+
if (a == 0.0 || b == 0.0) {
1835+
return a * b + c; // Handled signed zero cases
1836+
} else {
1837+
return (new BigDecimal((double)a * (double)b) // Exact multiply
1838+
.add(new BigDecimal((double)c))) // Exact sum
1839+
.floatValue(); // One rounding
1840+
// to a float value
1841+
}
1842+
} else {
1843+
// At least one of a,b, and c is non-finite. The result
1844+
// will be non-finite as well and will be the same
1845+
// non-finite value under double as float arithmetic.
1846+
return (float)fma((double)a, (double)b, (double)c);
1847+
}
18591848
}
18601849

18611850
/**

test/jdk/java/lang/Math/FusedMultiplyAddTests.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,12 @@
2323

2424
/*
2525
* @test
26-
* @bug 4851642
26+
* @bug 4851642 8253409
2727
* @summary Tests for Math.fusedMac and StrictMath.fusedMac.
2828
* @build Tests
2929
* @build FusedMultiplyAddTests
3030
* @run main FusedMultiplyAddTests
31+
* @run main/othervm -XX:-UseFMA FusedMultiplyAddTests
3132
*/
3233

3334
/**
@@ -350,6 +351,9 @@ private static int testSimpleF() {
350351

351352
{1.0f+Math.ulp(1.0f), 1.0f+Math.ulp(1.0f), -1.0f-2.0f*Math.ulp(1.0f),
352353
Math.ulp(1.0f)*Math.ulp(1.0f)},
354+
355+
// Double-rounding if done in double precision
356+
{0x1.fffffep23f, 0x1.000004p28f, 0x1.fep5f, 0x1.000002p52f}
353357
};
354358

355359
for (float[] testCase: testCases)

0 commit comments

Comments
 (0)