ICU-2552 number of zeros

X-SVN-Rev: 13520
This commit is contained in:
Doug Felt 2003-10-29 00:20:05 +00:00
parent ed3bced160
commit 3f812b4d59
6 changed files with 218 additions and 50 deletions

View File

@ -104,6 +104,8 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat)
const int32_t DecimalFormat::kDoubleIntegerDigits = 309;
const int32_t DecimalFormat::kDoubleFractionDigits = 340;
const int32_t DecimalFormat::kMaxScientificIntegerDigits = 8;
/**
* These are the tags we expect to see in normal resource bundle files associated
* with a locale.
@ -612,15 +614,12 @@ DecimalFormat::format(int32_t number,
|| number < (INT32_MIN / fMultiplier))))
{
digits.set(((double)number) * fMultiplier,
fUseExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() : 0,
precision(FALSE),
!fUseExponentialNotation);
}
else
{
digits.set(number * fMultiplier,
fUseExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() : 0);
digits.set(number * fMultiplier, precision(TRUE));
}
return subformat(appendTo, fieldPosition, digits, TRUE);
@ -704,9 +703,7 @@ DecimalFormat::format( double number,
DigitList digits;
// This detects negativity too.
digits.set(number, fUseExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() :
getMaximumFractionDigits(),
digits.set(number, precision(FALSE),
!fUseExponentialNotation);
return subformat(appendTo, fieldPosition, digits, FALSE);
@ -802,6 +799,15 @@ DecimalFormat::subformat(UnicodeString& appendTo,
}
int32_t maxIntDig = getMaximumIntegerDigits();
int32_t minIntDig = getMinimumIntegerDigits();
if (fUseExponentialNotation && maxIntDig > kMaxScientificIntegerDigits) {
maxIntDig = 1;
if (maxIntDig < minIntDig) {
maxIntDig = minIntDig;
}
}
if (fUseExponentialNotation && maxIntDig > minIntDig) {
minIntDig = 1;
}
/* Per bug 4147706, DecimalFormat must respect the sign of numbers which
* format as zero. This allows sensible computations and preserves
@ -926,8 +932,14 @@ DecimalFormat::subformat(UnicodeString& appendTo,
DigitList expDigits;
expDigits.set(exponent);
for (i=expDigits.fDecimalAt; i<fMinExponentDigits; ++i)
appendTo += (zero);
{
int expDig = fMinExponentDigits;
if (fUseExponentialNotation && expDig < 1) {
expDig = 1;
}
for (i=expDigits.fDecimalAt; i<expDig; ++i)
appendTo += (zero);
}
for (i=0; i<expDigits.fDecimalAt; ++i)
{
UChar32 c = (UChar32)((i < expDigits.fCount) ?
@ -2091,9 +2103,6 @@ UBool DecimalFormat::isScientificNotation() {
*/
void DecimalFormat::setScientificNotation(UBool useScientific) {
fUseExponentialNotation = useScientific;
if (fUseExponentialNotation && fMinExponentDigits < 1) {
fMinExponentDigits = 1;
}
}
/**
@ -2619,9 +2628,15 @@ DecimalFormat::toPattern(UnicodeString& result, UBool localized) const
if (g > 0 && fGroupingSize2 > 0 && fGroupingSize2 != fGroupingSize) {
g += fGroupingSize2;
}
int32_t maxIntDig = fUseExponentialNotation ? getMaximumIntegerDigits() :
(uprv_max(uprv_max(g, getMinimumIntegerDigits()),
roundingDecimalPos) + 1);
int maxIntDig = getMaximumIntegerDigits();
if (fUseExponentialNotation) {
if (maxIntDig > kMaxScientificIntegerDigits) {
maxIntDig = 1;
}
} else {
maxIntDig = uprv_max(uprv_max(g, getMinimumIntegerDigits()),
roundingDecimalPos) + 1;
}
for (i = maxIntDig; i > 0; --i) {
if (!fUseExponentialNotation && i<maxIntDig &&
isGroupingPosition(i)) {
@ -3463,6 +3478,13 @@ void DecimalFormat::setCurrency(const UChar* theCurrency) {
}
}
int32_t
DecimalFormat::precision(UBool isIntegral) const {
return fUseExponentialNotation
? getMinimumIntegerDigits() + getMaximumFractionDigits()
: (isIntegral ? 0 : getMaximumFractionDigits());
}
U_NAMESPACE_END
#endif /* #if !UCONFIG_NO_FORMATTING */

View File

@ -752,7 +752,11 @@ public:
virtual UBool isScientificNotation(void);
/**
* Set whether or not scientific notation is used.
* Set whether or not scientific notation is used. When scientific notation
* is used, the effective maximum number of integer digits is <= 8. If the
* maximum number of integer digits is set to more than 8, the effective
* maximum will be 1. This allows this call to generate a 'default' scientific
* number format without additional changes.
* @param useScientific TRUE if this object formats and parses scientific
* notation
* @see #isScientificNotation
@ -1106,6 +1110,8 @@ public:
private:
DecimalFormat(); // default constructor not implemented
int32_t precision(UBool isIntegral) const;
/**
* Do real work of constructing a new DecimalFormat.
*/
@ -1294,6 +1300,17 @@ protected:
* @draft ICU 2.4
*/
static const int32_t kDoubleFractionDigits;
/**
* When someone turns on scientific mode, we assume that more than this
* number of digits is due to flipping from some other mode that didn't
* restrict the maximum, and so we force 1 integer digit. We don't bother
* to track and see if someone is using exponential notation with more than
* this number, it wouldn't make sense anyway, and this is just to make sure
* that someone turning on scientific mode with default settings doesn't
* end up with lots of zeroes.
*/
static const int32_t kMaxScientificIntegerDigits;
};
inline UnicodeString&

View File

@ -61,6 +61,9 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
CASE(20,TestSymbolsWithBadLocale);
CASE(21,TestAdoptDecimalFormatSymbols);
CASE(22,TestScientific2);
CASE(23,TestScientificGrouping);
default: name = ""; break;
}
}
@ -146,7 +149,7 @@ NumberFormatTest::TestDigitList(void)
list1.append('1');
list1.fDecimalAt = 1;
DigitList list2;
list2.set(1);
list2.set((int32_t)1);
if (list1 != list2) {
errln("digitlist append, operator!= or set failed ");
}
@ -334,6 +337,37 @@ NumberFormatTest::TestExponential(void)
}
}
void
NumberFormatTest::TestScientific2() {
// jb 2552
UErrorCode status = U_ZERO_ERROR;
DecimalFormat* fmt = (DecimalFormat*)NumberFormat::createCurrencyInstance("en_US", status);
if (U_SUCCESS(status)) {
double num = 12.34;
expect(*fmt, num, "$12.34");
fmt->setScientificNotation(TRUE);
expect(*fmt, num, "$1.23E1");
fmt->setScientificNotation(FALSE);
expect(*fmt, num, "$12.34");
}
delete fmt;
}
void
NumberFormatTest::TestScientificGrouping() {
// jb 2552
UErrorCode status = U_ZERO_ERROR;
DecimalFormat fmt("###.##E0",status);
if (U_SUCCESS(status)) {
expect(fmt, .01234, "12.3E-3");
expect(fmt, .1234, "123E-3");
expect(fmt, 1.234, "1.23E0");
expect(fmt, 12.34, "12.3E0");
expect(fmt, 123.4, "123E0");
expect(fmt, 1234., "1.23E3");
}
}
// -------------------------------------
// Test the handling of quotes

View File

@ -75,6 +75,10 @@ class NumberFormatTest: public CalendarTimeZoneTest {
void TestScientific(void);
void TestScientific2(void);
void TestScientificGrouping(void);
void TestSurrogateSupport(void);
/**

View File

@ -4,8 +4,8 @@
* others. All Rights Reserved. *
*******************************************************************************
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/dev/test/format/NumberFormatTest.java,v $
* $Date: 2003/06/11 18:49:38 $
* $Revision: 1.19 $
* $Date: 2003/10/29 00:20:05 $
* $Revision: 1.20 $
*
*****************************************************************************************
*/
@ -24,6 +24,7 @@ import com.ibm.icu.util.*;
import java.math.BigInteger;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.ParseException;
import java.util.Locale;
public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
@ -173,6 +174,20 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
errln("FAIL: Expected a'b123");
}
public void TestParseCurrencyTrailingSymbol() {
// see sun bug 4709840
NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.GERMANY);
float val = 12345.67f;
String str = fmt.format(val);
logln("val: " + val + " str: " + str);
try {
Number num = fmt.parse(str);
logln("num: " + num);
} catch (ParseException e) {
errln("parse of '" + str + "' threw exception: " + e);
}
}
/**
* Test the handling of the currency symbol in patterns.
**/
@ -734,6 +749,28 @@ public class NumberFormatTest extends com.ibm.icu.dev.test.TestFmwk {
}
}
public void TestScientific2() {
// jb 2552
DecimalFormat fmt = (DecimalFormat)NumberFormat.getCurrencyInstance();
Number num = new Double(12.34);
expect(fmt, num, "$12.34");
fmt.setScientificNotation(true);
expect(fmt, num, "$1.23E1");
fmt.setScientificNotation(false);
expect(fmt, num, "$12.34");
}
public void TestScientificGrouping() {
// jb 2552
DecimalFormat fmt = new DecimalFormat("###.##E0");
expect(fmt, .01234, "12.3E-3");
expect(fmt, .1234, "123E-3");
expect(fmt, 1.234, "1.23E0");
expect(fmt, 12.34, "12.3E0");
expect(fmt, 123.4, "123E0");
expect(fmt, 1234, "1.23E3");
}
// additional coverage tests
// sigh, can't have static inner classes, why not?

View File

@ -5,8 +5,8 @@
*******************************************************************************
*
* $Source: /xsrl/Nsvn/icu/icu4j/src/com/ibm/icu/text/DecimalFormat.java,v $
* $Date: 2003/09/12 10:31:16 $
* $Revision: 1.36 $
* $Date: 2003/10/29 00:20:03 $
* $Revision: 1.37 $
*
*****************************************************************************************
*/
@ -616,11 +616,7 @@ public class DecimalFormat extends NumberFormat {
// At this point we are guaranteed a nonnegative finite
// number.
synchronized(digitList) {
digitList.set(number, useExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() :
getMaximumFractionDigits(),
!useExponentialNotation);
digitList.set(number, precision(false), !useExponentialNotation);
return subformat(result, fieldPosition, isNegative, false);
}
}
@ -729,9 +725,7 @@ public class DecimalFormat extends NumberFormat {
number *= multiplier;
synchronized(digitList) {
digitList.set(number, useExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() : 0);
digitList.set(number, precision(true));
return subformat(result, fieldPosition, isNegative, true);
}
}
@ -756,9 +750,7 @@ public class DecimalFormat extends NumberFormat {
// At this point we are guaranteed a nonnegative finite
// number.
synchronized(digitList) {
digitList.set(number, useExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() : 0);
digitList.set(number, precision(true));
return subformat(result, fieldPosition, number.signum() < 0, false);
}
}
@ -782,15 +774,11 @@ public class DecimalFormat extends NumberFormat {
// At this point we are guaranteed a nonnegative finite
// number.
synchronized(digitList) {
digitList.set(number, useExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() :
getMaximumFractionDigits(),
!useExponentialNotation);
digitList.set(number, precision(false), !useExponentialNotation);
return subformat(result, fieldPosition, number.signum() < 0, false);
}
}
/**
* <strong><font face=helvetica color=red>NEW</font></strong>
* Format a BigDecimal number.
@ -817,10 +805,7 @@ public class DecimalFormat extends NumberFormat {
// At this point we are guaranteed a nonnegative finite
// number.
synchronized(digitList) {
digitList.set(number, useExponentialNotation ?
getMinimumIntegerDigits() + getMaximumFractionDigits() :
getMaximumFractionDigits(),
!useExponentialNotation);
digitList.set(number, precision(false), !useExponentialNotation);
return subformat(result, fieldPosition, number.signum() < 0, false);
}
}
@ -847,6 +832,23 @@ public class DecimalFormat extends NumberFormat {
return result;
}
/**
* Return the number of digits to show.
*/
private int precision(boolean isIntegral) {
int maxIntDig = getMaximumIntegerDigits();
int minIntDig = getMinimumIntegerDigits();
if (useExponentialNotation && maxIntDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
maxIntDig = 1;
if (maxIntDig < minIntDig) {
maxIntDig = minIntDig;
}
}
return useExponentialNotation
? getMinimumIntegerDigits() + getMaximumFractionDigits()
: (isIntegral ? 0 : getMaximumFractionDigits());
}
/**
* Complete the formatting of a finite number. On entry, the digitList must
* be filled in with the correct digits.
@ -877,6 +879,15 @@ public class DecimalFormat extends NumberFormat {
symbols.getDecimalSeparator();
int maxIntDig = getMaximumIntegerDigits();
int minIntDig = getMinimumIntegerDigits();
if (useExponentialNotation && maxIntDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
maxIntDig = 1;
if (maxIntDig < minIntDig) {
maxIntDig = minIntDig;
}
}
if (useExponentialNotation && maxIntDig > minIntDig) {
minIntDig = 1;
}
/* Per bug 4147706, DecimalFormat must respect the sign of numbers which
* format as zero. This allows sensible computations and preserves
@ -997,7 +1008,13 @@ public class DecimalFormat extends NumberFormat {
result.append(symbols.getPlusSign());
}
digitList.set(exponent);
for (i=digitList.decimalAt; i<minExponentDigits; ++i) result.append(zero);
{
int expDig = minExponentDigits;
if (useExponentialNotation && expDig < 1) {
expDig = 1;
}
for (i=digitList.decimalAt; i<expDig; ++i) result.append(zero);
}
for (i=0; i<digitList.decimalAt; ++i)
{
result.append((i < digitList.count) ?
@ -2155,7 +2172,11 @@ public class DecimalFormat extends NumberFormat {
/**
* <strong><font face=helvetica color=red>NEW</font></strong>
* Set whether or not scientific notation is used.
* Set whether or not scientific notation is used. When scientific notation
* is used, the effective maximum number of integer digits is <= 8. If the
* maximum number of integer digits is set to more than 8, the effective
* maximum will be 1. This allows this call to generate a 'default' scientific
* number format without additional changes.
* @param useScientific true if this object formats and parses scientific
* notation
* @see #isScientificNotation
@ -2167,9 +2188,6 @@ public class DecimalFormat extends NumberFormat {
*/
public void setScientificNotation(boolean useScientific) {
useExponentialNotation = useScientific;
if (useExponentialNotation && minExponentDigits < 1) {
minExponentDigits = 1;
}
}
/**
@ -2387,6 +2405,25 @@ public class DecimalFormat extends NumberFormat {
&& symbols.equals(other.symbols));
}
// protected void handleToString(StringBuffer buf) {
// super.handleToString(buf);
// buf.append("\nposPrefixPattern: '" + posPrefixPattern + "'\n");
// buf.append("positivePrefix: '" + positivePrefix + "'\n");
// buf.append("posSuffixPattern: '" + posSuffixPattern + "'\n");
// buf.append("positiveSuffix: '" + positiveSuffix + "'\n");
// buf.append("negPrefixPattern: '" + Utility.format1ForSource(negPrefixPattern) + "'\n");
// buf.append("negativePrefix: '" + Utility.format1ForSource(negativePrefix) + "'\n");
// buf.append("negSuffixPattern: '" + negSuffixPattern + "'\n");
// buf.append("negativeSuffix: '" + negativeSuffix + "'\n");
// buf.append("multiplier: '" + multiplier + "'\n");
// buf.append("groupingSize: '" + groupingSize + "'\n");
// buf.append("groupingSize2: '" + groupingSize2 + "'\n");
// buf.append("decimalSeparatorAlwaysShown: '" + decimalSeparatorAlwaysShown + "'\n");
// buf.append("useExponentialNotation: '" + useExponentialNotation + "'\n");
// buf.append("minExponentDigits: '" + minExponentDigits + "'\n");
// buf.append("symbols: '" + symbols + "'");
// }
/**
* Overrides hashCode
* @stable ICU 2.0
@ -2718,9 +2755,15 @@ public class DecimalFormat extends NumberFormat {
if (g > 0 && groupingSize2 > 0 && groupingSize2 != groupingSize) {
g += groupingSize2;
}
int maxIntDig = useExponentialNotation ? getMaximumIntegerDigits() :
(Math.max(Math.max(g, getMinimumIntegerDigits()),
int maxIntDig = getMaximumIntegerDigits();
if (useExponentialNotation) {
if (maxIntDig > MAX_SCIENTIFIC_INTEGER_DIGITS) {
maxIntDig = 1;
}
} else {
maxIntDig = (Math.max(Math.max(g, getMinimumIntegerDigits()),
roundingDecimalPos) + 1);
}
for (i = maxIntDig; i > 0; --i) {
if (!useExponentialNotation && i<maxIntDig &&
isGroupingPosition(i)) {
@ -3846,6 +3889,17 @@ public class DecimalFormat extends NumberFormat {
static final int DOUBLE_INTEGER_DIGITS = 309;
static final int DOUBLE_FRACTION_DIGITS = 340;
/**
* When someone turns on scientific mode, we assume that more than this
* number of digits is due to flipping from some other mode that didn't
* restrict the maximum, and so we force 1 integer digit. We don't bother
* to track and see if someone is using exponential notation with more than
* this number, it wouldn't make sense anyway, and this is just to make sure
* that someone turning on scientific mode with default settings doesn't
* end up with lots of zeroes.
*/
static final int MAX_SCIENTIFIC_INTEGER_DIGITS = 8;
// Proclaim JDK 1.1 serial compatibility.
static final long serialVersionUID = 864413376551465018L;