Decimal arithmetic
Copyright (c) IBM Corporation, 2000. All rights reserved. ©
11 Jan 2000
[contents | next]

Decimal arithmetic for Java

The JavaTM runtime environment includes a class (java.math.BigDecimal) for decimal arithmetic. While suitable for simple financial calculations, it is missing a number of features that are necessary for general-purpose decimal arithmetic. This document describes what is missing, and proposes a small and upwards compatible enhancement to the BigDecimal class which makes the necessary additions.

Included in this document are:

The requirements

Java currently provides classes (java.math.BigDecimal and java.math.BigInteger) for fixed point arithmetic, and also supports native integer and binary floating point arithmetic directly. Binary floating point is usually implemented by hardware, and therefore is widely used for 'numerically intensive' work where performance is critical.

However, with the growth in importance of applications where usability is the primary concern, the anomalies of binary floating point arithmetic (such as the inability to represent common values such as 0.10 exactly) are increasingly troublesome.[1]  In financial and commercial applications, especially, an arithmetic which can achieve exact decimal results when required is essential. This is the original purpose of the BigDecimal class.

Unfortunately, the current BigDecimal class provides only a limited set of fixed point operations on numbers which are in practice limited to those which can be represented conveniently as 'plain' numbers, with no exponent. There are, in addition, a number of problems with conversions to and from other Java types. These, and the other problems with the BigDecimal class, are listed overleaf.

Problems with the BigDecimal class:

  1. The fixed point (integer + scale) arithmetic is suitable for some tasks (such as calculating taxes or balancing a check book), but is inconvenient and awkward for many common applications.
    For example, calculating the total amount repaid on a mortgage over 20 years is difficult, requiring several steps which do not involve exact arithmetic and which may require explicit rounding. For this task (and many others) an arithmetic that allows working to a chosen precision is both simpler and more convenient.
  2. Several operators commonly used in applications are missing, specifically integer division, remainder, and exponentiation to an integer power (as required for straightforward calculation of the mortgage repayment just described, for example).
  3. The constructors for BigDecimal do not accept exponential notation. This means that results from other sources (for example, spreadsheets and calculators, or the Java Double.toString() method) are difficult to use.
  4. The string form of a BigDecimal is always a plain number. This means that very large or very small numbers are expressed using many digits -- this makes them expensive and difficult to handle. For many calculations an exponential or floating point representation is desirable (and is potentially more efficient).
  5. The conversions from BigDecimal to Java integer types are dangerous. Specifically, they are treated as a narrowing primitive conversion, even though there is a change of base involved. This means that decimal parts of numbers can be dropped without warning, and high order significant bits can also be lost without warning (an error sometimes called 'decapitation'). It was exactly this kind of error that caused the loss of the Ariane 5 launcher in 1996.[2] 

In the proposal that follows, these deficiencies are addressed by adding floating point arithmetic and exponential notation to the BigDecimal class, in a fully upwards-compatible and seamless manner. In addition, the set of base operators is completed, and new robust conversion methods are added.

The proposal

This proposal answers the primary requirements of the last section by adding support for decimal floating point arithmetic to the BigDecimal class. This is achieved by simply adding a second parameter to the existing operator methods. The augmented class implements the decimal arithmetic defined in the ANSI standard X3.274-1996,[3]  which has the following advantages:

This arithmetic has been further enhanced by supporting a variety of rounding algorithms, as already defined in Java 1.1 for the java.math.BigDecimal class.

A prototype of the proposed enhanced BigDecimal class has been specified (see the remainder of this document) and has been fully implemented, including javadoc comments following Java guidelines and an appropriate set of test cases.

It is a small class (at approximately 23,000 bytes, including line number tables, it is smaller than the BigInteger class in Java 1.2), and does not use any native methods. The class is based on code that has been in use since 1996, and which has been packaged as a BigDecimal class since June 1998. It has been available on the IBM alphaWorks site since late 1998.

For reasons explained later, the detail in this document also proposes adding one very small new context class to Java, in addition to enhancing the BigDecimal class. The new class would most logically be added to the java.math package in the Java Runtime Environment, and it is suggested that it be called MathContext.

The changes to the Java runtime proposed are summarized on the next page.

The changes to the current Java API affect only two classes; BigDecimal (which is enhanced from the current specification) and MathContext (which is new).

BigDecimal

Instantiates a decimal number, and includes:

  1. Constructors and methods for creating a BigDecimal number from the primitive Java types, and from strings and BigInteger object. Four constructors and one method have been added.
  2. Operator methods, for the usual arithmetic operators, including comparisons. Four new operators have been added, and all operator methods have a second version which specifies a context.
  3. Other methods, including standard Java methods (equals, hashCode, etc.), and conversions to primitive types and String (intValueExact, floatValue, toString, format, signum, etc.). Seven methods have been added, mostly to effect robust (error-detecting) conversions.
This initial proposal does not include transcendental functions.

MathContext

A very small class, used for defining a context for arithmetic, as described in the next section. This comprises four constructors and five methods (four 'get' methods and a toString() method).

These classes are available for testing in the package com.ibm.math (that is, as the classes com.ibm.math.BigDecimal and com.ibm.math.MathContext). Comments on them and on this draft are welcome. Please send comments to Mike Cowlishaw, mfc@speleotrove.com.

Acknowledgements

Very many people have contributed to the arithmetic described in this document, especially the IBM REXX language committee, the IBM Vienna Compiler group, and the X3 (now NCITS) J18 technical committee. Special thanks for their contributions to the current design are due to Joshua Bloch, Dirk Bosmans, and Brian Marks.
Footnotes:
[1] See, for example, Floating point issues, C. Sweeney, at:
http://www.truebasic.com/tech08.html
[2] See: http://www.esrin.esa.it/htdocs/tidc/Press/Press96/ariane5rep.html
[3] American National Standard for Information Technology -- Programming Language REXX, X3.274-1996, American National Standards Institute, New York, 1996.

[contents | next]