1 // © 2017 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT 7 #ifndef __NUMBER_ROUNDINGUTILS_H__ 8 #define __NUMBER_ROUNDINGUTILS_H__ 9 10 #include "number_types.h" 11 12 U_NAMESPACE_BEGIN 13 namespace number { 14 namespace impl { 15 namespace roundingutils { 16 17 enum Section { 18 SECTION_LOWER_EDGE = -1, 19 SECTION_UPPER_EDGE = -2, 20 SECTION_LOWER = 1, 21 SECTION_MIDPOINT = 2, 22 SECTION_UPPER = 3 23 }; 24 25 /** 26 * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining 27 * whether the value should be rounded toward infinity or toward zero. 28 * 29 * <p>The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK 30 * showed that ints were demonstrably faster than enums in switch statements. 31 * 32 * @param isEven Whether the digit immediately before the rounding magnitude is even. 33 * @param isNegative Whether the quantity is negative. 34 * @param section Whether the part of the quantity to the right of the rounding magnitude is 35 * exactly halfway between two digits, whether it is in the lower part (closer to zero), or 36 * whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER}, {@link 37 * #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}. 38 * @param roundingMode The integer version of the {@link RoundingMode}, which you can get via 39 * {@link RoundingMode#ordinal}. 40 * @param status Error code, set to U_FORMAT_INEXACT_ERROR if the rounding mode is kRoundUnnecessary. 41 * @return true if the number should be rounded toward zero; false if it should be rounded toward 42 * infinity. 43 */ 44 inline bool 45 getRoundingDirection(bool isEven, bool isNegative, Section section, RoundingMode roundingMode, 46 UErrorCode &status) { 47 switch (roundingMode) { 48 case RoundingMode::UNUM_ROUND_UP: 49 // round away from zero 50 return false; 51 52 case RoundingMode::UNUM_ROUND_DOWN: 53 // round toward zero 54 return true; 55 56 case RoundingMode::UNUM_ROUND_CEILING: 57 // round toward positive infinity 58 return isNegative; 59 60 case RoundingMode::UNUM_ROUND_FLOOR: 61 // round toward negative infinity 62 return !isNegative; 63 64 case RoundingMode::UNUM_ROUND_HALFUP: 65 switch (section) { 66 case SECTION_MIDPOINT: 67 return false; 68 case SECTION_LOWER: 69 return true; 70 case SECTION_UPPER: 71 return false; 72 default: 73 break; 74 } 75 break; 76 77 case RoundingMode::UNUM_ROUND_HALFDOWN: 78 switch (section) { 79 case SECTION_MIDPOINT: 80 return true; 81 case SECTION_LOWER: 82 return true; 83 case SECTION_UPPER: 84 return false; 85 default: 86 break; 87 } 88 break; 89 90 case RoundingMode::UNUM_ROUND_HALFEVEN: 91 switch (section) { 92 case SECTION_MIDPOINT: 93 return isEven; 94 case SECTION_LOWER: 95 return true; 96 case SECTION_UPPER: 97 return false; 98 default: 99 break; 100 } 101 break; 102 103 default: 104 break; 105 } 106 107 status = U_FORMAT_INEXACT_ERROR; 108 return false; 109 } 110 111 /** 112 * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding 113 * boundary is the point at which a number switches from being rounded down to being rounded up. 114 * For example, with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at 115 * the midpoint, and this function would return true. However, for UP, DOWN, CEILING, and FLOOR, 116 * the rounding boundary is at the "edge", and this function would return false. 117 * 118 * @param roundingMode The integer version of the {@link RoundingMode}. 119 * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise. 120 */ 121 inline bool roundsAtMidpoint(int roundingMode) { 122 switch (roundingMode) { 123 case RoundingMode::UNUM_ROUND_UP: 124 case RoundingMode::UNUM_ROUND_DOWN: 125 case RoundingMode::UNUM_ROUND_CEILING: 126 case RoundingMode::UNUM_ROUND_FLOOR: 127 return false; 128 129 default: 130 return true; 131 } 132 } 133 134 } // namespace roundingutils 135 } // namespace impl 136 } // namespace number 137 U_NAMESPACE_END 138 139 #endif //__NUMBER_ROUNDINGUTILS_H__ 140 141 #endif /* #if !UCONFIG_NO_FORMATTING */ 142