Home | History | Annotate | Download | only in i18n
      1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 2015, International Business Machines
      6 * Corporation and others.  All Rights Reserved.
      7 *******************************************************************************
      8 * precision.h
      9 *
     10 * created on: 2015jan06
     11 * created by: Travis Keep
     12 */
     13 
     14 #ifndef __PRECISION_H__
     15 #define __PRECISION_H__
     16 
     17 #include "unicode/uobject.h"
     18 
     19 #if !UCONFIG_NO_FORMATTING
     20 #include "unicode/utypes.h"
     21 
     22 #include "digitinterval.h"
     23 #include "digitlst.h"
     24 #include "significantdigitinterval.h"
     25 
     26 U_NAMESPACE_BEGIN
     27 
     28 class VisibleDigits;
     29 class VisibleDigitsWithExponent;
     30 
     31 
     32 /**
     33  * A precision manager for values to be formatted as fixed point.
     34  * Handles rounding of number to prepare it for formatting.
     35  */
     36 class U_I18N_API FixedPrecision : public UMemory {
     37 public:
     38 
     39     /**
     40      * The smallest format interval allowed. Default is 1 integer digit and no
     41      * fraction digits.
     42      */
     43     DigitInterval fMin;
     44 
     45     /**
     46      * The largest format interval allowed. Must contain fMin.
     47      *  Default is all digits.
     48      */
     49     DigitInterval fMax;
     50 
     51     /**
     52      * Min and max significant digits allowed. The default is no constraints.
     53      */
     54     SignificantDigitInterval fSignificant;
     55 
     56     /**
     57      * The rounding increment or zero if there is no rounding increment.
     58      * Default is zero.
     59      */
     60     DigitList fRoundingIncrement;
     61 
     62     /**
     63      * If set, causes round() to set status to U_FORMAT_INEXACT_ERROR if
     64      * any rounding is done. Default is FALSE.
     65      */
     66     UBool fExactOnly;
     67 
     68     /**
     69      * If set, causes round() to set status to U_ILLEGAL_ARGUMENT_ERROR if
     70      * rounded number has more than maximum integer digits. Default is FALSE.
     71      */
     72     UBool fFailIfOverMax;
     73 
     74     /**
     75      * Controls the rounding mode that initVisibleDigits uses.
     76      * Default is DecimalFormat::kRoundHalfEven
     77      */
     78     DecimalFormat::ERoundingMode fRoundingMode;
     79 
     80     FixedPrecision();
     81 
     82     /**
     83      * Returns TRUE if this object equals rhs.
     84      */
     85     UBool equals(const FixedPrecision &rhs) const {
     86         return (fMin.equals(rhs.fMin) &&
     87                 fMax.equals(rhs.fMax) &&
     88                 fSignificant.equals(rhs.fSignificant) &&
     89                 (fRoundingIncrement == rhs.fRoundingIncrement) &&
     90                 fExactOnly == rhs.fExactOnly &&
     91                 fFailIfOverMax == rhs.fFailIfOverMax &&
     92                 fRoundingMode == rhs.fRoundingMode);
     93     }
     94 
     95     /**
     96      * Rounds value in place to prepare it for formatting.
     97      * @param value The value to be rounded. It is rounded in place.
     98      * @param exponent Always pass 0 for fixed decimal formatting. scientific
     99      *  precision passes the exponent value.  Essentially, it divides value by
    100      *  10^exponent, rounds and then multiplies by 10^exponent.
    101      * @param status error returned here.
    102      * @return reference to value.
    103      */
    104     DigitList &round(DigitList &value, int32_t exponent, UErrorCode &status) const;
    105 
    106     /**
    107      * Returns the interval to use to format the rounded value.
    108      * @param roundedValue the already rounded value to format.
    109      * @param interval modified in place to be the interval to use to format
    110      *   the rounded value.
    111      * @return a reference to interval.
    112      */
    113     DigitInterval &getInterval(
    114             const DigitList &roundedValue, DigitInterval &interval) const;
    115 
    116     /**
    117      * Returns TRUE if this instance allows for fast formatting of integers.
    118      */
    119     UBool isFastFormattable() const;
    120 
    121     /**
    122      * Initializes a VisibleDigits.
    123      * @param value value for VisibleDigits
    124      *    Caller must not assume that the value of this parameter will remain
    125      *    unchanged.
    126      * @param digits This is the value that is initialized.
    127      * @param status any error returned here.
    128      * @return digits
    129      */
    130     VisibleDigits &initVisibleDigits(
    131             DigitList &value,
    132             VisibleDigits &digits,
    133             UErrorCode &status) const;
    134 
    135     /**
    136      * Initializes a VisibleDigits.
    137      * @param value value for VisibleDigits
    138      * @param digits This is the value that is initialized.
    139      * @param status any error returned here.
    140      * @return digits
    141      */
    142     VisibleDigits &initVisibleDigits(
    143             double value,
    144             VisibleDigits &digits,
    145             UErrorCode &status) const;
    146 
    147     /**
    148      * Initializes a VisibleDigits.
    149      * @param value value for VisibleDigits
    150      * @param digits This is the value that is initialized.
    151      * @param status any error returned here.
    152      * @return digits
    153      */
    154     VisibleDigits &initVisibleDigits(
    155             int64_t value,
    156             VisibleDigits &digits,
    157             UErrorCode &status) const;
    158 
    159     /**
    160      * Initializes a VisibleDigitsWithExponent.
    161      * @param value value for VisibleDigits
    162      *    Caller must not assume that the value of this parameter will remain
    163      *    unchanged.
    164      * @param digits This is the value that is initialized.
    165      * @param status any error returned here.
    166      * @return digits
    167      */
    168     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
    169             DigitList &value,
    170             VisibleDigitsWithExponent &digits,
    171             UErrorCode &status) const;
    172 
    173     /**
    174      * Initializes a VisibleDigitsWithExponent.
    175      * @param value value for VisibleDigits
    176      * @param digits This is the value that is initialized.
    177      * @param status any error returned here.
    178      * @return digits
    179      */
    180     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
    181             double value,
    182             VisibleDigitsWithExponent &digits,
    183             UErrorCode &status) const;
    184 
    185     /**
    186      * Initializes a VisibleDigitsWithExponent.
    187      * @param value value for VisibleDigits
    188      * @param digits This is the value that is initialized.
    189      * @param status any error returned here.
    190      * @return digits
    191      */
    192     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
    193             int64_t value,
    194             VisibleDigitsWithExponent &digits,
    195             UErrorCode &status) const;
    196 
    197 private:
    198     /**
    199      * Attempts to initialize 'digits' using simple mod 10 arithmetic.
    200      * Returns FALSE if this is not possible such as when rounding
    201      * would change the value. Otherwise returns TRUE.
    202      *
    203      * If the method returns FALSE, caller should create a DigitList
    204      * and use it to initialize 'digits'. If this method returns TRUE,
    205      * caller should accept the value stored in 'digits'. If this
    206      * method returns TRUE along with a non zero error, caller must accept
    207      * the error and not try again with a DigitList.
    208      *
    209      * Before calling this method, caller must verify that this object
    210      * has no rounding increment set.
    211      *
    212      * The value that 'digits' is initialized to is mantissa * 10^exponent.
    213      * For example mantissa = 54700 and exponent = -3 means 54.7. The
    214      * properties of this object (such as min and max fraction digits),
    215      * not the number of trailing zeros in the mantissa, determine whether or
    216      * not the result contains any trailing 0's after the decimal point.
    217      *
    218      * @param mantissa the digits. May be positive or negative. May contain
    219      *  trailing zeros.
    220      * @param exponent must always be zero or negative. An exponent > 0
    221      *  yields undefined results!
    222      * @param digits result stored here.
    223      * @param status any error returned here.
    224      */
    225     UBool
    226     initVisibleDigits(
    227             int64_t mantissa,
    228             int32_t exponent,
    229             VisibleDigits &digits,
    230             UErrorCode &status) const;
    231     UBool isRoundingRequired(
    232             int32_t upperExponent, int32_t lowerExponent) const;
    233     DigitInterval &getIntervalForZero(DigitInterval &interval) const;
    234     DigitInterval &getInterval(
    235             int32_t upperExponent, DigitInterval &interval) const;
    236     static UBool handleNonNumeric(DigitList &value, VisibleDigits &digits);
    237 
    238     friend class ScientificPrecision;
    239 };
    240 
    241 /**
    242  * A precision manager for values to be expressed as scientific notation.
    243  */
    244 class U_I18N_API ScientificPrecision : public UMemory {
    245 public:
    246     FixedPrecision fMantissa;
    247     int32_t fMinExponentDigits;
    248 
    249     ScientificPrecision();
    250 
    251     /**
    252      * rounds value in place to prepare it for formatting.
    253      * @param value The value to be rounded. It is rounded in place.
    254      * @param status error returned here.
    255      * @return reference to value.
    256      */
    257     DigitList &round(DigitList &value, UErrorCode &status) const;
    258 
    259     /**
    260      * Converts value to a mantissa and exponent.
    261      *
    262      * @param value modified in place to be the mantissa. Depending on
    263      *   the precision settings, the resulting mantissa may not fall
    264      *   between 1.0 and 10.0.
    265      * @return the exponent of value.
    266      */
    267     int32_t toScientific(DigitList &value) const;
    268 
    269     /**
    270      * Returns TRUE if this object equals rhs.
    271      */
    272     UBool equals(const ScientificPrecision &rhs) const {
    273         return fMantissa.equals(rhs.fMantissa) && fMinExponentDigits == rhs.fMinExponentDigits;
    274     }
    275 
    276     /**
    277      * Initializes a VisibleDigitsWithExponent.
    278      * @param value the value
    279      *    Caller must not assume that the value of this parameter will remain
    280      *    unchanged.
    281      * @param digits This is the value that is initialized.
    282      * @param status any error returned here.
    283      * @return digits
    284      */
    285     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
    286             DigitList &value,
    287             VisibleDigitsWithExponent &digits,
    288             UErrorCode &status) const;
    289 
    290     /**
    291      * Initializes a VisibleDigitsWithExponent.
    292      * @param value the value
    293      * @param digits This is the value that is initialized.
    294      * @param status any error returned here.
    295      * @return digits
    296      */
    297     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
    298             double value,
    299             VisibleDigitsWithExponent &digits,
    300             UErrorCode &status) const;
    301 
    302     /**
    303      * Initializes a VisibleDigitsWithExponent.
    304      * @param value the value
    305      * @param digits This is the value that is initialized.
    306      * @param status any error returned here.
    307      * @return digits
    308      */
    309     VisibleDigitsWithExponent &initVisibleDigitsWithExponent(
    310             int64_t value,
    311             VisibleDigitsWithExponent &digits,
    312             UErrorCode &status) const;
    313 
    314 private:
    315     int32_t getMultiplier() const;
    316 
    317 };
    318 
    319 
    320 
    321 U_NAMESPACE_END
    322 #endif // #if !UCONFIG_NO_FORMATTING
    323 #endif  // __PRECISION_H__
    324