xref: /aosp_15_r20/external/icu/libicu/cts_headers/number_roundingutils.h (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
1*0e209d39SAndroid Build Coastguard Worker // © 2017 and later: Unicode, Inc. and others.
2*0e209d39SAndroid Build Coastguard Worker // License & terms of use: http://www.unicode.org/copyright.html
3*0e209d39SAndroid Build Coastguard Worker 
4*0e209d39SAndroid Build Coastguard Worker #include "unicode/utypes.h"
5*0e209d39SAndroid Build Coastguard Worker 
6*0e209d39SAndroid Build Coastguard Worker #if !UCONFIG_NO_FORMATTING
7*0e209d39SAndroid Build Coastguard Worker #ifndef __NUMBER_ROUNDINGUTILS_H__
8*0e209d39SAndroid Build Coastguard Worker #define __NUMBER_ROUNDINGUTILS_H__
9*0e209d39SAndroid Build Coastguard Worker 
10*0e209d39SAndroid Build Coastguard Worker #include "number_types.h"
11*0e209d39SAndroid Build Coastguard Worker #include "string_segment.h"
12*0e209d39SAndroid Build Coastguard Worker 
13*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_BEGIN
14*0e209d39SAndroid Build Coastguard Worker namespace number::impl {
15*0e209d39SAndroid Build Coastguard Worker namespace roundingutils {
16*0e209d39SAndroid Build Coastguard Worker 
17*0e209d39SAndroid Build Coastguard Worker enum Section {
18*0e209d39SAndroid Build Coastguard Worker     SECTION_LOWER_EDGE = -1,
19*0e209d39SAndroid Build Coastguard Worker     SECTION_UPPER_EDGE = -2,
20*0e209d39SAndroid Build Coastguard Worker     SECTION_LOWER = 1,
21*0e209d39SAndroid Build Coastguard Worker     SECTION_MIDPOINT = 2,
22*0e209d39SAndroid Build Coastguard Worker     SECTION_UPPER = 3
23*0e209d39SAndroid Build Coastguard Worker };
24*0e209d39SAndroid Build Coastguard Worker 
25*0e209d39SAndroid Build Coastguard Worker /**
26*0e209d39SAndroid Build Coastguard Worker  * Converts a rounding mode and metadata about the quantity being rounded to a boolean determining
27*0e209d39SAndroid Build Coastguard Worker  * whether the value should be rounded toward infinity or toward zero.
28*0e209d39SAndroid Build Coastguard Worker  *
29*0e209d39SAndroid Build Coastguard Worker  * <p>The parameters are of type int because benchmarks on an x86-64 processor against OpenJDK
30*0e209d39SAndroid Build Coastguard Worker  * showed that ints were demonstrably faster than enums in switch statements.
31*0e209d39SAndroid Build Coastguard Worker  *
32*0e209d39SAndroid Build Coastguard Worker  * @param isEven Whether the digit immediately before the rounding magnitude is even.
33*0e209d39SAndroid Build Coastguard Worker  * @param isNegative Whether the quantity is negative.
34*0e209d39SAndroid Build Coastguard Worker  * @param section Whether the part of the quantity to the right of the rounding magnitude is
35*0e209d39SAndroid Build Coastguard Worker  *     exactly halfway between two digits, whether it is in the lower part (closer to zero), or
36*0e209d39SAndroid Build Coastguard Worker  *     whether it is in the upper part (closer to infinity). See {@link #SECTION_LOWER}, {@link
37*0e209d39SAndroid Build Coastguard Worker  *     #SECTION_MIDPOINT}, and {@link #SECTION_UPPER}.
38*0e209d39SAndroid Build Coastguard Worker  * @param roundingMode The integer version of the {@link RoundingMode}, which you can get via
39*0e209d39SAndroid Build Coastguard Worker  *     {@link RoundingMode#ordinal}.
40*0e209d39SAndroid Build Coastguard Worker  * @param status Error code, set to U_FORMAT_INEXACT_ERROR if the rounding mode is kRoundUnnecessary.
41*0e209d39SAndroid Build Coastguard Worker  * @return true if the number should be rounded toward zero; false if it should be rounded toward
42*0e209d39SAndroid Build Coastguard Worker  *     infinity.
43*0e209d39SAndroid Build Coastguard Worker  */
44*0e209d39SAndroid Build Coastguard Worker inline bool
getRoundingDirection(bool isEven,bool isNegative,Section section,RoundingMode roundingMode,UErrorCode & status)45*0e209d39SAndroid Build Coastguard Worker getRoundingDirection(bool isEven, bool isNegative, Section section, RoundingMode roundingMode,
46*0e209d39SAndroid Build Coastguard Worker                      UErrorCode &status) {
47*0e209d39SAndroid Build Coastguard Worker     if (U_FAILURE(status)) {
48*0e209d39SAndroid Build Coastguard Worker         return false;
49*0e209d39SAndroid Build Coastguard Worker     }
50*0e209d39SAndroid Build Coastguard Worker     switch (roundingMode) {
51*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_UP:
52*0e209d39SAndroid Build Coastguard Worker             // round away from zero
53*0e209d39SAndroid Build Coastguard Worker             return false;
54*0e209d39SAndroid Build Coastguard Worker 
55*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_DOWN:
56*0e209d39SAndroid Build Coastguard Worker             // round toward zero
57*0e209d39SAndroid Build Coastguard Worker             return true;
58*0e209d39SAndroid Build Coastguard Worker 
59*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_CEILING:
60*0e209d39SAndroid Build Coastguard Worker             // round toward positive infinity
61*0e209d39SAndroid Build Coastguard Worker             return isNegative;
62*0e209d39SAndroid Build Coastguard Worker 
63*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_FLOOR:
64*0e209d39SAndroid Build Coastguard Worker             // round toward negative infinity
65*0e209d39SAndroid Build Coastguard Worker             return !isNegative;
66*0e209d39SAndroid Build Coastguard Worker 
67*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_HALFUP:
68*0e209d39SAndroid Build Coastguard Worker             switch (section) {
69*0e209d39SAndroid Build Coastguard Worker                 case SECTION_MIDPOINT:
70*0e209d39SAndroid Build Coastguard Worker                     return false;
71*0e209d39SAndroid Build Coastguard Worker                 case SECTION_LOWER:
72*0e209d39SAndroid Build Coastguard Worker                     return true;
73*0e209d39SAndroid Build Coastguard Worker                 case SECTION_UPPER:
74*0e209d39SAndroid Build Coastguard Worker                     return false;
75*0e209d39SAndroid Build Coastguard Worker                 default:
76*0e209d39SAndroid Build Coastguard Worker                     break;
77*0e209d39SAndroid Build Coastguard Worker             }
78*0e209d39SAndroid Build Coastguard Worker             break;
79*0e209d39SAndroid Build Coastguard Worker 
80*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_HALFDOWN:
81*0e209d39SAndroid Build Coastguard Worker             switch (section) {
82*0e209d39SAndroid Build Coastguard Worker                 case SECTION_MIDPOINT:
83*0e209d39SAndroid Build Coastguard Worker                     return true;
84*0e209d39SAndroid Build Coastguard Worker                 case SECTION_LOWER:
85*0e209d39SAndroid Build Coastguard Worker                     return true;
86*0e209d39SAndroid Build Coastguard Worker                 case SECTION_UPPER:
87*0e209d39SAndroid Build Coastguard Worker                     return false;
88*0e209d39SAndroid Build Coastguard Worker                 default:
89*0e209d39SAndroid Build Coastguard Worker                     break;
90*0e209d39SAndroid Build Coastguard Worker             }
91*0e209d39SAndroid Build Coastguard Worker             break;
92*0e209d39SAndroid Build Coastguard Worker 
93*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_HALFEVEN:
94*0e209d39SAndroid Build Coastguard Worker             switch (section) {
95*0e209d39SAndroid Build Coastguard Worker                 case SECTION_MIDPOINT:
96*0e209d39SAndroid Build Coastguard Worker                     return isEven;
97*0e209d39SAndroid Build Coastguard Worker                 case SECTION_LOWER:
98*0e209d39SAndroid Build Coastguard Worker                     return true;
99*0e209d39SAndroid Build Coastguard Worker                 case SECTION_UPPER:
100*0e209d39SAndroid Build Coastguard Worker                     return false;
101*0e209d39SAndroid Build Coastguard Worker                 default:
102*0e209d39SAndroid Build Coastguard Worker                     break;
103*0e209d39SAndroid Build Coastguard Worker             }
104*0e209d39SAndroid Build Coastguard Worker             break;
105*0e209d39SAndroid Build Coastguard Worker 
106*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_HALF_ODD:
107*0e209d39SAndroid Build Coastguard Worker             switch (section) {
108*0e209d39SAndroid Build Coastguard Worker                 case SECTION_MIDPOINT:
109*0e209d39SAndroid Build Coastguard Worker                     return !isEven;
110*0e209d39SAndroid Build Coastguard Worker                 case SECTION_LOWER:
111*0e209d39SAndroid Build Coastguard Worker                     return true;
112*0e209d39SAndroid Build Coastguard Worker                 case SECTION_UPPER:
113*0e209d39SAndroid Build Coastguard Worker                     return false;
114*0e209d39SAndroid Build Coastguard Worker                 default:
115*0e209d39SAndroid Build Coastguard Worker                     break;
116*0e209d39SAndroid Build Coastguard Worker             }
117*0e209d39SAndroid Build Coastguard Worker             break;
118*0e209d39SAndroid Build Coastguard Worker 
119*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_HALF_CEILING:
120*0e209d39SAndroid Build Coastguard Worker             switch (section) {
121*0e209d39SAndroid Build Coastguard Worker                 case SECTION_MIDPOINT:
122*0e209d39SAndroid Build Coastguard Worker                     return isNegative;
123*0e209d39SAndroid Build Coastguard Worker                 case SECTION_LOWER:
124*0e209d39SAndroid Build Coastguard Worker                     return true;
125*0e209d39SAndroid Build Coastguard Worker                 case SECTION_UPPER:
126*0e209d39SAndroid Build Coastguard Worker                     return false;
127*0e209d39SAndroid Build Coastguard Worker                 default:
128*0e209d39SAndroid Build Coastguard Worker                     break;
129*0e209d39SAndroid Build Coastguard Worker             }
130*0e209d39SAndroid Build Coastguard Worker             break;
131*0e209d39SAndroid Build Coastguard Worker 
132*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_HALF_FLOOR:
133*0e209d39SAndroid Build Coastguard Worker             switch (section) {
134*0e209d39SAndroid Build Coastguard Worker                 case SECTION_MIDPOINT:
135*0e209d39SAndroid Build Coastguard Worker                     return !isNegative;
136*0e209d39SAndroid Build Coastguard Worker                 case SECTION_LOWER:
137*0e209d39SAndroid Build Coastguard Worker                     return true;
138*0e209d39SAndroid Build Coastguard Worker                 case SECTION_UPPER:
139*0e209d39SAndroid Build Coastguard Worker                     return false;
140*0e209d39SAndroid Build Coastguard Worker                 default:
141*0e209d39SAndroid Build Coastguard Worker                     break;
142*0e209d39SAndroid Build Coastguard Worker             }
143*0e209d39SAndroid Build Coastguard Worker             break;
144*0e209d39SAndroid Build Coastguard Worker 
145*0e209d39SAndroid Build Coastguard Worker         default:
146*0e209d39SAndroid Build Coastguard Worker             break;
147*0e209d39SAndroid Build Coastguard Worker     }
148*0e209d39SAndroid Build Coastguard Worker 
149*0e209d39SAndroid Build Coastguard Worker     status = U_FORMAT_INEXACT_ERROR;
150*0e209d39SAndroid Build Coastguard Worker     return false;
151*0e209d39SAndroid Build Coastguard Worker }
152*0e209d39SAndroid Build Coastguard Worker 
153*0e209d39SAndroid Build Coastguard Worker /**
154*0e209d39SAndroid Build Coastguard Worker  * Gets whether the given rounding mode's rounding boundary is at the midpoint. The rounding
155*0e209d39SAndroid Build Coastguard Worker  * boundary is the point at which a number switches from being rounded down to being rounded up.
156*0e209d39SAndroid Build Coastguard Worker  * For example, with rounding mode HALF_EVEN, HALF_UP, or HALF_DOWN, the rounding boundary is at
157*0e209d39SAndroid Build Coastguard Worker  * the midpoint, and this function would return true. However, for UP, DOWN, CEILING, and FLOOR,
158*0e209d39SAndroid Build Coastguard Worker  * the rounding boundary is at the "edge", and this function would return false.
159*0e209d39SAndroid Build Coastguard Worker  *
160*0e209d39SAndroid Build Coastguard Worker  * @param roundingMode The integer version of the {@link RoundingMode}.
161*0e209d39SAndroid Build Coastguard Worker  * @return true if rounding mode is HALF_EVEN, HALF_UP, or HALF_DOWN; false otherwise.
162*0e209d39SAndroid Build Coastguard Worker  */
roundsAtMidpoint(int roundingMode)163*0e209d39SAndroid Build Coastguard Worker inline bool roundsAtMidpoint(int roundingMode) {
164*0e209d39SAndroid Build Coastguard Worker     switch (roundingMode) {
165*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_UP:
166*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_DOWN:
167*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_CEILING:
168*0e209d39SAndroid Build Coastguard Worker         case RoundingMode::UNUM_ROUND_FLOOR:
169*0e209d39SAndroid Build Coastguard Worker             return false;
170*0e209d39SAndroid Build Coastguard Worker 
171*0e209d39SAndroid Build Coastguard Worker         default:
172*0e209d39SAndroid Build Coastguard Worker             return true;
173*0e209d39SAndroid Build Coastguard Worker     }
174*0e209d39SAndroid Build Coastguard Worker }
175*0e209d39SAndroid Build Coastguard Worker 
176*0e209d39SAndroid Build Coastguard Worker } // namespace roundingutils
177*0e209d39SAndroid Build Coastguard Worker 
178*0e209d39SAndroid Build Coastguard Worker 
179*0e209d39SAndroid Build Coastguard Worker /**
180*0e209d39SAndroid Build Coastguard Worker  * Encapsulates a Precision and a RoundingMode and performs rounding on a DecimalQuantity.
181*0e209d39SAndroid Build Coastguard Worker  *
182*0e209d39SAndroid Build Coastguard Worker  * This class does not exist in Java: instead, the base Precision class is used.
183*0e209d39SAndroid Build Coastguard Worker  */
184*0e209d39SAndroid Build Coastguard Worker class RoundingImpl {
185*0e209d39SAndroid Build Coastguard Worker   public:
186*0e209d39SAndroid Build Coastguard Worker     RoundingImpl() = default;  // defaults to pass-through rounder
187*0e209d39SAndroid Build Coastguard Worker 
188*0e209d39SAndroid Build Coastguard Worker     RoundingImpl(const Precision& precision, UNumberFormatRoundingMode roundingMode,
189*0e209d39SAndroid Build Coastguard Worker                  const CurrencyUnit& currency, UErrorCode& status);
190*0e209d39SAndroid Build Coastguard Worker 
191*0e209d39SAndroid Build Coastguard Worker     static RoundingImpl passThrough();
192*0e209d39SAndroid Build Coastguard Worker 
193*0e209d39SAndroid Build Coastguard Worker     /** Required for ScientificFormatter */
194*0e209d39SAndroid Build Coastguard Worker     bool isSignificantDigits() const;
195*0e209d39SAndroid Build Coastguard Worker 
196*0e209d39SAndroid Build Coastguard Worker     /**
197*0e209d39SAndroid Build Coastguard Worker      * Rounding endpoint used by Engineering and Compact notation. Chooses the most appropriate multiplier (magnitude
198*0e209d39SAndroid Build Coastguard Worker      * adjustment), applies the adjustment, rounds, and returns the chosen multiplier.
199*0e209d39SAndroid Build Coastguard Worker      *
200*0e209d39SAndroid Build Coastguard Worker      * <p>
201*0e209d39SAndroid Build Coastguard Worker      * In most cases, this is simple. However, when rounding the number causes it to cross a multiplier boundary, we
202*0e209d39SAndroid Build Coastguard Worker      * need to re-do the rounding. For example, to display 999,999 in Engineering notation with 2 sigfigs, first you
203*0e209d39SAndroid Build Coastguard Worker      * guess the multiplier to be -3. However, then you end up getting 1000E3, which is not the correct output. You then
204*0e209d39SAndroid Build Coastguard Worker      * change your multiplier to be -6, and you get 1.0E6, which is correct.
205*0e209d39SAndroid Build Coastguard Worker      *
206*0e209d39SAndroid Build Coastguard Worker      * @param input The quantity to process.
207*0e209d39SAndroid Build Coastguard Worker      * @param producer Function to call to return a multiplier based on a magnitude.
208*0e209d39SAndroid Build Coastguard Worker      * @return The number of orders of magnitude the input was adjusted by this method.
209*0e209d39SAndroid Build Coastguard Worker      */
210*0e209d39SAndroid Build Coastguard Worker     int32_t
211*0e209d39SAndroid Build Coastguard Worker     chooseMultiplierAndApply(impl::DecimalQuantity &input, const impl::MultiplierProducer &producer,
212*0e209d39SAndroid Build Coastguard Worker                              UErrorCode &status);
213*0e209d39SAndroid Build Coastguard Worker 
214*0e209d39SAndroid Build Coastguard Worker     void apply(impl::DecimalQuantity &value, UErrorCode &status) const;
215*0e209d39SAndroid Build Coastguard Worker 
216*0e209d39SAndroid Build Coastguard Worker     /** Version of {@link #apply} that obeys minInt constraints. Used for scientific notation compatibility mode. */
217*0e209d39SAndroid Build Coastguard Worker     void apply(impl::DecimalQuantity &value, int32_t minInt, UErrorCode status);
218*0e209d39SAndroid Build Coastguard Worker 
219*0e209d39SAndroid Build Coastguard Worker   private:
220*0e209d39SAndroid Build Coastguard Worker     Precision fPrecision;
221*0e209d39SAndroid Build Coastguard Worker     UNumberFormatRoundingMode fRoundingMode;
222*0e209d39SAndroid Build Coastguard Worker     bool fPassThrough = true;  // default value
223*0e209d39SAndroid Build Coastguard Worker 
224*0e209d39SAndroid Build Coastguard Worker     // Permits access to fPrecision.
225*0e209d39SAndroid Build Coastguard Worker     friend class units::UnitsRouter;
226*0e209d39SAndroid Build Coastguard Worker 
227*0e209d39SAndroid Build Coastguard Worker     // Permits access to fPrecision.
228*0e209d39SAndroid Build Coastguard Worker     friend class UnitConversionHandler;
229*0e209d39SAndroid Build Coastguard Worker };
230*0e209d39SAndroid Build Coastguard Worker 
231*0e209d39SAndroid Build Coastguard Worker /**
232*0e209d39SAndroid Build Coastguard Worker  * Parses Precision-related skeleton strings without knowledge of MacroProps
233*0e209d39SAndroid Build Coastguard Worker  * - see blueprint_helpers::parseIncrementOption().
234*0e209d39SAndroid Build Coastguard Worker  *
235*0e209d39SAndroid Build Coastguard Worker  * Referencing MacroProps means needing to pull in the .o files that have the
236*0e209d39SAndroid Build Coastguard Worker  * destructors for the SymbolsWrapper, StringProp, and Scale classes.
237*0e209d39SAndroid Build Coastguard Worker  */
238*0e209d39SAndroid Build Coastguard Worker void parseIncrementOption(const StringSegment &segment, Precision &outPrecision, UErrorCode &status);
239*0e209d39SAndroid Build Coastguard Worker 
240*0e209d39SAndroid Build Coastguard Worker } // namespace number::impl
241*0e209d39SAndroid Build Coastguard Worker U_NAMESPACE_END
242*0e209d39SAndroid Build Coastguard Worker 
243*0e209d39SAndroid Build Coastguard Worker #endif //__NUMBER_ROUNDINGUTILS_H__
244*0e209d39SAndroid Build Coastguard Worker 
245*0e209d39SAndroid Build Coastguard Worker #endif /* #if !UCONFIG_NO_FORMATTING */
246