2

I am working on a small app to deposit and withdraw funds from a bank account. The program is running mostly fine, but I am getting strange output from some of the transactions with a lot of trailing decimals. I am randomly generating doubles that should only have 2 decimals, so I'm not sure where they are coming from.

C:\Users\Jon\Documents\Class\Java>java SavingsAccountTest
Balance: 62.0
Deposit Count: 0
Withdraw Count: 0
Annual Interest Rate: 0.09
Service Charges: 0.0
Active: false

        Withdraw first, then deposit using
        randomly generated amounts.

Balance: 62.0
Withrdaw:               Deposit:
8.76                    35.43

Your account is inactive due to: Insufficient Funds
***Unable to complete withdrawal.***

Balance: 97.43
Withrdaw:               Deposit:

16.83                   3.98


Balance: 84.58000000000001
Withrdaw:               Deposit:
99.44                   35.2

Your account is inactive due to: Insufficient Funds
***Unable to complete withdrawal.***

Press enter to continue.


C:\Users\Jon\Documents\Class\Java>

The issue is with the second transaction, beginning the third set of transactions with a balance of 84.58000000000001.

Here is the code for my main class.

import java.util.Random;
import java.util.Scanner;

public class SavingsAccountTest
{
    public static void main(String[] args)
    {
        Random rand = new Random();

        double[] depositArray = {(double)rand.nextInt(10001)/100, 
                                         (double)rand.nextInt(10001)/100,
                                         (double)rand.nextInt(10001)/100};

        double[] withdrawArray = {(double)rand.nextInt(10001)/100, 
                                          (double)rand.nextInt(10001)/100,
                                          (double)rand.nextInt(10001)/100};

        SavingsAccount account = new SavingsAccount((double)rand.nextInt(101), 
                                                (double)(rand.nextInt(10)+1)/100.0);

        System.out.print(account.toString());

        System.out.println("\n\n\tWithdraw first, then deposit using\n\trandomly generated amounts.");

        for (int i = 0; i < 3; i++)
        {   
            System.out.println("\nBalance: " + account.getBalance());
            System.out.print("Withrdaw:\t\tDeposit:\n" +
                                    withdrawArray[i] + "\t\t\t" + depositArray[i] + "\n\n");

            account.withdraw(withdrawArray[i]);
            account.deposit(depositArray[i]);
        }

        pause();
    }

    private static void pause()
    {       
        Scanner keyboard = new Scanner(System.in);

        System.out.print("\nPress enter to continue.");
        keyboard.nextLine();
        System.out.print("\n");
    }
}

Here are the deposit and withdraw methods from SavingsAccount

public void withdraw(double amount)
{
    if (this.active && amount <= super.balance)
        super.withdraw(amount);

    else
        System.out.print("Your account is inactive due to: " + 
                                "Insufficient Funds" + "\n***Unable to complete " +
                                "withdrawal.***\n");
}       

public void deposit(double amount)
{
    if (super.balance + amount >= 25.00)
    {
        this.active = true;
        super.deposit(amount);
    }

    else
        super.deposit(amount);
}

Here are the deposit and withdraw methods from the BankAccount super class:

public void withdraw(double withdraw)
{
    this.balance -= withdraw;
    withdrawCount++;
}

public void deposit(double deposit)
{
    this.balance += deposit;
    depositCount++;
}
The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
Jonathon Anderson
  • 1,162
  • 1
  • 8
  • 24
  • 4
    Floating point math in java is not exact. If you need truly exact values, hold the dollar and cents in separate int variables and do the formatting yourself. – azurefrog Apr 28 '14 at 17:03
  • 3
    [Welcome to the world of programming](http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). – Alexis C. Apr 28 '14 at 17:03
  • 1
    Or use System.out.printf("Balance: %2d", balance); which gives you a 2-decimal-place double – La-comadreja Apr 28 '14 at 17:04
  • An obvious naive solution would be to convert to the decimal to a String and drop anything 2 places after index of `.` – But I'm Not A Wrapper Class Apr 28 '14 at 17:05
  • I would personally use decimal formatting so that values will not only round to two places if it is too long, but it will concat the extra values on when there is only 1 decimal place. That way things like your 62.0 balance will be 62.00 – zgc7009 Apr 28 '14 at 17:10
  • Possible duplicate of http://stackoverflow.com/questions/1661273/floating-point-arithmetic-not-producing-exact-results – azurefrog Apr 28 '14 at 17:12
  • Thanks, I didn't realize it was a floating point issue. Looks like BigDecimal would give the most mathematically pure solution. In the interest of time and sticking within the scope of my coursework, I'll just adjust the output with the DecimalFormat class. – Jonathon Anderson Apr 28 '14 at 17:20

3 Answers3

0

This is because the value is stored in binary. 84.58 cannot be represented exactly in binary, but it can get close. Apparently the closest it can get is 84.58000000000001. To fix this, you can use format or printf to format the output..

The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
0

As stated by others, some values cannot be represented exactly in floating point. This guide has lots of details on this. When doing calculations for currency, an arbitrary precision type is better suited. Java has the BigDecimal type for this purpose. You will encounter errors in calculations at some point if you go with approaches that just format the output to use 2 decimal places.

Martin Serrano
  • 3,727
  • 1
  • 35
  • 48
  • Thanks. The whole arbitrary and floating point thing is a bit over my head at the moment and I'm not familiar with the BigDecimal class yet. Our assignment is meant to demonstrate our ability to extend abstract classes. – Jonathon Anderson Apr 28 '14 at 17:33
  • 1
    @NonSecwitter, no problem! If you are satisfied with an answer, you should accept and upvote one them. – Martin Serrano Apr 28 '14 at 17:43
  • I can't upvote... I had 16 rep points, but someone downvoted my question... Also, not sure what to do on selecting an answer if I used something that was suggested in a comment (DecimalFormat) – Jonathon Anderson Apr 28 '14 at 18:42
  • FWIW I would upvote both answers because they were both relevant and potentially helpful. – Jonathon Anderson Apr 28 '14 at 18:52
0

I suggest working in integer numbers of cents for the random number generation. java.util.Random has a method, nextInt(int n), that generates a number in the range (0,n].

You can either do the rest in integer cents, and only format with a ".", or convert to BigDecimal with scale 2.

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75