8253409: Double-rounding possibility in float fma
Reviewed-by: bpb
This commit is contained in:
parent
3132b1c4b1
commit
e5304b3a99
@ -1886,32 +1886,21 @@ public final class Math {
|
|||||||
*/
|
*/
|
||||||
@IntrinsicCandidate
|
@IntrinsicCandidate
|
||||||
public static float fma(float a, float b, float c) {
|
public static float fma(float a, float b, float c) {
|
||||||
/*
|
if (Float.isFinite(a) && Float.isFinite(b) && Float.isFinite(c)) {
|
||||||
* Since the double format has more than twice the precision
|
if (a == 0.0 || b == 0.0) {
|
||||||
* of the float format, the multiply of a * b is exact in
|
return a * b + c; // Handled signed zero cases
|
||||||
* double. The add of c to the product then incurs one
|
} else {
|
||||||
* rounding error. Since the double format moreover has more
|
return (new BigDecimal((double)a * (double)b) // Exact multiply
|
||||||
* than (2p + 2) precision bits compared to the p bits of the
|
.add(new BigDecimal((double)c))) // Exact sum
|
||||||
* float format, the two roundings of (a * b + c), first to
|
.floatValue(); // One rounding
|
||||||
* the double format and then secondarily to the float format,
|
// to a float value
|
||||||
* are equivalent to rounding the intermediate result directly
|
}
|
||||||
* to the float format.
|
} else {
|
||||||
*
|
// At least one of a,b, and c is non-finite. The result
|
||||||
* In terms of strictfp vs default-fp concerns related to
|
// will be non-finite as well and will be the same
|
||||||
* overflow and underflow, since
|
// non-finite value under double as float arithmetic.
|
||||||
*
|
return (float)fma((double)a, (double)b, (double)c);
|
||||||
* (Float.MAX_VALUE * Float.MAX_VALUE) << Double.MAX_VALUE
|
}
|
||||||
* (Float.MIN_VALUE * Float.MIN_VALUE) >> Double.MIN_VALUE
|
|
||||||
*
|
|
||||||
* neither the multiply nor add will overflow or underflow in
|
|
||||||
* double. Therefore, it is not necessary for this method to
|
|
||||||
* be declared strictfp to have reproducible
|
|
||||||
* behavior. However, it is necessary to explicitly store down
|
|
||||||
* to a float variable to avoid returning a value in the float
|
|
||||||
* extended value set.
|
|
||||||
*/
|
|
||||||
float result = (float)(((double) a * (double) b ) + (double) c);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -23,11 +23,12 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @bug 4851642
|
* @bug 4851642 8253409
|
||||||
* @summary Tests for Math.fusedMac and StrictMath.fusedMac.
|
* @summary Tests for Math.fusedMac and StrictMath.fusedMac.
|
||||||
* @build Tests
|
* @build Tests
|
||||||
* @build FusedMultiplyAddTests
|
* @build FusedMultiplyAddTests
|
||||||
* @run main FusedMultiplyAddTests
|
* @run main FusedMultiplyAddTests
|
||||||
|
* @run main/othervm -XX:-UseFMA FusedMultiplyAddTests
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -350,6 +351,9 @@ public class FusedMultiplyAddTests {
|
|||||||
|
|
||||||
{1.0f+Math.ulp(1.0f), 1.0f+Math.ulp(1.0f), -1.0f-2.0f*Math.ulp(1.0f),
|
{1.0f+Math.ulp(1.0f), 1.0f+Math.ulp(1.0f), -1.0f-2.0f*Math.ulp(1.0f),
|
||||||
Math.ulp(1.0f)*Math.ulp(1.0f)},
|
Math.ulp(1.0f)*Math.ulp(1.0f)},
|
||||||
|
|
||||||
|
// Double-rounding if done in double precision
|
||||||
|
{0x1.fffffep23f, 0x1.000004p28f, 0x1.fep5f, 0x1.000002p52f}
|
||||||
};
|
};
|
||||||
|
|
||||||
for (float[] testCase: testCases)
|
for (float[] testCase: testCases)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user