# HG changeset patch # User bpb # Date 1378399108 25200 # Node ID 8eba1c47f58cd797498d0452fdac01d7495b50f8 # Parent c6a4df06d57e3cfc764c68864e3550b4255df668 8010430: Math.round has surprising behavior for odd values of ulp 1 Summary: If the effective floating point exponent is zero return the significand including the implicit 1-bit. Reviewed-by: bpb, darcy, gls Contributed-by: Dmitry Nadezhin diff --git a/src/share/classes/java/lang/Math.java b/src/share/classes/java/lang/Math.java --- a/src/share/classes/java/lang/Math.java +++ b/src/share/classes/java/lang/Math.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -646,7 +646,7 @@ /** * Returns the closest {@code int} to the argument, with ties - * rounding up. + * rounding to positive infinity. * *

* Special cases: @@ -665,15 +665,37 @@ * @see java.lang.Integer#MIN_VALUE */ public static int round(float a) { - if (a != 0x1.fffffep-2f) // greatest float value less than 0.5 - return (int)floor(a + 0.5f); - else - return 0; + int intBits = Float.floatToRawIntBits(a); + int biasedExp = (intBits & FloatConsts.EXP_BIT_MASK) + >> (FloatConsts.SIGNIFICAND_WIDTH - 1); + int shift = (FloatConsts.SIGNIFICAND_WIDTH - 2 + + FloatConsts.EXP_BIAS) - biasedExp; + if ((shift & -32) == 0) { // shift >= 0 && shift < 32 + // a is a finite number such that pow(2,-32) <= ulp(a) < 1 + int r = ((intBits & FloatConsts.SIGNIF_BIT_MASK) + | (FloatConsts.SIGNIF_BIT_MASK + 1)); + if (intBits < 0) { + r = -r; + } + // In the comments below each Java expression evaluates to the value + // the corresponding mathematical expression: + // (r) evaluates to a / ulp(a) + // (r >> shift) evaluates to floor(a * 2) + // ((r >> shift) + 1) evaluates to floor((a + 1/2) * 2) + // (((r >> shift) + 1) >> 1) evaluates to floor(a + 1/2) + return ((r >> shift) + 1) >> 1; + } else { + // a is either + // - a finite number with abs(a) < exp(2,FloatConsts.SIGNIFICAND_WIDTH-32) < 1/2 + // - a finite number with ulp(a) >= 1 and hence a is a mathematical integer + // - an infinity or NaN + return (int) a; + } } /** * Returns the closest {@code long} to the argument, with ties - * rounding up. + * rounding to positive infinity. * *

Special cases: *