Fix "FastMath#round(..)" to comply to changed contract of "Math#round()" in Java 8
Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/83b70a37 Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/83b70a37 Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/83b70a37 Branch: refs/heads/develop Commit: 83b70a377f79ba90f846b3a720e6c402c63bccc5 Parents: 540564e Author: Thomas Neidhart <[email protected]> Authored: Fri Aug 5 15:17:43 2016 +0200 Committer: Emmanuel Bourg <[email protected]> Committed: Fri Aug 5 15:17:43 2016 +0200 ---------------------------------------------------------------------- .../org/apache/commons/math4/util/FastMath.java | 40 +- .../apache/commons/math4/util/FastMathTest.java | 1019 ++++++++---------- 2 files changed, 505 insertions(+), 554 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/commons-math/blob/83b70a37/src/main/java/org/apache/commons/math4/util/FastMath.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/commons/math4/util/FastMath.java b/src/main/java/org/apache/commons/math4/util/FastMath.java index 2532c62..dbcd266 100644 --- a/src/main/java/org/apache/commons/math4/util/FastMath.java +++ b/src/main/java/org/apache/commons/math4/util/FastMath.java @@ -3510,7 +3510,25 @@ public class FastMath { * @return closest long to x */ public static long round(double x) { - return (long) floor(x + 0.5); + final long bits = Double.doubleToRawLongBits(x); + final int biasedExp = ((int)(bits>>52)) & 0x7ff; + // Shift to get rid of bits past comma except first one: will need to + // 1-shift to the right to end up with correct magnitude. + final int shift = (52 - 1 + Double.MAX_EXPONENT) - biasedExp; + if ((shift & -64) == 0) { + // shift in [0,63], so unbiased exp in [-12,51]. + long extendedMantissa = 0x0010000000000000L | (bits & 0x000fffffffffffffL); + if (bits < 0) { + extendedMantissa = -extendedMantissa; + } + // If value is positive and first bit past comma is 0, rounding + // to lower integer, else to upper one, which is what "+1" and + // then ">>1" do. + return ((extendedMantissa >> shift) + 1L) >> 1; + } else { + // +-Infinity, NaN, or a mathematical integer. + return (long) x; + } } /** Get the closest int to x. @@ -3518,7 +3536,25 @@ public class FastMath { * @return closest int to x */ public static int round(final float x) { - return (int) floor(x + 0.5f); + final int bits = Float.floatToRawIntBits(x); + final int biasedExp = (bits>>23) & 0xff; + // Shift to get rid of bits past comma except first one: will need to + // 1-shift to the right to end up with correct magnitude. + final int shift = (23 - 1 + Float.MAX_EXPONENT) - biasedExp; + if ((shift & -32) == 0) { + // shift in [0,31], so unbiased exp in [-9,22]. + int extendedMantissa = 0x00800000 | (bits & 0x007fffff); + if (bits < 0) { + extendedMantissa = -extendedMantissa; + } + // If value is positive and first bit past comma is 0, rounding + // to lower integer, else to upper one, which is what "+1" and + // then ">>1" do. + return ((extendedMantissa >> shift) + 1) >> 1; + } else { + // +-Infinity, NaN, or a mathematical integer. + return (int) x; + } } /** Compute the minimum of two values
