The new forums will be named Coin Return (based on the most recent vote)! You can check on the status and timeline of the transition to the new forums here.
The Guiding Principles and New Rules document is now in effect.

java... rounding error with mod operator?

Shazkar ShadowstormShazkar Shadowstorm Registered User regular
edited February 2007 in Help / Advice Forum
I'm a bit confused here. This is only the second java (or any) program that I've written. It's supposed to take the amount of money you input and give you the least amount of bills and coins to use with it. It works flawlessly for anything under $32. For some reason, after that, or at least as far as I've tested, I get 1 less penny than I should, or in the case of something ending with 5 cents, I get 4 pennies instead of a nickel. I'm not really sure what could be happening, but I can only attribute it to the mod operator.. perhaps? Any help would be nice.

Here is the code I have (name has been changed :P) :
//**************************************************
// LessBills.java
//		by &^&^%^&$%&(
//
// Determines the least amount of each coin and bill
// that can represent a given monetary amount
//**************************************************

import java.util.Scanner;

public class LessBills
{
	public static void main (String[] args)
	{
		double money;
		int tens, fives, ones, quarters, dimes, nickels, pennies, dollars, cents, extra;
			// 'extra' is a variable that will be used to store remainders.
		
		Scanner scan = new Scanner (System.in);
		
		System.out.print ("How much money do you have? $");
		money = scan.nextDouble();
		
		// Convert double 'money' into individual integers for 'dollars' and 'cents'.
		
		dollars = (int) money;
		cents = (int) ((money - dollars) * 100);
		
		// Get minimum number of bills, starting with tens and going to smaller bills.
		
		tens = dollars / 10;
		extra = dollars % 10;
		
		fives = extra / 5;
		extra = extra % 5;
		
		ones = extra;
		
		// Get the minimum number of coins, starting with quarters and going to smaller coins.
		
		quarters = cents / 25;
		extra = cents % 25;
		
		dimes = extra / 10;
		extra = extra % 10;
		
		nickels = extra / 5;
		extra = extra % 5;
		
		pennies = extra;
		
		// Print results.
		
		System.out.println ("These are the minimum amounts of bills and coins you can keep that money in:");
		System.out.println ("" + tens + " ten dollar bills. \n" + fives + " five dollar bills. \n" + ones + 
							" one dollar bills. \n" + quarters + " quarters. \n" + dimes + " dimes. \n" +
							nickels + " nickels. \n" + pennies + " pennies.");
		System.out.println ("Have a nice day.");
	}
}

poo
Shazkar Shadowstorm on

Posts

  • localh77localh77 Registered User regular
    edited February 2007
    This may not help much, but it looks fine. I doubt the mod stuff is causing a problem. You might want to try printing out dollars and cents after you set them to make sure they're getting set right.

    localh77 on
  • Bob SappBob Sapp Registered User regular
    edited February 2007
    I just ran through it with a debugger. This line:
    cents = (int) ((money - dollars) * 100);
    
    Gives one less cent that it should for values over $32 (I guess, I just tried something under 32 and something over). Not sure why. For example, a value of 35.80 gave me 79 cents...

    Bob Sapp on
    fizzatar.jpg
  • DrFrylockDrFrylock Registered User regular
    edited February 2007
    Bob Sapp wrote:
    I just ran through it with a debugger. This line:
    cents = (int) ((money - dollars) * 100);
    
    Gives one less cent that it should for values over $32 (I guess, I just tried something under 32 and something over). Not sure why. For example, a value of 35.80 gave me 79 cents...

    Doubles are notoriously horrible for representing currency values. Rounding errors and the like because binary can't super accurately represent certain floating point values. I'm thinking what's happening there is the results of the 'money' variable's representation (in the underlying binary) is 32.84999999999 instead of 32.85 or something and when you trunc it by casting to int it's just cutting off the 9999s. You could java.util.Math.round() it...

    DrFrylock on
  • taerictaeric Registered User, ClubPA regular
    edited February 2007
    I'll second that the problem is in using a double. Instead, you should split it up into two int variables, on for dollars and one for cents.

    taeric on
  • Bob SappBob Sapp Registered User regular
    edited February 2007
    DrFrylock wrote:
    Bob Sapp wrote:
    I just ran through it with a debugger. This line:
    cents = (int) ((money - dollars) * 100);
    
    Gives one less cent that it should for values over $32 (I guess, I just tried something under 32 and something over). Not sure why. For example, a value of 35.80 gave me 79 cents...

    Doubles are notoriously horrible for representing currency values. Rounding errors and the like because binary can't super accurately represent certain floating point values. I'm thinking what's happening there is the results of the 'money' variable's representation (in the underlying binary) is 32.84999999999 instead of 32.85 or something and when you trunc it by casting to int it's just cutting off the 9999s. You could java.util.Math.round() it...
    Yeah, looking into Java's floating point representation scheme, you're dead on. 35.8 isn't represented perfectly in binary and thus you get an answer "close" but not accurate.

    OP, is this for class or your own learning? If it's for class you might want to ask the teacher how you should procede. If this is for yourself, go with the Math.round() route.

    Bob Sapp on
    fizzatar.jpg
  • mspencermspencer PAX [ENFORCER] Council Bluffs, IARegistered User regular
    edited February 2007
    You could also consider adding 0.005 to each value before you MOD it. So instead of:
    cents = (int) ((money - dollars) * 100);
    
    use this:
    cents = (int) ((money - dollars + 0.005) * 100);
    
    or this:
    cents = (int) ((money - dollars) * 100 + 0.5);
    

    mspencer on
    MEMBER OF THE PARANOIA GM GUILD
    XBL Michael Spencer || Wii 6007 6812 1605 7315 || PSN MichaelSpencerJr || Steam Michael_Spencer || Ham NOØK
    QRZ || My last known GPS coordinates: FindU or APRS.fi (Car antenna feed line busted -- no ham radio for me X__X )
  • NerissaNerissa Registered User regular
    edited February 2007
    Is your breaking point 32.76 by chance?

    I don't know java data types, but it's sounding like double must be a 16-bit representation with a range of +/- 32767 (with the decimal point somewhere in there)

    You might try using an integer for money, and asking the user to enter it without a decimal point (i.e. in cents), or using a string, breaking it at the decimal, and finding the values of each part to get your original dollars and cents values.

    Nerissa on
  • ProtoProto Registered User regular
    edited February 2007
    as has been said, doubles/floats are horrible for monitary amounts.


    import java.math.BigDecimal should work.

    http://java.sun.com/j2se/1.4.2/docs/api/java/math/BigDecimal.html

    Proto on
    and her knees up on the glove compartment
    took out her barrettes and her hair spilled out like rootbeer
  • ClipseClipse Registered User regular
    edited February 2007
    import java.math.BigDecimal should work.

    Unless one is working with huge amounts of money or fractions of pennies, there's no need to use something like this. It suffices to store the amount of money as an int representing the number of cents. For instance, $12.77 gets stored as the int 1277.

    Clipse on
  • Shazkar ShadowstormShazkar Shadowstorm Registered User regular
    edited February 2007
    It's for class and the problem said to use a double as an input type... but to whoever suggested adding a small decimal number so that when it truncated I was a-ok.. thanks, it worked. Whee. Programming is cool.

    Shazkar Shadowstorm on
    poo
  • Jimmy KingJimmy King Registered User regular
    edited February 2007
    Even though you've got a work around, I would still ask your teacher about it. This is both to ensure that you are not going to get marked down because the teacher doesn't like your work around and so that the teacher will (hopefully) fix the assignment in the future and/or be more precise on what they want you to do ie. specifically say "using a double here is going to cause a bug, I want you to find a way to work around it", since what was done here was imo either unfair based on how low level of a class this is or just piss poor teaching which I see all too much of.

    Depending on your relationship with the teacher and their attitude I would even show them this page on sun's website that specifically says not to use Double for currency.

    Jimmy King on
Sign In or Register to comment.