ICU-13634 Changing DecimalQuantity#toNumberString() to be DecimalQuantity#toScientificString() with slightly friendlier output syntax for better compatibility. More currency tweaks.

X-SVN-Rev: 41215
This commit is contained in:
Shane Carr 2018-04-11 05:52:58 +00:00
parent a901b5c04a
commit cd92fa2c88
18 changed files with 194 additions and 132 deletions

View file

@ -18,20 +18,23 @@
#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);

View 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);

View 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;
}

View 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 */

View 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 */

View 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
}

View 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;

View 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;
}

View 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;

View 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())) {
// 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;
}
// Check for invalid syntax and set the corresponding error code.
if ((fContext.status & DEC_Conversion_syntax) != 0) {
status = U_DECIMAL_NUMBER_SYNTAX_ERROR;
} else if (fContext.status != 0) {
// Not a syntax error, but some other error, like an exponent that is too large.
// For consistency with Java BigDecimal, no support for DecNum that is NaN or Infinity!
if (decNumberIsSpecial(fData.getAlias())) {
status = U_UNSUPPORTED_ERROR;
return;
}
}

View 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);
}

View 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() {

View 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.
*

View 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) {

View file

@ -306,6 +306,7 @@ final class NumberPropertyMapper {
if (exportedProperties != null) {
exportedProperties.setCurrency(currency);
exportedProperties.setMathContext(mathContext);
exportedProperties.setRoundingMode(mathContext.getRoundingMode());
exportedProperties.setMinimumIntegerDigits(minInt);

View 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();
}
/**

View 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());

View 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());
}