BigDecimal


The class java.math.BigDecimal allows you to do arbitrary-precision decimal (base 10) floating-point arithmetic. This means that arithmetic with BigDecimal works like you learned in grade school. The BigDecimal class provides a comprehensive set of arithmetic methods and extensive control over rounding. A BigDecimal object represents a decimal number of arbitrary precision, meaning that you decide the number of significant digits it will contain. It is immutableyou cannot change the number that a BigDecimal stores.

The most frequent use of BigDecimal is in financial applications. Financial applications often require you to accurately account for money down to the last hundredth of a cent or even at more granular levels.

Floating-point numbers, as implemented by the Java primitive types float and double, do not allow every number to be represented exactly as specified. This is because it is not mathematically possible to represent certain decimal numbers (such as 0.1) using binary.[1] BigDecimal can exactly represent every number.

[1] See http://www.alphaworks.ibm.com/aw.nsf/FAQs/bigdecimal.

There are two major downsides to using BigDecimal. First, hardware normally optimizes binary floating-point operations, but BigDecimal's decimal floating point is implemented in software. You may experience poor performance when doing extremely heavy math calculations with BigDecimal.

Second, there is no mathematical operator support for BigDecimal. You must execute common operations such as addition and multiplication via method calls. The requisite code is wordy and thus tedious to write and read.

Using BigDecimal

The student information system must maintain an account of charges and credits for each student. The first test demonstrates the ability of an Account to track a balance based on applied charges and credits.


 package sis.studentinfo; import java.math.BigDecimal; import junit.framework.*; public class AccountTest extends TestCase {    public void testTransactions() {       Account account = new Account();       account.credit(new BigDecimal("0.10"));       account.credit(new BigDecimal("11.00"));       assertEquals(new BigDecimal("11.10"), account.getBalance());    } } 

The preferred way to construct a new BigDecimal is to pass a String to its constructor. The String contains the value you want the BigDecimal to represent. You could also pass a double, but it may not precisely represent the number you expect, due to the nature of floating-point representation in Java.[2] As a result, the BigDecimal may not precisely represent the number you expect.

[2] See the Java Glossary entry at http://mindprod.com/jgloss/floatingpoint.html for a discussion of floating-point representation.

You may also construct BigDecimal objects from other BigDecimal objects. This allows you to directly use an expression returning a BigDecimal as the constructor parameter.

The Account implementation:

 package sis.studentinfo; import java.math.BigDecimal; public class Account {    private BigDecimal balance = new BigDecimal("0.00");    public void credit(BigDecimal amount) {       balance = balance.add(amount);    }    public BigDecimal getBalance() {       return balance;    } } 

BigDecimal objects are immutable. Sending an add message to a BigDecimal does not alter it. Instead, the add method takes the argument's value and adds it to the value the BigDecimal stores. The add method then creates and returns a new BigDecimal object with this sum. In the Account implementation, the result of sending the add message to balance is a new BigDecimal object. You must reassign this new object to balance in order to maintain the total.

BigDecimal provides a full complement of methods to represent arithmetic operations. They include abs, add, divide, max, min, multiply, negate, and subtract. Additional methods help you to manage scaling and to extract values as different types from a BigDecimal.

Scale

In testTransactions, the assertion expects the result to be a BigDecimal with value "11.10"with two places after the decimal point. In contrast, you would expect the result of an equivalent Java float or double operation to be "11.1". Adding such an assertion:

 assertEquals(new BigDecimal("11.1"), account.getBalance()); 

fails the test.

The number of digits in the fractional part represents the scale of the number. When one does arithmetic operations on BigDecimal numbers, the result is a new BigDecimal whose scale is the larger between the receiving BigDecimal and the parameter BigDecimal. For example:

 assertEquals(new BigDecimal("5.300"),    new BigDecimal("5.000").add(new BigDecimal("0.3"))); 

That is, the scale as the result of adding a 1-scale number to a 3-scale number is 3.

Division and Rounding

When dividing numbers, the result often contains a larger number of fractional digits than either the divisor or the dividend. By default, BigDecimal does not expand the scale of the result to this larger amount; instead, it restricts it to the larger of the dividend and divisor scales. You can also explicitly define a new scale for the result.

Constraining the scale means that Java may need to round the result of a division operation. Java provides eight different rounding modes. You are probably most familiar with the rounding mode that corresponds to BigDecimal.ROUND_HALF_UP. This mode tells BigDecimal to round the result up if the distance toward the nearest neighbor is greater than or equal to 0.5, and to round it down otherwise. For example, 5.935 would round up to the 2-scale number 5.94, and 5.934 would round down to 5.93.


For an account, you must be able to capture the average transaction amount. A test demonstrates this need:

 public void testTransactionAverage() {   Account account = new Account();   account.credit(new BigDecimal("0.10"));   account.credit(new BigDecimal("11.00"));   account.credit(new BigDecimal("2.99"));   assertEquals(new BigDecimal("4.70"), account.transactionAverage()); } 

The modified Account class:

 package sis.studentinfo; import java.math.BigDecimal; public class Account {    private BigDecimal balance = new BigDecimal("0.00");    private int transactionCount = 0;    public void credit(BigDecimal amount) {       balance = balance.add(amount);       transactionCount++;    }    public BigDecimal getBalance() {       return balance;    }    public BigDecimal transactionAverage() {       return balance.divide(          new BigDecimal(transactionCount), BigDecimal.ROUND_HALF_UP);    } } 

Review the Java API documentation for details on the other seven rounding modes.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net