// © 2017 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT #ifndef __NUMBER_ROUNDINGUTILS_H__ #define __NUMBER_ROUNDINGUTILS_H__ #include "number_types.h" U_NAMESPACE_BEGIN namespace number { namespace impl { namespace roundingutils { enum Section { SECTION_LOWER_EDGE = -1, SECTION_UPPER_EDGE = -2, SECTION_LOWER = 1, SECTION_MIDPOINT = 2, SECTION_UPPER = 3 }; /** * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining * whether the value should be rounded toward infinity or toward zero. * * <p>The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK * showed that ints were demonstrably faster than enums in switch statements. * * @param isEven Whether the digit immediately before the rounding magnitude is even. * @param isNegative Whether the quantity is negative. * @param section Whether the part of the quantity to the right of the rounding magnitude is * exactly halfway between two digits, whether it is in the lower part (closer to zero), or * whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER}, {@link * #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}. * @param roundingMode The integer version of the {@link RoundingMode}, which you can get via * {@link RoundingMode#ordinal}. * @param status Error code, set to U_FORMAT_INEXACT_ERROR if the rounding mode is kRoundUnnecessary. * @return true if the number should be rounded toward zero; false if it should be rounded toward * infinity. */ inline bool getRoundingDirection(bool isEven, bool isNegative, Section section, RoundingMode roundingMode, UErrorCode &status) { switch (roundingMode) { case RoundingMode::UNUM_ROUND_UP: // round away from zero return false; case RoundingMode::UNUM_ROUND_DOWN: // round toward zero return true; case RoundingMode::UNUM_ROUND_CEILING: // round toward positive infinity return isNegative; case RoundingMode::UNUM_ROUND_FLOOR: // round toward negative infinity return !isNegative; case RoundingMode::UNUM_ROUND_HALFUP: switch (section) { case SECTION_MIDPOINT: return false; case SECTION_LOWER: return true; case SECTION_UPPER: return false; default: break; } break; case RoundingMode::UNUM_ROUND_HALFDOWN: switch (section) { case SECTION_MIDPOINT: return true; case SECTION_LOWER: return true; case SECTION_UPPER: return false; default: break; } break; case RoundingMode::UNUM_ROUND_HALFEVEN: switch (section) { case SECTION_MIDPOINT: return isEven; case SECTION_LOWER: return true; case SECTION_UPPER: return false; default: break; } break; default: break; } status = U_FORMAT_INEXACT_ERROR; return false; } /** * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding * boundary is the point at which a number switches from being rounded down to being rounded up. * For example, with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at * the midpoint, and this function would return true. However, for UP, DOWN, CEILING, and FLOOR, * the rounding boundary is at the "edge", and this function would return false. * * @param roundingMode The integer version of the {@link RoundingMode}. * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise. */ inline bool roundsAtMidpoint(int roundingMode) { switch (roundingMode) { case RoundingMode::UNUM_ROUND_UP: case RoundingMode::UNUM_ROUND_DOWN: case RoundingMode::UNUM_ROUND_CEILING: case RoundingMode::UNUM_ROUND_FLOOR: return false; default: return true; } } } // namespace roundingutils } // namespace impl } // namespace number U_NAMESPACE_END #endif //__NUMBER_ROUNDINGUTILS_H__ #endif /* #if !UCONFIG_NO_FORMATTING */