+// © 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
*
#include "nfsubs.h"
#include "digitlst.h"
+#include "fmtableimp.h"
#if U_HAVE_RBNF
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;
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;
}
}
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;
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,
// otherwise, return a MultiplierSubstitution
else {
- return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
+ return new MultiplierSubstitution(pos, rule, ruleSet,
description, status);
}
// otherwise, return a ModulusSubstitution
else {
- return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
+ return new ModulusSubstitution(pos, rule, predecessor,
ruleSet, description, status);
}
* @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
}
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);
+ }
}
}
* 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;
}