]> granicus.if.org Git - icu/commitdiff
ICU-9889 Implement scaling for decimalFormat
authorJohn Emmons <emmo@us.ibm.com>
Thu, 7 Feb 2013 19:48:29 +0000 (19:48 +0000)
committerJohn Emmons <emmo@us.ibm.com>
Thu, 7 Feb 2013 19:48:29 +0000 (19:48 +0000)
X-SVN-Rev: 33138

icu4c/source/i18n/decimfmt.cpp
icu4c/source/i18n/unicode/decimfmt.h
icu4c/source/i18n/unicode/unum.h
icu4c/source/test/intltest/dcfmapts.cpp
icu4c/source/test/intltest/dcfmapts.h

index d5f4f6a513c19a57fa8d9c44970f50240af099cc..69cb3ddb01ab7c15724c11f2b4050dea05679916 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and    *
+* Copyright (C) 1997-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
@@ -341,6 +341,7 @@ DecimalFormat::init(UErrorCode &status) {
     fNegSuffixPattern = 0;
     fCurrencyChoice = 0;
     fMultiplier = NULL;
+    fScale = 0;
     fGroupingSize = 0;
     fGroupingSize2 = 0;
     fDecimalSeparatorAlwaysShown = FALSE;
@@ -1057,6 +1058,8 @@ void DecimalFormat::handleChanged() {
     debug("No format fastpath: fMinSignificantDigits!=1");
   } else if(fMultiplier!=NULL) {
     debug("No format fastpath: fMultiplier!=NULL");
+  } else if(fScale!=0) {
+    debug("No format fastpath: fScale!=0");
   } else if(0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)) {
     debug("No format fastpath: 0x0030 != getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0)");
   } else if(fDecimalSeparatorAlwaysShown) {
@@ -1368,6 +1371,26 @@ DecimalFormat::_round(const DigitList &number, DigitList &adjustedNum, UBool& is
         }
     }
 
+    if (fScale != 0) {
+        DigitList ten;
+        ten.set(10);
+        if (fScale > 0) {
+            for (int32_t i = fScale ; i > 0 ; i--) {
+                adjustedNum.mult(ten, status);
+                if (U_FAILURE(status)) {
+                    return adjustedNum;
+                }
+            }
+        } else {
+            for (int32_t i = fScale ; i < 0 ; i++) {
+                adjustedNum.div(ten, status);
+                if (U_FAILURE(status)) {
+                    return adjustedNum;
+                }
+            }
+        }
+    }
+
     /*
      * Note: sign is important for zero as well as non-zero numbers.
      * Proper detection of -0.0 is needed to deal with the
@@ -1997,6 +2020,22 @@ void DecimalFormat::parse(const UnicodeString& text,
             digits->div(*fMultiplier, ec);
         }
 
+        if (fScale != 0) {
+            DigitList ten;
+            ten.set(10);
+            if (fScale > 0) {
+                for (int32_t i = fScale; i > 0; i--) {
+                    UErrorCode ec = U_ZERO_ERROR;
+                    digits->div(ten,ec);
+                }
+            } else {
+                for (int32_t i = fScale; i < 0; i++) {
+                    UErrorCode ec = U_ZERO_ERROR;
+                    digits->mult(ten,ec);
+                }
+            }
+        }
+
         // Negative zero special case:
         //    if parsing integerOnly, change to +0, which goes into an int32 in a Formattable.
         //    if not parsing integerOnly, leave as -0, which a double can represent.
@@ -5505,6 +5544,10 @@ DecimalFormat& DecimalFormat::setAttribute( UNumberFormatAttribute attr,
       }
       break;
 
+    case UNUM_SCALE:
+        fScale = newValue;
+        break;
+
     default:
       status = U_UNSUPPORTED_ERROR;
       break;
@@ -5580,6 +5623,9 @@ int32_t DecimalFormat::getAttribute( UNumberFormatAttribute attr,
     case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS:
       return fBoolFlags.get(attr);
 
+    case UNUM_SCALE:
+        return fScale;
+
     default:
         status = U_UNSUPPORTED_ERROR;
         break;
index 2055bd03764ca7ceae04941bddd514e51dccd860..c83af5b75ac33246be6ce39d36e63706feebd6aa 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ********************************************************************************
-*   Copyright (C) 1997-2012, International Business Machines
+*   Copyright (C) 1997-2013, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 ********************************************************************************
 *
@@ -17,7 +17,8 @@
 *   07/10/97    helena      Made ParsePosition a class and get rid of the function
 *                           hiding problems.
 *   09/09/97    aliu        Ported over support for exponential formats.
-*    07/20/98    stephen        Changed documentation
+*   07/20/98    stephen     Changed documentation
+*   01/30/13    emmons      Added Scaling methods
 ********************************************************************************
 */
 
@@ -2234,6 +2235,7 @@ private:
     ChoiceFormat*           fCurrencyChoice;
 
     DigitList *             fMultiplier;   // NULL for multiplier of one
+    int32_t                 fScale;        
     int32_t                 fGroupingSize;
     int32_t                 fGroupingSize2;
     UBool                   fDecimalSeparatorAlwaysShown;
index f3132f18e6563a2977f4f50b206422a886df2f3c..b1b45d8a58e4628846fa25e5865b2259bbea2f4e 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and others.
+* Copyright (C) 1997-2013, International Business Machines Corporation and others.
 * All Rights Reserved.
 * Modification History:
 *
@@ -795,7 +795,16 @@ typedef enum UNumberFormatAttribute {
    */
   UNUM_PARSE_ALL_INPUT,
 #endif
-
+  /** 
+    * Scale, which adjusts the position of the
+    * decimal point when formatting.  Amounts will be multiplied by 10 ^ (scale)
+    * before they are formatted.  The default value for the scale is 0 ( no adjustment ).
+    *
+    * <p>Example: setting the scale to 3, 123 formats as "123,000"
+    * <p>Example: setting the scale to -4, 123 formats as "0.0123"
+    *
+   * @draft ICU 51 */
+  UNUM_SCALE,
   /** Count of "regular" numeric attributes.
    * @internal */
   UNUM_NUMERIC_ATTRIBUTE_COUNT,
@@ -831,7 +840,8 @@ typedef enum UNumberFormatAttribute {
 * @param attr The attribute to query; one of UNUM_PARSE_INT_ONLY, UNUM_GROUPING_USED,
 * UNUM_DECIMAL_ALWAYS_SHOWN, UNUM_MAX_INTEGER_DIGITS, UNUM_MIN_INTEGER_DIGITS, UNUM_INTEGER_DIGITS,
 * UNUM_MAX_FRACTION_DIGITS, UNUM_MIN_FRACTION_DIGITS, UNUM_FRACTION_DIGITS, UNUM_MULTIPLIER,
-* UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE.
+* UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE,
+* UNUM_SCALE.
 * @return The value of attr.
 * @see unum_setAttribute
 * @see unum_getDoubleAttribute
@@ -854,7 +864,7 @@ unum_getAttribute(const UNumberFormat*          fmt,
 * UNUM_DECIMAL_ALWAYS_SHOWN, UNUM_MAX_INTEGER_DIGITS, UNUM_MIN_INTEGER_DIGITS, UNUM_INTEGER_DIGITS,
 * UNUM_MAX_FRACTION_DIGITS, UNUM_MIN_FRACTION_DIGITS, UNUM_FRACTION_DIGITS, UNUM_MULTIPLIER,
 * UNUM_GROUPING_SIZE, UNUM_ROUNDING_MODE, UNUM_FORMAT_WIDTH, UNUM_PADDING_POSITION, UNUM_SECONDARY_GROUPING_SIZE,
-* or UNUM_LENIENT_PARSE.
+* UNUM_LENIENT_PARSE, or UNUM_SCALE.
 * @param newValue The new value of attr.
 * @see unum_getAttribute
 * @see unum_getDoubleAttribute
index b190a0805f673fa1972985c906bd4bcc22306e36..3287f5f6d2852aa5973ba690c1026b9257b43952 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2010, International Business Machines Corporation and
+ * Copyright (c) 1997-2013, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
@@ -54,6 +54,12 @@ void IntlTestDecimalFormatAPI::runIndexedTest( int32_t index, UBool exec, const
                TestCurrencyPluralInfo();
             }
             break;
+        case 4: name = "TestScale";
+            if(exec) {
+               logln((UnicodeString)"Scale test---");
+               TestScale();
+            }
+            break;
         default: name = ""; break;
     }
 }
@@ -448,14 +454,14 @@ void IntlTestDecimalFormatAPI::testRounding(/*char *par*/)
         //for +2.55 with RoundingIncrement=1.0
         pat.setRoundingIncrement(1.0);
         pat.format(Roundingnumber, resultStr);
-        message= (UnicodeString)"round(" + (double)Roundingnumber + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
+        message= (UnicodeString)"Round() failed:  round(" + (double)Roundingnumber + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
         verify(message, resultStr, result[i++]);
         message.remove();
         resultStr.remove();
 
         //for -2.55 with RoundingIncrement=1.0
         pat.format(Roundingnumber1, resultStr);
-        message= (UnicodeString)"round(" + (double)Roundingnumber1 + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
+        message= (UnicodeString)"Round() failed:  round(" + (double)Roundingnumber1 + UnicodeString(",") + mode + UnicodeString(",FALSE) with RoundingIncrement=1.0==>");
         verify(message, resultStr, result[i++]);
         message.remove();
         resultStr.remove();
@@ -467,7 +473,14 @@ void IntlTestDecimalFormatAPI::verify(const UnicodeString& message, const Unicod
     UnicodeString expectedStr("");
     expectedStr=expectedStr + expected;
     if(got != expectedStr ) {
-            errln((UnicodeString)"ERROR: Round() failed:  " + message + got + (UnicodeString)"  Expected : " + expectedStr);
+            errln((UnicodeString)"ERROR: " + message + got + (UnicodeString)"  Expected : " + expectedStr);
+        }
+}
+
+void IntlTestDecimalFormatAPI::verifyString(const UnicodeString& message, const UnicodeString& got, UnicodeString& expected){
+    logln((UnicodeString)message + got + (UnicodeString)" Expected : " + expected);
+    if(got != expected ) {
+            errln((UnicodeString)"ERROR: " + message + got + (UnicodeString)"  Expected : " + expected);
         }
 }
 
@@ -501,4 +514,49 @@ void IntlTestDecimalFormatAPI::testRoundingInc(/*char *par*/)
     }
 }
 
+void IntlTestDecimalFormatAPI::TestScale()
+{
+    typedef struct TestData {
+        double inputValue;
+        int inputScale;
+        char *expectedOutput;
+    } TestData;
+
+    static TestData testData[] = {
+        { 100.0, 3,  "100,000" },
+        { 10034.0, -2, "100.34" },
+        { 0.86, -3, "0.0009" },
+        { -0.000455, 1, "-0%" },
+        { -0.000555, 1, "-1%" },
+        { 0.000455, 1, "0%" },
+        { 0.000555, 1, "1%" },
+    };
+
+    UErrorCode status = U_ZERO_ERROR;
+    DecimalFormat pat(status);
+    if(U_FAILURE(status)) {
+      errcheckln(status, "ERROR: Could not create DecimalFormat (default) - %s", u_errorName(status));
+      return;
+    }
+
+    UnicodeString message;
+    UnicodeString resultStr;
+    UnicodeString exp;
+    UnicodeString percentPattern("#,##0%");
+    pat.setMaximumFractionDigits(4);
+
+    for(int32_t i=0;i < sizeof(testData)/sizeof(testData[0]);i++) {
+        if ( i > 2 ) {
+            pat.applyPattern(percentPattern,status);
+        }
+        pat.setAttribute(UNUM_SCALE,testData[i].inputScale,status);
+        pat.format(testData[i].inputValue, resultStr);
+        message = UnicodeString("Unexpected output for ") + testData[i].inputValue + UnicodeString(" and scale ") + testData[i].inputScale + UnicodeString(". Got: ");
+        exp = testData[i].expectedOutput;
+        verifyString(message, resultStr, exp);
+        message.remove();
+        resultStr.remove();
+        exp.remove();
+    }
+}
 #endif /* #if !UCONFIG_NO_FORMATTING */
index c17d0b39300bf2351ececb1bc9b5dd5c5a4623f0..dc831c3687d440b5c16e751684f3e89854ec7ed0 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2009, International Business Machines Corporation and
+ * Copyright (c) 1997-2013, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
@@ -27,9 +27,11 @@ public:
     void testRounding(/*char *par*/);
     void testRoundingInc(/*char *par*/);
     void TestCurrencyPluralInfo();
+    void TestScale();
 private:
     /*Helper functions */
     void verify(const UnicodeString& message, const UnicodeString& got, double expected);
+    void verifyString(const UnicodeString& message, const UnicodeString& got, UnicodeString& expected);
 };
 
 #endif /* #if !UCONFIG_NO_FORMATTING */