]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/nfsubs.cpp
ICU-59117.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / nfsubs.cpp
index b88e6806c199592dc64e459fbcc4df6f94a76341..688d109016d391c110990b1f153a67d0fc2e1f01 100644 (file)
@@ -1,10 +1,12 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 ******************************************************************************
 *   Copyright (C) 1997-2015, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 ******************************************************************************
 *   file name:  nfsubs.cpp
-*   encoding:   US-ASCII
+*   encoding:   UTF-8
 *   tab size:   8 (not used)
 *   indentation:4
 *
@@ -18,6 +20,7 @@
 
 #include "nfsubs.h"
 #include "digitlst.h"
+#include "fmtableimp.h"
 
 #if U_HAVE_RBNF
 
@@ -66,27 +69,24 @@ public:
 SameValueSubstitution::~SameValueSubstitution() {}
 
 class MultiplierSubstitution : public NFSubstitution {
-    double divisor;
-    int64_t ldivisor;
+    int64_t divisor;
 
 public:
     MultiplierSubstitution(int32_t _pos,
-        double _divisor,
+        const NFRule *rule,
         const NFRuleSet* _ruleSet,
         const UnicodeString& description,
         UErrorCode& status)
-        : NFSubstitution(_pos, _ruleSet, description, status), divisor(_divisor)
+        : NFSubstitution(_pos, _ruleSet, description, status), divisor(rule->getDivisor())
     {
-        ldivisor = util64_fromDouble(divisor);
         if (divisor == 0) {
             status = U_PARSE_ERROR;
         }
     }
     virtual ~MultiplierSubstitution();
 
-    virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
-        divisor = uprv_pow(radix, exponent);
-        ldivisor = util64_fromDouble(divisor);
+    virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status) { 
+        divisor = util64_pow(radix, exponent);
 
         if(divisor == 0) {
             status = U_PARSE_ERROR;
@@ -96,14 +96,14 @@ public:
     virtual UBool operator==(const NFSubstitution& rhs) const;
 
     virtual int64_t transformNumber(int64_t number) const {
-        return number / ldivisor;
+        return number / divisor;
     }
 
     virtual double transformNumber(double number) const {
         if (getRuleSet()) {
             return uprv_floor(number / divisor);
         } else {
-            return number/divisor;
+            return number / divisor;
         }
     }
 
@@ -123,21 +123,19 @@ public:
 MultiplierSubstitution::~MultiplierSubstitution() {}
 
 class ModulusSubstitution : public NFSubstitution {
-    double divisor;
-    int64_t  ldivisor;
+    int64_t  divisor;
     const NFRule* ruleToUse;
 public:
     ModulusSubstitution(int32_t pos,
-        double _divisor,
+        const NFRule* rule,
         const NFRule* rulePredecessor,
         const NFRuleSet* ruleSet,
         const UnicodeString& description,
         UErrorCode& status);
     virtual ~ModulusSubstitution();
 
-    virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
-        divisor = uprv_pow(radix, exponent);
-        ldivisor = util64_fromDouble(divisor);
+    virtual void setDivisor(int32_t radix, int16_t exponent, UErrorCode& status) { 
+        divisor = util64_pow(radix, exponent);
 
         if (divisor == 0) {
             status = U_PARSE_ERROR;
@@ -149,7 +147,7 @@ public:
     virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
     virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos, int32_t recursionCount, UErrorCode& status) const;
 
-    virtual int64_t transformNumber(int64_t number) const { return number % ldivisor; }
+    virtual int64_t transformNumber(int64_t number) const { return number % divisor; }
     virtual double transformNumber(double number) const { return uprv_fmod(number, divisor); }
 
     virtual UBool doParse(const UnicodeString& text, 
@@ -351,7 +349,7 @@ NFSubstitution::makeSubstitution(int32_t pos,
 
         // otherwise, return a MultiplierSubstitution
         else {
-            return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
+            return new MultiplierSubstitution(pos, rule, ruleSet,
                 description, status);
         }
 
@@ -381,7 +379,7 @@ NFSubstitution::makeSubstitution(int32_t pos,
 
         // otherwise, return a ModulusSubstitution
         else {
-            return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
+            return new ModulusSubstitution(pos, rule, predecessor,
                 ruleSet, description, status);
         }
 
@@ -489,7 +487,7 @@ NFSubstitution::~NFSubstitution()
  * @param exponent The exponent of the divisor
  */
 void
-NFSubstitution::setDivisor(int32_t /*radix*/, int32_t /*exponent*/, UErrorCode& /*status*/) {
+NFSubstitution::setDivisor(int32_t /*radix*/, int16_t /*exponent*/, UErrorCode& /*status*/) {
   // a no-op for all substitutions except multiplier and modulus substitutions
 }
 
@@ -570,23 +568,38 @@ void
 NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos, int32_t recursionCount, UErrorCode& status) const
 {
     if (ruleSet != NULL) {
-        // perform a transformation on the number that is dependent
+        // Perform a transformation on the number that is dependent
         // on the type of substitution this is, then just call its
         // rule set's format() method to format the result
         ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos, recursionCount, status);
     } else if (numberFormat != NULL) {
-        // or perform the transformation on the number (preserving
-        // the result's fractional part if the formatter it set
-        // to show it), then use that formatter's format() method
-        // to format the result
-        double numberToFormat = transformNumber((double)number);
-        if (numberFormat->getMaximumFractionDigits() == 0) {
-            numberToFormat = uprv_floor(numberToFormat);
-        }
+        if (number <= MAX_INT64_IN_DOUBLE) {
+            // or perform the transformation on the number (preserving
+            // the result's fractional part if the formatter it set
+            // to show it), then use that formatter's format() method
+            // to format the result
+            double numberToFormat = transformNumber((double)number);
+            if (numberFormat->getMaximumFractionDigits() == 0) {
+                numberToFormat = uprv_floor(numberToFormat);
+            }
 
-        UnicodeString temp;
-        numberFormat->format(numberToFormat, temp, status);
-        toInsertInto.insert(_pos + this->pos, temp);
+            UnicodeString temp;
+            numberFormat->format(numberToFormat, temp, status);
+            toInsertInto.insert(_pos + this->pos, temp);
+        } 
+        else { 
+            // We have gone beyond double precision. Something has to give. 
+            // We're favoring accuracy of the large number over potential rules 
+            // that round like a CompactDecimalFormat, which is not a common use case. 
+            // 
+            // Perform a transformation on the number that is dependent 
+            // on the type of substitution this is, then just call its 
+            // rule set's format() method to format the result 
+            int64_t numberToFormat = transformNumber(number); 
+            UnicodeString temp;
+            numberFormat->format(numberToFormat, temp, status);
+            toInsertInto.insert(_pos + this->pos, temp);
+        } 
     }
 }
 
@@ -825,22 +838,20 @@ UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const
  * regular rule.
  */
 ModulusSubstitution::ModulusSubstitution(int32_t _pos,
-                                         double _divisor,
+                                         const NFRule* rule,
                                          const NFRule* predecessor,
                                          const NFRuleSet* _ruleSet,
                                          const UnicodeString& description,
                                          UErrorCode& status)
  : NFSubstitution(_pos, _ruleSet, description, status)
- , divisor(_divisor)
+ , divisor(rule->getDivisor())
  , ruleToUse(NULL)
 {
-  ldivisor = util64_fromDouble(_divisor);
-
   // the owning rule's divisor controls the behavior of this
   // substitution: rather than keeping a backpointer to the rule,
   // we keep a copy of the divisor
 
-  if (ldivisor == 0) {
+  if (divisor == 0) {
       status = U_PARSE_ERROR;
   }