/// <summary> /// Rounds the given non-negative value to the "nearest" integer. Nearest is /// determined by the rounding method specified. Rounding methods are defined /// in <seealso cref="BigDecimal"/>. /// </summary> /// <param name="unscaled"> Value to round. </param> /// <param name="sign"> Sign of the original, scaled value. </param> /// <param name="roundingMethod"> Rounding method, as defined in <seealso cref="BigDecimal"/>. </param> /// <returns> the rounded value. </returns> /// <exception cref="MathArithmeticException"> if an exact operation is required but result is not exact </exception> /// <exception cref="MathIllegalArgumentException"> if {@code roundingMethod} is not a valid rounding method. /// @since 1.1 (previously in {@code MathUtils}, moved as of version 3.0) </exception> private static double RoundUnscaled(double unscaled, double sign, int roundingMethod) { switch (roundingMethod) { case decimal.ROUND_CEILING: if (sign == -1) { unscaled = FastMath.Floor(FastMath.nextAfter(unscaled, double.NegativeInfinity)); } else { unscaled = FastMath.Ceil(FastMath.nextAfter(unscaled, double.PositiveInfinity)); } break; case decimal.ROUND_DOWN: unscaled = FastMath.Floor(FastMath.nextAfter(unscaled, double.NegativeInfinity)); break; case decimal.ROUND_FLOOR: if (sign == -1) { unscaled = FastMath.Ceil(FastMath.nextAfter(unscaled, double.PositiveInfinity)); } else { unscaled = FastMath.Floor(FastMath.nextAfter(unscaled, double.NegativeInfinity)); } break; case decimal.ROUND_HALF_DOWN: { unscaled = FastMath.nextAfter(unscaled, double.NegativeInfinity); double fraction = unscaled - FastMath.Floor(unscaled); if (fraction > 0.5) { unscaled = FastMath.Ceil(unscaled); } else { unscaled = FastMath.Floor(unscaled); } break; } case decimal.ROUND_HALF_EVEN: { double fraction = unscaled - FastMath.Floor(unscaled); if (fraction > 0.5) { unscaled = FastMath.Ceil(unscaled); } else if (fraction < 0.5) { unscaled = FastMath.Floor(unscaled); } else { // The following equality test is intentional and needed for rounding purposes if (FastMath.Floor(unscaled) / 2.0 == FastMath.Floor(FastMath.Floor(unscaled) / 2.0)) { // even unscaled = FastMath.Floor(unscaled); } else { // odd unscaled = FastMath.Ceil(unscaled); } } break; } case decimal.ROUND_HALF_UP: { unscaled = FastMath.nextAfter(unscaled, double.PositiveInfinity); double fraction = unscaled - FastMath.Floor(unscaled); if (fraction >= 0.5) { unscaled = FastMath.Ceil(unscaled); } else { unscaled = FastMath.Floor(unscaled); } break; } case decimal.ROUND_UNNECESSARY: if (unscaled != FastMath.Floor(unscaled)) { throw new MathArithmeticException(); } break; case decimal.ROUND_UP: // do not round if the discarded fraction is equal to zero if (unscaled != FastMath.Floor(unscaled)) { unscaled = FastMath.Ceil(FastMath.nextAfter(unscaled, double.PositiveInfinity)); } break; default: throw new MathIllegalArgumentException(LocalizedFormats.INVALID_ROUNDING_METHOD, roundingMethod, "ROUND_CEILING", decimal.ROUND_CEILING, "ROUND_DOWN", decimal.ROUND_DOWN, "ROUND_FLOOR", decimal.ROUND_FLOOR, "ROUND_HALF_DOWN", decimal.ROUND_HALF_DOWN, "ROUND_HALF_EVEN", decimal.ROUND_HALF_EVEN, "ROUND_HALF_UP", decimal.ROUND_HALF_UP, "ROUND_UNNECESSARY", decimal.ROUND_UNNECESSARY, "ROUND_UP", decimal.ROUND_UP); } return(unscaled); }