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
getRoundingDirection(bool isEven,bool isNegative,Section section,RoundingMode roundingMode,UErrorCode & status)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 */
roundsAtMidpoint(int roundingMode)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