]> granicus.if.org Git - icu/commitdiff
ICU-13634 Changing DecimalQuantity#toNumberString() to be DecimalQuantity#toScientifi...
authorShane Carr <shane@unicode.org>
Wed, 11 Apr 2018 05:52:58 +0000 (05:52 +0000)
committerShane Carr <shane@unicode.org>
Wed, 11 Apr 2018 05:52:58 +0000 (05:52 +0000)
X-SVN-Rev: 41215

18 files changed:
icu4c/source/i18n/currunit.cpp
icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/fmtable.cpp
icu4c/source/i18n/number_decimalquantity.cpp
icu4c/source/i18n/number_decimalquantity.h
icu4c/source/i18n/number_formatimpl.cpp
icu4c/source/i18n/number_mapper.cpp
icu4c/source/i18n/number_stringbuilder.cpp
icu4c/source/i18n/number_types.h
icu4c/source/i18n/number_utils.cpp
icu4c/source/test/intltest/numbertest_decimalquantity.cpp
icu4c/source/test/intltest/numfmtst.cpp
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_AbstractBCD.java
icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalQuantity_DualStorageBCD.java
icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java
icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/number/DecimalQuantityTest.java

index 1750b94fab411b790227b0d0a1ec7d45839f645e..003ce612109e78990e5a70c5fa7a8392149b21d7 100644 (file)
 #include "unicode/ustring.h"
 #include "cstring.h"
 
+static constexpr char16_t kDefaultCurrency[] = u"XXX";
+
 U_NAMESPACE_BEGIN
 
 CurrencyUnit::CurrencyUnit(ConstChar16Ptr _isoCode, UErrorCode& ec) {
-    *isoCode = 0;
-    if (U_SUCCESS(ec)) {
-        if (_isoCode != nullptr && u_strlen(_isoCode)==3) {
-            u_strcpy(isoCode, _isoCode);
-            char simpleIsoCode[4];
-            u_UCharsToChars(isoCode, simpleIsoCode, 4);
-            initCurrency(simpleIsoCode);
-        } else {
-            ec = U_ILLEGAL_ARGUMENT_ERROR;
-        }
+    // The constructor always leaves the CurrencyUnit in a valid state (with a 3-character currency code).
+    if (U_FAILURE(ec) || _isoCode == nullptr) {
+        u_strcpy(isoCode, kDefaultCurrency);
+    } else if (u_strlen(_isoCode) != 3) {
+        u_strcpy(isoCode, kDefaultCurrency);
+        ec = U_ILLEGAL_ARGUMENT_ERROR;
+    } else {
+        u_strcpy(isoCode, _isoCode);
     }
+    char simpleIsoCode[4];
+    u_UCharsToChars(isoCode, simpleIsoCode, 4);
+    initCurrency(simpleIsoCode);
 }
 
 CurrencyUnit::CurrencyUnit(const CurrencyUnit& other) : MeasureUnit(other) {
@@ -52,7 +55,7 @@ CurrencyUnit::CurrencyUnit(const MeasureUnit& other, UErrorCode& ec) : MeasureUn
 }
 
 CurrencyUnit::CurrencyUnit() : MeasureUnit() {
-    u_strcpy(isoCode, u"XXX");
+    u_strcpy(isoCode, kDefaultCurrency);
     char simpleIsoCode[4];
     u_UCharsToChars(isoCode, simpleIsoCode, 4);
     initCurrency(simpleIsoCode);
index bf975a31d99aded5a488994a51ab2016679f96fc..c88857c271954ccdf6b6c6df84d2cf5bfac27b27 100644 (file)
@@ -402,7 +402,9 @@ UnicodeString&
 DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter,
                       UErrorCode& status) const {
     FormattedNumber output = fFormatter->formatDouble(number, status);
-    output.populateFieldPositionIterator(*posIter, status);
+    if (posIter != nullptr) {
+        output.populateFieldPositionIterator(*posIter, status);
+    }
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -445,7 +447,9 @@ UnicodeString&
 DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter,
                       UErrorCode& status) const {
     FormattedNumber output = fFormatter->formatInt(number, status);
-    output.populateFieldPositionIterator(*posIter, status);
+    if (posIter != nullptr) {
+        output.populateFieldPositionIterator(*posIter, status);
+    }
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -456,7 +460,9 @@ DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPosition
                       UErrorCode& status) const {
     ErrorCode localStatus;
     FormattedNumber output = fFormatter->formatDecimal(number, localStatus);
-    output.populateFieldPositionIterator(*posIter, status);
+    if (posIter != nullptr) {
+        output.populateFieldPositionIterator(*posIter, status);
+    }
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -465,7 +471,9 @@ DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPosition
 UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo,
                                      FieldPositionIterator* posIter, UErrorCode& status) const {
     FormattedNumber output = fFormatter->formatDecimalQuantity(number, status);
-    output.populateFieldPositionIterator(*posIter, status);
+    if (posIter != nullptr) {
+        output.populateFieldPositionIterator(*posIter, status);
+    }
     auto appendable = UnicodeStringAppendable(appendTo);
     output.appendTo(appendable);
     return appendTo;
@@ -916,6 +924,7 @@ void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {
 }
 
 void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {
+    NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility
     fProperties->currency = CurrencyUnit(theCurrency, ec);
     // TODO: Set values in fSymbols, too?
     refreshFormatterNoError();
@@ -923,6 +932,7 @@ void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {
 
 void DecimalFormat::setCurrency(const char16_t* theCurrency) {
     ErrorCode localStatus;
+    NumberFormat::setCurrency(theCurrency, localStatus); // to set field for compatibility
     setCurrency(theCurrency, localStatus);
 }
 
@@ -998,6 +1008,7 @@ void DecimalFormat::refreshFormatter(UErrorCode& status) {
                     *fProperties, *fSymbols, true, status), status);
 
     // In order for the getters to work, we need to populate some fields in NumberFormat.
+    NumberFormat::setCurrency(fExportedProperties->currency.get(status).getISOCurrency(), status);
     NumberFormat::setMaximumIntegerDigits(fExportedProperties->maximumIntegerDigits);
     NumberFormat::setMinimumIntegerDigits(fExportedProperties->minimumIntegerDigits);
     NumberFormat::setMaximumFractionDigits(fExportedProperties->maximumFractionDigits);
index 68e06767a1c07bcf94ba63e314d3add461e849d9..ecee7388dabea4c6a6c46d67dc6003cf5ed44d3c 100644 (file)
@@ -745,8 +745,14 @@ CharString *Formattable::internalGetCharString(UErrorCode &status) {
         status = U_MEMORY_ALLOCATION_ERROR;
         return NULL;
       }
-      UnicodeString result = fDecimalQuantity->toNumberString();
-      fDecimalStr->appendInvariantChars(result, status);
+      // Older ICUs called uprv_decNumberToString here, which is not exactly the same as
+      // DecimalQuantity::toScientificString(). The biggest difference is that uprv_decNumberToString does
+      // not print scientific notation for magnitudes greater than -5 and smaller than some amount (+5?).
+      if (std::abs(fDecimalQuantity->getMagnitude()) < 5) {
+        fDecimalStr->appendInvariantChars(fDecimalQuantity->toPlainString(), status);
+      } else {
+        fDecimalStr->appendInvariantChars(fDecimalQuantity->toScientificString(), status);
+      }
     }
     return fDecimalStr;
 }
index 9c16fe4c3e7803afac75ef571bb6533ed956d5e2..baae9b76321e378b8930ea3b32db4aaf5744631f 100644 (file)
@@ -553,13 +553,12 @@ double DecimalQuantity::toDouble() const {
 
     // We are processing well-formed input, so we don't need any special options to StringToDoubleConverter.
     StringToDoubleConverter converter(0, 0, 0, "", "");
-    UnicodeString numberString = toNumberString();
+    UnicodeString numberString = this->toScientificString();
     int32_t count;
-    double result = converter.StringToDouble(reinterpret_cast<const uint16_t*>(numberString.getBuffer()), numberString.length(), &count);
-    if (isNegative()) {
-        result = -result;
-    }
-    return result;
+    return converter.StringToDouble(
+            reinterpret_cast<const uint16_t*>(numberString.getBuffer()),
+            numberString.length(),
+            &count);
 }
 
 double DecimalQuantity::toDoubleFromOriginal() const {
@@ -775,7 +774,7 @@ UnicodeString DecimalQuantity::toPlainString() const {
     if (isNegative()) {
         sb.append(u'-');
     }
-    if (precision == 0) {
+    if (precision == 0 || getMagnitude() < 0) {
         sb.append(u'0');
     }
     for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
@@ -785,6 +784,43 @@ UnicodeString DecimalQuantity::toPlainString() const {
     return sb;
 }
 
+UnicodeString DecimalQuantity::toScientificString() const {
+    U_ASSERT(!isApproximate);
+    UnicodeString result;
+    if (isNegative()) {
+        result.append(u'-');
+    }
+    if (precision == 0) {
+        result.append(u"0E+0", -1);
+        return result;
+    }
+    result.append(u'0' + getDigitPos(precision - 1));
+    if (precision > 1) {
+        result.append(u'.');
+        for (int32_t i = 1; i < precision; i++) {
+            result.append(u'0' + getDigitPos(precision - i - 1));
+        }
+    }
+    result.append(u'E');
+    int32_t _scale = scale + precision - 1;
+    if (_scale < 0) {
+        _scale *= -1;
+        result.append(u'-');
+    } else {
+        result.append(u'+');
+    }
+    if (_scale == 0) {
+        result.append(u'0');
+    }
+    int32_t insertIndex = result.length();
+    while (_scale > 0) {
+        std::div_t res = std::div(_scale, 10);
+        result.insert(insertIndex, u'0' + res.rem);
+        _scale = res.quot;
+    }
+    return result;
+}
+
 ////////////////////////////////////////////////////
 /// End of DecimalQuantity_AbstractBCD.java      ///
 /// Start of DecimalQuantity_DualStorageBCD.java ///
@@ -1128,31 +1164,4 @@ UnicodeString DecimalQuantity::toString() const {
     return UnicodeString(buffer8, -1, US_INV);
 }
 
-UnicodeString DecimalQuantity::toNumberString() const {
-    U_ASSERT(!isApproximate);
-    UnicodeString result;
-    if (precision == 0) {
-        result.append(u'0');
-    }
-    for (int32_t i = 0; i < precision; i++) {
-        result.append(u'0' + getDigitPos(precision - i - 1));
-    }
-    result.append(u'E');
-    int32_t _scale = scale;
-    if (_scale < 0) {
-        _scale *= -1;
-        result.append(u'-');
-    }
-    if (_scale == 0) {
-        result.append(u'0');
-    }
-    int32_t insertIndex = result.length();
-    while (_scale > 0) {
-        std::div_t res = std::div(_scale, 10);
-        result.insert(insertIndex, u'0' + res.rem);
-        _scale = res.quot;
-    }
-    return result;
-}
-
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 268cdd9967b4fc212af4af27b1688547122837c4..78bcdfc0b35fa0316616ef0c0331173dcc57fd85 100644 (file)
@@ -252,10 +252,10 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
 
     UnicodeString toString() const;
 
-    /* Returns the string in exponential notation. */
-    UnicodeString toNumberString() const;
+    /** Returns the string in standard exponential notation. */
+    UnicodeString toScientificString() const;
 
-    /* Returns the string without exponential notation. Slightly slower than toNumberString(). */
+    /** Returns the string without exponential notation. Slightly slower than toScientificString(). */
     UnicodeString toPlainString() const;
 
     /** Visible for testing */
index 62947be571145509a6297ffdd1f2aa9ed5f77292..48a45c0044983ae09ab908d60a1d25b960a8062d 100644 (file)
@@ -185,7 +185,7 @@ NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe,
     bool isAccounting =
             macros.sign == UNUM_SIGN_ACCOUNTING || macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS ||
             macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO;
-    CurrencyUnit currency(kDefaultCurrency, status);
+    CurrencyUnit currency(nullptr, status);
     if (isCurrency) {
         currency = CurrencyUnit(macros.unit, status); // Restore CurrencyUnit from MeasureUnit
     }
index ef13267dcd833454d6c72c2ce093dcbb3b0aa8c4..24a09e6f4b2c8379a809df255c228bfb89370090 100644 (file)
@@ -265,6 +265,7 @@ MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& propert
 
     if (exportedProperties != nullptr) {
 
+        exportedProperties->currency = currency;
         exportedProperties->roundingMode = roundingMode;
         exportedProperties->minimumIntegerDigits = minInt;
         exportedProperties->maximumIntegerDigits = maxInt == -1 ? INT32_MAX : maxInt;
index a1900deab82f9b70a16e00d651d1267ab851c727..dd189067a79e7bf9699582d30b89a3a42070944b 100644 (file)
@@ -459,7 +459,7 @@ void NumberStringBuilder::populateFieldPosition(FieldPosition &fp, int32_t offse
 
 void NumberStringBuilder::populateFieldPositionIterator(FieldPositionIterator &fpi, UErrorCode &status) const {
     // TODO: Set an initial capacity on uvec?
-    LocalPointer <UVector32> uvec(new UVector32(status));
+    LocalPointer <UVector32> uvec(new UVector32(status), status);
     if (U_FAILURE(status)) {
         return;
     }
index 1081919c4cc1814862e96c16e12e4e93c351d4ef..ac7b095932555ce05531530716a37323d2d0dd50 100644 (file)
@@ -38,9 +38,6 @@ static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN;
 // ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING
 static constexpr char16_t kFallbackPaddingString[] = u" ";
 
-// ICU4J Equivalent: NumberFormatterImpl.DEFAULT_CURRENCY
-static constexpr char16_t kDefaultCurrency[] = u"XXX";
-
 // Forward declarations:
 
 class Modifier;
index c2f74e5bb677ac063fd034fecd606baa13279f57..8cf702dd3361634a2da9a48357b2eeeb14d1894c 100644 (file)
@@ -104,18 +104,20 @@ void DecNum::_setTo(const char* str, int32_t maxDigits, UErrorCode& status) {
     static_assert(DECDPUN == 1, "Assumes that DECDPUN is set to 1");
     uprv_decNumberFromString(fData.getAlias(), str, &fContext);
 
-    // For consistency with Java BigDecimal, no support for DecNum that is NaN or Infinity!
-    if (decNumberIsSpecial(fData.getAlias())) {
-        status = U_UNSUPPORTED_ERROR;
-        return;
-    }
-
     // Check for invalid syntax and set the corresponding error code.
     if ((fContext.status & DEC_Conversion_syntax) != 0) {
         status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
+        return;
     } else if (fContext.status != 0) {
         // Not a syntax error, but some other error, like an exponent that is too large.
         status = U_UNSUPPORTED_ERROR;
+        return;
+    }
+
+    // For consistency with Java BigDecimal, no support for DecNum that is NaN or Infinity!
+    if (decNumberIsSpecial(fData.getAlias())) {
+        status = U_UNSUPPORTED_ERROR;
+        return;
     }
 }
 
index 320dbe0eaba24cc31f0ce77cf4ae2b088b967557..2a19b0b90879a819ef28b8a9751bf3c54e6c57ca 100644 (file)
@@ -105,18 +105,18 @@ void DecimalQuantityTest::testSwitchStorage() {
 
     fq.setToLong(1234123412341234L);
     assertFalse("Should not be using byte array", fq.isUsingBytes());
-    assertEquals("Failed on initialize", u"1234123412341234E0", fq.toNumberString());
+    assertEquals("Failed on initialize", u"1.234123412341234E+15", fq.toScientificString());
     assertHealth(fq);
     // Long -> Bytes
     fq.appendDigit(5, 0, true);
     assertTrue("Should be using byte array", fq.isUsingBytes());
-    assertEquals("Failed on multiply", u"12341234123412345E0", fq.toNumberString());
+    assertEquals("Failed on multiply", u"1.2341234123412345E+16", fq.toScientificString());
     assertHealth(fq);
     // Bytes -> Long
     fq.roundToMagnitude(5, RoundingMode::UNUM_ROUND_HALFEVEN, status);
     assertSuccess("Rounding to magnitude", status);
     assertFalse("Should not be using byte array", fq.isUsingBytes());
-    assertEquals("Failed on round", u"123412341234E5", fq.toNumberString());
+    assertEquals("Failed on round", u"1.23412341234E+16", fq.toScientificString());
     assertHealth(fq);
 }
 
@@ -170,50 +170,46 @@ void DecimalQuantityTest::testCopyMove() {
 void DecimalQuantityTest::testAppend() {
     DecimalQuantity fq;
     fq.appendDigit(1, 0, true);
-    assertEquals("Failed on append", u"1E0", fq.toNumberString());
+    assertEquals("Failed on append", u"1E+0", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(2, 0, true);
-    assertEquals("Failed on append", u"12E0", fq.toNumberString());
+    assertEquals("Failed on append", u"1.2E+1", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(3, 1, true);
-    assertEquals("Failed on append", u"1203E0", fq.toNumberString());
+    assertEquals("Failed on append", u"1.203E+3", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(0, 1, true);
-    assertEquals("Failed on append", u"1203E2", fq.toNumberString());
+    assertEquals("Failed on append", u"1.203E+5", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(4, 0, true);
-    assertEquals("Failed on append", u"1203004E0", fq.toNumberString());
+    assertEquals("Failed on append", u"1.203004E+6", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(0, 0, true);
-    assertEquals("Failed on append", u"1203004E1", fq.toNumberString());
+    assertEquals("Failed on append", u"1.203004E+7", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(5, 0, false);
-    assertEquals("Failed on append", u"120300405E-1", fq.toNumberString());
+    assertEquals("Failed on append", u"1.20300405E+7", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(6, 0, false);
-    assertEquals("Failed on append", u"1203004056E-2", fq.toNumberString());
+    assertEquals("Failed on append", u"1.203004056E+7", fq.toScientificString());
     assertHealth(fq);
     fq.appendDigit(7, 3, false);
-    assertEquals("Failed on append", u"12030040560007E-6", fq.toNumberString());
+    assertEquals("Failed on append", u"1.2030040560007E+7", fq.toScientificString());
     assertHealth(fq);
-    UnicodeString baseExpected(u"12030040560007");
+    UnicodeString baseExpected(u"1.2030040560007");
     for (int i = 0; i < 10; i++) {
         fq.appendDigit(8, 0, false);
         baseExpected.append(u'8');
         UnicodeString expected(baseExpected);
-        expected.append(u"E-");
-        if (i >= 3) {
-            expected.append(u'1');
-        }
-        expected.append(((7 + i) % 10) + u'0');
-        assertEquals("Failed on append", expected, fq.toNumberString());
+        expected.append(u"E+7");
+        assertEquals("Failed on append", expected, fq.toScientificString());
         assertHealth(fq);
     }
     fq.appendDigit(9, 2, false);
     baseExpected.append(u"009");
     UnicodeString expected(baseExpected);
-    expected.append(u"E-19");
-    assertEquals("Failed on append", expected, fq.toNumberString());
+    expected.append(u"E+7");
+    assertEquals("Failed on append", expected, fq.toScientificString());
     assertHealth(fq);
 }
 
index cf9bd3bc8a4b0c95014185dd2df92f528ba1f6e9..dc014a3c92d773724b57c6b4a69a72c3e872c2f5 100644 (file)
@@ -458,15 +458,15 @@ UBool NumberFormatTestDataDriven::isParsePass(
 
     DecimalQuantity expectedQuantity;
     strToDigitList(tuple.output, expectedQuantity, status);
-    UnicodeString expectedString = expectedQuantity.toNumberString();
+    UnicodeString expectedString = expectedQuantity.toScientificString();
     if (U_FAILURE(status)) {
         appendErrorMessage.append("[Error parsing decnumber] ");
         // If this happens, assume that tuple.output is exactly the same format as
-        // DecimalQuantity.toNumberString()
+        // DecimalQuantity.toScientificString()
         expectedString = tuple.output;
         status = U_ZERO_ERROR;
     }
-    UnicodeString actualString = result.getDecimalQuantity()->toNumberString();
+    UnicodeString actualString = result.getDecimalQuantity()->toScientificString();
     if (expectedString != actualString) {
         appendErrorMessage.append(
                 UnicodeString("Expected: ") + tuple.output + " (i.e., " + expectedString + "), but got: " +
@@ -503,7 +503,7 @@ UBool NumberFormatTestDataDriven::isParseCurrencyPass(
     }
     UnicodeString currStr(currAmt->getISOCurrency());
     U_ASSERT(currAmt->getNumber().getDecimalQuantity() != nullptr); // no doubles in currency tests
-    UnicodeString resultStr = currAmt->getNumber().getDecimalQuantity()->toNumberString();
+    UnicodeString resultStr = currAmt->getNumber().getDecimalQuantity()->toScientificString();
     if (tuple.output == "fail") {
         appendErrorMessage.append(UnicodeString("Parse succeeded: ") + resultStr + ", but was expected to fail.");
         return TRUE; // TRUE because failure handling is in the test suite
@@ -511,7 +511,7 @@ UBool NumberFormatTestDataDriven::isParseCurrencyPass(
 
     DecimalQuantity expectedQuantity;
     strToDigitList(tuple.output, expectedQuantity, status);
-    UnicodeString expectedString = expectedQuantity.toNumberString();
+    UnicodeString expectedString = expectedQuantity.toScientificString();
     if (U_FAILURE(status)) {
         appendErrorMessage.append("Error parsing decnumber");
         // If this happens, assume that tuple.output is exactly the same format as
@@ -6978,15 +6978,11 @@ const char* attrString(int32_t attrId) {
 //      API test, not a comprehensive test.
 //      See DecimalFormatTest/DataDrivenTests
 //
-#define ASSERT_SUCCESS(status) {if (U_FAILURE(status)) errln("file %s, line %d: status: %s", \
-                                                __FILE__, __LINE__, u_errorName(status));}
-#define ASSERT_EQUALS(expected, actual) {if ((expected) != (actual)) \
-                  errln("file %s, line %d: %s != %s", __FILE__, __LINE__, #expected, #actual);}
-
-static UBool operator != (const char *s1, UnicodeString &s2) {
-    // This function lets ASSERT_EQUALS("literal", UnicodeString) work.
-    UnicodeString us1(s1);
-    return us1 != s2;
+#define ASSERT_SUCCESS(status) { \
+    assertSuccess(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (status)); \
+}
+#define ASSERT_EQUALS(expected, actual) { \
+    assertEquals(UnicodeString("file ") + __FILE__ + ", line " + __LINE__, (expected), (actual)); \
 }
 
 void NumberFormatTest::TestDecimal() {
@@ -6996,7 +6992,7 @@ void NumberFormatTest::TestDecimal() {
         ASSERT_SUCCESS(status);
         StringPiece s = f.getDecimalNumber(status);
         ASSERT_SUCCESS(status);
-        ASSERT_EQUALS("1.2345678999987654321E+667", s);
+        ASSERT_EQUALS("1.2345678999987654321E+667", s.data());
         //printf("%s\n", s.data());
     }
 
@@ -7015,7 +7011,7 @@ void NumberFormatTest::TestDecimal() {
         ASSERT_EQUALS(123.45, f.getDouble());
         ASSERT_EQUALS(123.45, f.getDouble(status));
         ASSERT_SUCCESS(status);
-        ASSERT_EQUALS("123.45", f.getDecimalNumber(status));
+        ASSERT_EQUALS("123.45", f.getDecimalNumber(status).data());
         ASSERT_SUCCESS(status);
 
         f.setDecimalNumber("4.5678E7", status);
@@ -7030,7 +7026,7 @@ void NumberFormatTest::TestDecimal() {
         ASSERT_EQUALS(-123, f.getLong());
         ASSERT_EQUALS(-123, f.getLong(status));
         ASSERT_SUCCESS(status);
-        ASSERT_EQUALS("-123", f.getDecimalNumber(status));
+        ASSERT_EQUALS("-123", f.getDecimalNumber(status).data());
         ASSERT_SUCCESS(status);
 
         status = U_ZERO_ERROR;
@@ -7040,7 +7036,7 @@ void NumberFormatTest::TestDecimal() {
         ASSERT_EQUALS(1234567890123LL, f.getInt64());
         ASSERT_EQUALS(1234567890123LL, f.getInt64(status));
         ASSERT_SUCCESS(status);
-        ASSERT_EQUALS("1234567890123", f.getDecimalNumber(status));
+        ASSERT_EQUALS("1.234567890123E+12", f.getDecimalNumber(status).data());
         ASSERT_SUCCESS(status);
     }
 
@@ -7103,7 +7099,7 @@ void NumberFormatTest::TestDecimal() {
             Formattable result;
             fmtr->parse(input, result, status);
             ASSERT_SUCCESS(status);
-            ASSERT_EQUALS(0, strcmp("0.0184", result.getDecimalNumber(status).data()));
+            ASSERT_EQUALS("0.0184", result.getDecimalNumber(status).data());
             //std::cout << result.getDecimalNumber(status).data();
             delete fmtr;
         }
@@ -7156,8 +7152,8 @@ void NumberFormatTest::TestCurrencyFractionDigits() {
             errln((UnicodeString)"NumberFormat::format() should return the same result - text1="
                 + text1 + " text2=" + text2);
         }
-        delete fmt;
     }
+    delete fmt;
 }
 
 void NumberFormatTest::TestExponentParse() {
index 772691004ee19a2b6cc4bcb57f80503923a79b52..160c4fd1f80802764b009cfb5753cba0bc9cb858 100644 (file)
@@ -947,7 +947,7 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
         if (isNegative()) {
             sb.append('-');
         }
-        if (precision == 0) {
+        if (precision == 0 || getMagnitude() < 0) {
             sb.append('0');
         }
         for (int m = getUpperDisplayMagnitude(); m >= getLowerDisplayMagnitude(); m--) {
@@ -958,6 +958,48 @@ public abstract class DecimalQuantity_AbstractBCD implements DecimalQuantity {
         return sb.toString();
     }
 
+    public String toScientificString() {
+        StringBuilder sb = new StringBuilder();
+        toScientificString(sb);
+        return sb.toString();
+    }
+
+    public void toScientificString(StringBuilder result) {
+        assert(!isApproximate);
+        if (isNegative()) {
+            result.append('-');
+        }
+        if (precision == 0) {
+            result.append("0E+0");
+            return;
+        }
+        result.append((char) ('0' + getDigitPos(precision - 1)));
+        if (precision > 1) {
+            result.append('.');
+            for (int i = 1; i < precision; i++) {
+                result.append((char) ('0' + getDigitPos(precision - i - 1)));
+            }
+        }
+        result.append('E');
+        int _scale = scale + precision - 1;
+        if (_scale < 0) {
+            _scale *= -1;
+            result.append('-');
+        } else {
+            result.append('+');
+        }
+        if (_scale == 0) {
+            result.append('0');
+        }
+        int insertIndex = result.length();
+        while (_scale > 0) {
+            int quot = _scale / 10;
+            int rem = _scale % 10;
+            result.insert(insertIndex, (char) ('0' + rem));
+            _scale = quot;
+        }
+    }
+
     /**
      * Returns a single digit from the BCD list. No internal state is changed by calling this method.
      *
index 72a923a21660e24213b8564d0282b0d31a1d7043..8d8e791ccaa6d8e35fdfcdd7219dc7609a1babe1 100644 (file)
@@ -425,7 +425,7 @@ public final class DecimalQuantity_DualStorageBCD extends DecimalQuantity_Abstra
                 toNumberString());
     }
 
-    public String toNumberString() {
+    private String toNumberString() {
         StringBuilder sb = new StringBuilder();
         if (usingBytes) {
             if (precision == 0) {
index 385944f677d799a14c0a97709f75f6a2326950e3..b3051bc4f68094c68ec7e41f0366a77f17118be8 100644 (file)
@@ -306,6 +306,7 @@ final class NumberPropertyMapper {
 
         if (exportedProperties != null) {
 
+            exportedProperties.setCurrency(currency);
             exportedProperties.setMathContext(mathContext);
             exportedProperties.setRoundingMode(mathContext.getRoundingMode());
             exportedProperties.setMinimumIntegerDigits(minInt);
index f1ec364337807fff4541c953167eeea70c4916a0..fa54739c496e524acc65dcef65ff62e7b1ef7b84 100644 (file)
@@ -2006,7 +2006,7 @@ public class DecimalFormat extends NumberFormat {
   }
 
   /**
-   * Returns the user-specified currency. May be null.
+   * Returns the currency used to display currency amounts. May be null.
    *
    * @see #setCurrency
    * @see DecimalFormatSymbols#getCurrency
@@ -2015,7 +2015,7 @@ public class DecimalFormat extends NumberFormat {
    */
   @Override
   public synchronized Currency getCurrency() {
-    return properties.getCurrency();
+    return exportedProperties.getCurrency();
   }
 
   /**
index d1386fcb87bf27d71a197f73e91d1c2b0e719b99..6a784fdf4c681950754838a245962cf45e8b4bf1 100644 (file)
@@ -5450,8 +5450,8 @@ public class NumberFormatTest extends TestFmwk {
 
     @Test
     public void testGetSetCurrency() {
-        DecimalFormat df = new DecimalFormat("¤#");
-        assertEquals("Currency should start out null", null, df.getCurrency());
+        DecimalFormat df = new DecimalFormat("¤#", DecimalFormatSymbols.getInstance(ULocale.US));
+        assertEquals("Currency should start out as the locale default", Currency.getInstance("USD"), df.getCurrency());
         Currency curr = Currency.getInstance("EUR");
         df.setCurrency(curr);
         assertEquals("Currency should equal EUR after set", curr, df.getCurrency());
index 85877343a25618b42bfb2636c99526da5b8d94c0..256f548e846f743e8e26ffd7d4867331914d6e26 100644 (file)
@@ -292,17 +292,17 @@ public class DecimalQuantityTest extends TestFmwk {
 
         fq.setToLong(1234123412341234L);
         assertFalse("Should not be using byte array", fq.isUsingBytes());
-        assertEquals("Failed on initialize", "1234123412341234E0", fq.toNumberString());
+        assertEquals("Failed on initialize", "1.234123412341234E+15", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         // Long -> Bytes
         fq.appendDigit((byte) 5, 0, true);
         assertTrue("Should be using byte array", fq.isUsingBytes());
-        assertEquals("Failed on multiply", "12341234123412345E0", fq.toNumberString());
+        assertEquals("Failed on multiply", "1.2341234123412345E+16", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         // Bytes -> Long
         fq.roundToMagnitude(5, MATH_CONTEXT_HALF_EVEN);
         assertFalse("Should not be using byte array", fq.isUsingBytes());
-        assertEquals("Failed on round", "123412341234E5", fq.toNumberString());
+        assertEquals("Failed on round", "1.23412341234E+16", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
     }
 
@@ -310,48 +310,46 @@ public class DecimalQuantityTest extends TestFmwk {
     public void testAppend() {
         DecimalQuantity_DualStorageBCD fq = new DecimalQuantity_DualStorageBCD();
         fq.appendDigit((byte) 1, 0, true);
-        assertEquals("Failed on append", "1E0", fq.toNumberString());
+        assertEquals("Failed on append", "1E+0", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 2, 0, true);
-        assertEquals("Failed on append", "12E0", fq.toNumberString());
+        assertEquals("Failed on append", "1.2E+1", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 3, 1, true);
-        assertEquals("Failed on append", "1203E0", fq.toNumberString());
+        assertEquals("Failed on append", "1.203E+3", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 0, 1, true);
-        assertEquals("Failed on append", "1203E2", fq.toNumberString());
+        assertEquals("Failed on append", "1.203E+5", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 4, 0, true);
-        assertEquals("Failed on append", "1203004E0", fq.toNumberString());
+        assertEquals("Failed on append", "1.203004E+6", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 0, 0, true);
-        assertEquals("Failed on append", "1203004E1", fq.toNumberString());
+        assertEquals("Failed on append", "1.203004E+7", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 5, 0, false);
-        assertEquals("Failed on append", "120300405E-1", fq.toNumberString());
+        assertEquals("Failed on append", "1.20300405E+7", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 6, 0, false);
-        assertEquals("Failed on append", "1203004056E-2", fq.toNumberString());
+        assertEquals("Failed on append", "1.203004056E+7", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
         fq.appendDigit((byte) 7, 3, false);
-        assertEquals("Failed on append", "12030040560007E-6", fq.toNumberString());
+        assertEquals("Failed on append", "1.2030040560007E+7", fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
-        StringBuilder baseExpected = new StringBuilder("12030040560007");
+        StringBuilder baseExpected = new StringBuilder("1.2030040560007");
         for (int i = 0; i < 10; i++) {
             fq.appendDigit((byte) 8, 0, false);
             baseExpected.append('8');
             StringBuilder expected = new StringBuilder(baseExpected);
-            expected.append("E");
-            expected.append(-7 - i);
-            assertEquals("Failed on append", expected.toString(), fq.toNumberString());
+            expected.append("E+7");
+            assertEquals("Failed on append", expected.toString(), fq.toScientificString());
             assertNull("Failed health check", fq.checkHealth());
         }
         fq.appendDigit((byte) 9, 2, false);
         baseExpected.append("009");
         StringBuilder expected = new StringBuilder(baseExpected);
-        expected.append('E');
-        expected.append("-19");
-        assertEquals("Failed on append", expected.toString(), fq.toNumberString());
+        expected.append("E+7");
+        assertEquals("Failed on append", expected.toString(), fq.toScientificString());
         assertNull("Failed health check", fq.checkHealth());
     }