Proposal: Significant digits number formatting in ICU 3.0

Alan S Liu <[email protected]> Thu, 25 Mar 2004 13:51:15 -0800
Newsgroups gmane.comp.lib.icu.general
Message-ID <OFD7C927C1.46195EA0-ON88256E61.0065440A-88256E62.00780DB8@us.ibm.com>
Proposal: Significant digits number formatting in ICU 3.0
Affects: ICU4C, ICU4J

Documentation of proposed changes:

  DecimalFormat supports significant digits patterns.  Rather than
  specifying integer and fraction digit counts, these specify a
  minimum and maximum number of significant digits. These are
  indicated by the '@' and '#' characters. Each formatter object is in
  one of two modes, in this regard. Either (a) it uses significant
  digits, or (b) it uses the integer and fraction digit counts.

  In order to enable significant digits formatting, use a pattern
  containing the '@' pattern character. Alternatively, call
  setSignificantDigits(true).

  In order to disable significant digits formatting, use a pattern
  containing the '0' pattern character. Alternatively, call
  setSignificantDigits(false).

  If a pattern uses significant digits, it may not contain the '0'
  character, nor may it include a fraction element. Patterns such as
  '@00' or '@.###' are disallowed.

  The minimum number of significant digits is the number of '@'
  characters. The maximum number of significant digits is the number
  of '@' characters plus the number of '#' characters following on the
  right. For example, the pattern '@@@' indicates exactly 3
  significant digits. The pattern '@##' indicates from 1 to 3
  significant digits. Trailing zero digits are suppressed after the
  minimum number of significant digits have been shown. This is
  similar to the behavior of fraction digits.

  Any number of '#' characters may be prepended to the left of the
  leftmost '@' character. These have no effect on the minimum and
  maximum significant digits counts, but may be used to position
  grouping separators. For example, "#,#@#" indicates a minimum of one
  significant digits, a maximum of two significant digits, and a
  grouping size of three.

  The number of significant digits has no effect on parsing.

  Significant digits may be used together with exponential
  notation. Such patterns are equivalent to a normal exponential
  pattern with a minimum and maximum integer digit count of one, a
  minimum fraction digit count of getMinimumSignificantDigits() - 1,
  and a maximum fraction digit count of getMaximumSignificantDigits()
  - 1. For example, the pattern "@@###E0" is equivalent to "0.0###E0".

  Significant digit counts are stored as negative values in the
  integer digit count fields. Thus, if significant digits are used,
  then getMinimumIntegerDigits() and getMaximumIntegerDigits() will
  return negative numbers. The converse is also true. If significant
  digits are not being used, then getMinimumSignificantDigits() and
  getMaximumSignificantDigits() will return non-positive numbers.

  If significant digits are in use, then the fraction digit counts are
  ignored.

Proposed new @draft ICU 3.0 API:

  DecimalFormatSymbols (java):
    char getSignificantDigit();
    void setSignificantDigit(char);

  DecimalFormatSymbols (C++):
    kSignificantDigitSymbol

  unum.h (C):
    /* Significant digit symbol */
    UNUM_SIGNIFICANT_DIGIT_SYMBOL
    /** Minimum significant digits
     * @draft ICU 3.0 */
    UNUM_MIN_SIGNIFICANT_DIGITS
    /** Maximum significant digits
     * @draft ICU 3.0 */
    UNUM_MAX_SIGNIFICANT_DIGITS

  DecimalFormat (C++ and Java):
    /**
     * Returns the minimum number of significant digits that will be
     * displayed.
     * @return the fewest significant digits that will be shown, or a
     * non-positive value if significant digits are not in use
     * @draft ICU 3.0
     */
    int32_t getMinimumSignificantDigits() const;

    /**
     * Returns the maximum number of significant digits that will be
     * displayed.
     * @return the most significant digits that will be shown, or a
     * non-positive value if significant digits are not in use
     * @draft ICU 3.0
     */
    int32_t getMaximumSignificantDigits() const;

    /**
     * Sets the minimum number of significant digits that will be
     * displayed.  If <code>min</code> is less than one then it is set
     * to one.  If the maximum significant digits count is less than
     * <code>min</code>, then it is set to <code>min</code>.  If
     * significant digits were not in use before this call, then the
     * maximum significant digits count will be set to
     * <code>min</code>.
     * @param min the fewest significant digits to be shown 
     * @draft ICU 3.0
     */
    void setMinimumSignificantDigits(int32_t min);

    /**
     * Sets the maximum number of significant digits that will be
     * displayed.  If <code>max</code> is less than one then it is set
     * to one.  If the minimum significant digits count is greater
     * than <code>max</code>, then it is set to <code>max</code>.  If
     * significant digits were not in use before this call, then the
     * minimum significant digits count will be set to one.
     * @param max the most significant digits to be shown 
     * @draft ICU 3.0
     */
    void setMaximumSignificantDigits(int32_t max);

    /**
     * Returns true if significant digits are in use.
     * @draft ICU 3.0
     */
    UBool isSignificantDigits() const;

    /**
     * Sets whether significant digits are in use.
     * @draft ICU 3.0
     */
    void setSignificantDigits(UBool);

Notes:

  An earlier version of this design had no explicit API to set whether
  significant digits were in use or not. Instead, this was to be
  determined implicitly. If setMinimumSignificantDigits() or
  setMaximumSiginificantDigits() was called, then significant digits
  mode was turned on. If setMinimumIntegerDigits() or
  setMaximumIntegerDigits() was called, then significant digits was
  turned off.  With this setup, there was no way to tell what mode a
  formatter was in.  Also, this arrangement would like to code like
  this:

    fmt.setMinimumSignificantDigits(fmt.getMinimumSignificantDigits());

  just to turn significant digits on. It seems better to have an
  explicit API.

[Alan S Liu/San Jose/IBM@IBMUS; [email protected];; IBM Globalization; 
5600 Cottle Road; San Jose, CA 95193;; (408) 256-3155]