1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
7 #ifndef __NUMBER_ROUNDINGUTILS_H__
8 #define __NUMBER_ROUNDINGUTILS_H__
10 #include "number_types.h"
15 namespace roundingutils
{
18 SECTION_LOWER_EDGE
= -1,
19 SECTION_UPPER_EDGE
= -2,
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.
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.
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
45 getRoundingDirection(bool isEven
, bool isNegative
, Section section
, RoundingMode roundingMode
,
47 switch (roundingMode
) {
48 case RoundingMode::UNUM_ROUND_UP
:
49 // round away from zero
52 case RoundingMode::UNUM_ROUND_DOWN
:
56 case RoundingMode::UNUM_ROUND_CEILING
:
57 // round toward positive infinity
60 case RoundingMode::UNUM_ROUND_FLOOR
:
61 // round toward negative infinity
64 case RoundingMode::UNUM_ROUND_HALFUP
:
66 case SECTION_MIDPOINT
:
77 case RoundingMode::UNUM_ROUND_HALFDOWN
:
79 case SECTION_MIDPOINT
:
90 case RoundingMode::UNUM_ROUND_HALFEVEN
:
92 case SECTION_MIDPOINT
:
107 status
= U_FORMAT_INEXACT_ERROR
;
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.
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.
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
:
135 * Computes the number of fraction digits in a double. Used for computing maxFrac for an increment.
136 * Calls into the DoubleToStringConverter library to do so.
138 * @param singleDigit An output parameter; set to a number if that is the
139 * only digit in the double, or -1 if there is more than one digit.
141 digits_t
doubleFractionLength(double input
, int8_t* singleDigit
);
143 } // namespace roundingutils
147 * Encapsulates a Precision and a RoundingMode and performs rounding on a DecimalQuantity.
149 * This class does not exist in Java: instead, the base Precision class is used.
153 RoundingImpl() = default; // default constructor: leaves object in undefined state
155 RoundingImpl(const Precision
& precision
, UNumberFormatRoundingMode roundingMode
,
156 const CurrencyUnit
& currency
, UErrorCode
& status
);
158 static RoundingImpl
passThrough();
160 /** Required for ScientificFormatter */
161 bool isSignificantDigits() const;
164 * Rounding endpoint used by Engineering and Compact notation. Chooses the most appropriate multiplier (magnitude
165 * adjustment), applies the adjustment, rounds, and returns the chosen multiplier.
168 * In most cases, this is simple. However, when rounding the number causes it to cross a multiplier boundary, we
169 * need to re-do the rounding. For example, to display 999,999 in Engineering notation with 2 sigfigs, first you
170 * guess the multiplier to be -3. However, then you end up getting 1000E3, which is not the correct output. You then
171 * change your multiplier to be -6, and you get 1.0E6, which is correct.
173 * @param input The quantity to process.
174 * @param producer Function to call to return a multiplier based on a magnitude.
175 * @return The number of orders of magnitude the input was adjusted by this method.
178 chooseMultiplierAndApply(impl::DecimalQuantity
&input
, const impl::MultiplierProducer
&producer
,
181 void apply(impl::DecimalQuantity
&value
, UErrorCode
&status
) const;
183 /** Version of {@link #apply} that obeys minInt constraints. Used for scientific notation compatibility mode. */
184 void apply(impl::DecimalQuantity
&value
, int32_t minInt
, UErrorCode status
);
187 Precision fPrecision
;
188 UNumberFormatRoundingMode fRoundingMode
;
194 } // namespace number
197 #endif //__NUMBER_ROUNDINGUTILS_H__
199 #endif /* #if !UCONFIG_NO_FORMATTING */