My idea is to have a Money value object (immutable), that would carry a double value and a Currency object. This class would have a default currency configured on a money.properties file (or some other config file). That is, in my opinion, a system should have a default currency to apply money calculations.
Then my first dilemma: how to and where to do the monetary calculations? Think about sum, subtract, applyTaxes and applyDiscount methods. They should be on the Money class itself, or on some other class? If in the Money class, it should not allow one to add Dollars and Brazilian Reais without some sort of conversion.
But my idea is have these operations on the Money object AND have them on a MonetaryCalculator object too. The difference is that the calculator would have a target currency that is the currency of the Money object returned by the result() method, and this calculator would convert automatically any Money object that had its Currency different from the target Currency before calculating.
For conversions, this MonetaryCalculator would use a CurrencyConverter, that is a class that returns a Money object that is the same amount of money of other Money object but has the currency (and value) converted. This CurrencyConverter would in turn use a CurrencyRateProvider object to get the currency rates used on conversion.
CurrencyRateProvider is a Interface that has a single method defined: getRate(Currency given, Currency target). The clients of this Monetary API should implement this interface so they get the rates of anywhere they want.
Then my second dilemma: how to actually implement these monetary calculations, since double (or float) does not give me the right precision? My first though was to do all the calculation using double primitive and do a rounding when showing a Money objects value is requested, actually having a internal value with all the precision of the double and a external value that is Math.round(amount * 100d) / 100d. Its not so bad but its too inflexible to fit most systems designs, my primary objective.
A way is to use BigDecimal but it seems damn slow to my (and others probably) needs. Another way was to define other Interface that has the methods responsible for the sum, subtract, divide and multiply operations, and have the APIs client to implement them, so the client would choose the right precision. The API will have about 5 implementations of this Interface. Then Money and MonetaryCalculator objects and would delegate the primary operations to the client class. This class would be fixed to Money objects and initiated on the Moneys constructor. Ill have to think how to do this (maybe yet another line on the money.properties config file, that would tell what class to use).
A MoneyFormatter class would be responsible for localized and configurable String representations of the money (precision, currency symbols, etc).
Please tell me your opinions about these ideas, and if its a good idea to implement it as a OpenSource project. Thanks a lot!
-
Monetary Calculation Pattern (38 messages)
- Posted by: Bengt Hammarlund
- Posted on: August 14 2004 01:10 EDT
Threaded Messages (38)
- Monetary Calculation Pattern by henry voyer on August 17 2004 11:09 EDT
- Monetary Calculation Pattern - Framework by Jason - on August 30 2004 17:21 EDT
- BigDecimal has rounding errors by Guillermo Schwarz on August 30 2004 23:10 EDT
-
BigDecimal has rounding errors by Rick DeBay on November 04 2004 04:20 EST
-
Re : Framework by Narendra Lilaramani on November 29 2004 07:32 EST
- Additional link about Money by cmartraire cmartraire on January 14 2005 05:48 EST
-
Re : Framework by Narendra Lilaramani on November 29 2004 07:32 EST
- BigDecimal has rounding errors by Neil Laurance on August 31 2005 05:11 EDT
- BigDecimal hasn't any rounding errors :) by Elijah Epifanov on September 02 2005 02:00 EDT
-
BigDecimal has rounding errors by Rick DeBay on November 04 2004 04:20 EST
- Monetary Calculation Pattern by Rishi Shankar Rengasamy on October 14 2004 08:16 EDT
- Interesting idea. by Neil Roy on August 17 2004 11:36 EDT
- Monetary Calculation Pattern by Tomas Karlsson on August 17 2004 15:12 EDT
- Monetary Calculation Pattern by henry voyer on August 19 2004 08:18 EDT
- Found this ! by henry voyer on August 19 2004 11:09 EDT
- Double? by David Bates on August 22 2004 07:18 EDT
- Monetary Calculation Pattern by Alan Borsato on August 31 2004 14:17 EDT
- Why not use integer arithmetic then by Guillermo Schwarz on September 02 2004 14:58 EDT
-
Why not use integer arithmetic then by Alan Borsato on September 03 2004 02:34 EDT
-
BigDecimal is not accurate enough (Was: Why not use integer ...) by Guillermo Schwarz on September 07 2004 10:10 EDT
- Don't instantiate the BigDecimal with a double by James Watson on October 05 2004 11:24 EDT
-
Infinte precision? by James Watson on October 05 2004 11:27 EDT
-
Infinte precision? Why not? by Guillermo Schwarz on October 06 2004 02:54 EDT
-
Infinte precision? Why not? by James Watson on October 07 2004 11:03 EDT
-
Infinte precision? Why not? by James Watson on October 07 2004 11:05 EDT
-
Infinte precision? Why not? by Guillermo Schwarz on October 12 2004 10:33 EDT
-
Infinte precision? Why not? by James Watson on October 12 2004 12:28 EDT
-
Accurate by Guillermo Schwarz on October 29 2004 10:39 EDT
- re: Accurate by James Watson on November 01 2004 09:51 EST
-
re: Accurate by James Watson on November 01 2004 10:30 EST
-
re: Accurate by Guillermo Schwarz on June 13 2005 12:53 EDT
- re: Accurate by James Watson on July 07 2005 05:45 EDT
-
re: Accurate by James Watson on July 07 2005 05:49 EDT
- re: Accurate by william c on August 27 2005 06:51 EDT
-
re: Accurate by Guillermo Schwarz on June 13 2005 12:53 EDT
-
Accurate by Guillermo Schwarz on October 29 2004 10:39 EDT
-
Infinte precision? Why not? by James Watson on October 12 2004 12:28 EDT
-
Infinte precision? Why not? by Guillermo Schwarz on October 12 2004 10:33 EDT
- Infinte precision? Why not? by James Watson on October 12 2004 12:31 EDT
-
Infinte precision? Why not? by James Watson on October 07 2004 11:05 EDT
-
Infinte precision? Why not? by James Watson on October 07 2004 11:03 EDT
-
Infinte precision? Why not? by Guillermo Schwarz on October 06 2004 02:54 EDT
-
BigDecimal is not accurate enough (Was: Why not use integer ...) by Guillermo Schwarz on September 07 2004 10:10 EDT
-
Why not use integer arithmetic then by Alan Borsato on September 03 2004 02:34 EDT
- Why not use integer arithmetic then by Guillermo Schwarz on September 02 2004 14:58 EDT
- Monetary Calculation Pattern by Risto Solman on October 19 2004 17:43 EDT
- Create a brand new fixed point datatype by Fernando Santucci on November 17 2004 11:04 EST
- Open-Source monetary package. by Jean-Marie Dautelle on February 05 2005 21:38 EST
- Don't take too much by Elijah Epifanov on September 02 2005 02:09 EDT
- Monetray Calculaiton Pattern by Robert Sachtjen on February 16 2006 17:00 EST
-
Monetary Calculation Pattern[ Go to top ]
- Posted by: henry voyer
- Posted on: August 17 2004 11:09 EDT
- in response to Bengt Hammarlund
Hi.
You can start by using BigDecimal inside the money object for all calculations.
Of course you have to add the currency concept to it.
This is something that the community needs. if you start an open source project i would love to contribute to it.
Regards
henry v. -
Monetary Calculation Pattern - Framework[ Go to top ]
- Posted by: Jason -
- Posted on: August 30 2004 17:21 EDT
- in response to henry voyer
Firstly, as someone who programs for a major financial institution, I can assure you that doubles are not sufficient in all cases, and that using them will denote your solution as naively charming. Specifically, when one is trying to work with things like, say, accounting cost percentages for deferred fees on 10 million dollar notional balances, the math reaches out beyond sixteen decimal places of precision and can most definately led to rounding errors and discrepancies that can shave not merely pennies, but dollars. Doubles and financial calculations simply do not mix - it is hard to overstress this point. An entry-class Monetary object and library must offer support for BigDecimals.
For example, in Java the following code does nothing!
float f = 1E8f; f += 1;
What you may wish to consider is a fullblown customizable framework, similiar to frameworks and libraries for mathematical matrices operations, wherein specification of the underlying data structures and algorythmns is configurable by the callers and users of said library, in this case, specification of doubles vs. BigDecimals.
In a likewise vein, an enterprise (e.g. non-hobbyist) solution would likely need better support for rate changes (if only to help support what financial people call payment schedule roll-offs). Foreign currency exchange swaps, for example, often do not have one true fixed currency rate - on any given day of the month upon which a forecast or a roll-off schedule needs to be generated, the rate may be shifting. A solution which can be configured to use and-or tracking multiple rates in time, or an evolving rate, becomes an essential solution feature. (pushing this off on the caller is...suboptimal...callers are looking to your library to help them manage precisely this kind of Money / Exchange Rate complexity)
I believe as you consider your problem space more deeply, you will discover that what you are envisioning needs to essentially evolve into a configurable framework library - a library with a variety of configuration constraints and parameters, and a variety of support for variations in the usage of monetary objects.
You will also find that serveral very good references exist in the literature addressing various aspects of this problem. See, for example, Generative Programming by Czarnecki and Eisenecker. Or google various jdk discussion boards for threads on aspects of the Money class, and it's lack in java. The Standard Template Library (STL) of C/C++ may also prove to be an eye-opener, in it's framing and solution of the configurable libraries thoughtspace.
I have evaluated several attempts at Money objects in the past, incidentally, although the links are not handy at the moment. (I came across this board doing a periodic re-search of what may have evolved out there.) You are biting off a much more complicated problem that you may expect, although I strongly encourage you to plunge in and give it a try. (We eventually rolled our own, our needs here were quite high end and somewhat complexly atypical. Regrettably, I am not able to open source our solution, nor is it very generic.)
Best wishes with your efforts. A truly robust solution is clearly lacking and needed. -
BigDecimal has rounding errors[ Go to top ]
- Posted by: Guillermo Schwarz
- Posted on: August 30 2004 23:10 EDT
- in response to henry voyer
Consider the following piece of code:
System.out.println( "*** Using BigDecimal" );
BigDecimal z = new BigDecimal( 0.1 );
System.out.println( "0.1 = " + z );
BigDecimal z2 = z.add( z );
BigDecimal z4 = z2.add( z2 );
BigDecimal z8 = z4.add( z4 );
BigDecimal z10 = z8.add( z2 );
System.out.println( "0.1 + 0.1 = " + z2 );
System.out.println( "0.1 +...+ 0.1 = " + z10 );
System.out.println( "10 * 0.1 = " + z.multiply( new BigDecimal( 10 ) ) );
System.out.println( "*** Using Fraction" );
Fraction q = new Fraction( 1, 10 );
System.out.println( "0.1 = " + q );
Fraction q2 = q.add( q );
Fraction q4 = q2.add( q2 );
Fraction q8 = q4.add( q4 );
Fraction q10 = q8.add( q2 );
System.out.println( "0.1 + 0.1 = " + q2 );
System.out.println( "0.1 +...+ 0.1 = " + q10 );
System.out.println( "10 * 0.1 = " + q.multiply( new Fraction( 10, 1 ) ) );
Output:
*** Using BigDecimal
0.1 = 0.1000000000000000055511151231257827021181583404541015625
0.1 + 0.1 = 0.2000000000000000111022302462515654042363166809082031250
0.1 +...+ 0.1 = 1.0000000000000000555111512312578270211815834045410156250
10 * 0.1 = 1.0000000000000000555111512312578270211815834045410156250
*** Using Fraction
0.1 = 0.1
0.1 + 0.1 = 0.2
0.1 +...+ 0.1 = 1
10 * 0.1 = 1
Fraction is a very simple class that solves that specific problem. Fraction has overflow limits and BigFraction doesn't because it is implemented on top of BigInteger.
You can download both from: http://sourceforge.net/projects/securecollect/
You may use it as needed in developing your Currency class. Please don't forget to share, if possible, your solution with us.
Cheers,
gfgschwarz at yahoo dot com -
BigDecimal has rounding errors[ Go to top ]
- Posted by: Rick DeBay
- Posted on: November 04 2004 16:20 EST
- in response to Guillermo Schwarz
Your initial constructor was flawed. It should have been:
BigDecimal z = new BigDecimal("0.1");
See http://java.sun.com/j2se/1.4.2/docs/api/java/math/BigDecimal.html#BigDecimal(double) -
Re : Framework[ Go to top ]
- Posted by: Narendra Lilaramani
- Posted on: November 29 2004 07:32 EST
- in response to Rick DeBay
What I think from this thread is:
Money should have a Currency and a value. The value part should be a valid value which can be represented using the correct Currency denominations. So, Currency will have three important attributes: code, fractionDigits and collection of denominations.If a value which can't be expressed using the denominations is not a valid Money value for the given currency at any point.
So, it should not be possible to have a valid Money representing 0.3333 as a value. Adding two money objects with USD as a currency will always return a valid result. So, additions and subtraction of valid money object will never give a problem.
The problem comes when we convert one currency to another using a rate like 1.23456789. At this point we are merely dealing with numbers and it does not matter if it is double or decimal. you CAN NOT have a situation where one part of an equation is money and another part is just a number. As soon as this occurs we may have to convert our Money to Number first. For this situation we can have an Exchange Rate Calculator based on various currency legs and to be more flexible rounding for each rate. You can start with HALF ROUND UP by default for all exchange Rates. This requires "Exchange Rate" to be considered as an object having Cur1, Cur2, RateValue, roundingMethod as attributes. So the Calculator will take sourceMoney,destCurrency as inputs locate a correct ExchangeRate object and convert it to destinationMoney.
The other part discussed here is to distribute values evenly when we have more than one conversion. ie, distribute x dollar to y no. of accounts without losing value. For example I have 1023 USD in bank. Now I want to distribute 22.45% to one account, 33.41% to another and 44.14% in the third account. If I take this one by one with exisitng Money object you get 229.66 USD, 341.78 USD, 451.55 USD = 1022.99 USD and will lose one penny. I do not think Money object should address these kind of problems. A Monetory calculator can have methods doing this, but in financial domains these calculators always return rounding errors with the Result and its up to the client to deal with rounding errors. -
Additional link about Money[ Go to top ]
- Posted by: cmartraire cmartraire
- Posted on: January 14 2005 05:48 EST
- in response to Narendra Lilaramani
Hi,
You should take a look at Martin Fowler analysis patterns, especially the pattern Quantity and its Money application at
http://martinfowler.com/ap2/quantity.html, also related to Converter and MoneyBag to handle the rounding or impossible division issues... -
BigDecimal has rounding errors[ Go to top ]
- Posted by: Neil Laurance
- Posted on: August 31 2005 17:11 EDT
- in response to Guillermo Schwarz
Consider the following piece of code: System.out.println( "*** Using BigDecimal" ); BigDecimal z = new BigDecimal( 0.1 ); System.out.println( "0.1 = " + z ); BigDecimal z2 = z.add( z ); BigDecimal z4 = z2.add( z2 ); BigDecimal z8 = z4.add( z4 ); BigDecimal z10 = z8.add( z2 ); System.out.println( "0.1 + 0.1 = " + z2 ); System.out.println( "0.1 +...+ 0.1 = " + z10 ); System.out.println( "10 * 0.1 = " + z.multiply( new BigDecimal( 10 ) ) ); System.out.println( "*** Using Fraction" ); Fraction q = new Fraction( 1, 10 ); System.out.println( "0.1 = " + q ); Fraction q2 = q.add( q ); Fraction q4 = q2.add( q2 ); Fraction q8 = q4.add( q4 ); Fraction q10 = q8.add( q2 ); System.out.println( "0.1 + 0.1 = " + q2 ); System.out.println( "0.1 +...+ 0.1 = " + q10 ); System.out.println( "10 * 0.1 = " + q.multiply( new Fraction( 10, 1 ) ) );Output:*** Using BigDecimal0.1 = 0.10000000000000000555111512312578270211815834045410156250.1 + 0.1 = 0.20000000000000001110223024625156540423631668090820312500.1 +...+ 0.1 = 1.000000000000000055511151231257827021181583404541015625010 * 0.1 = 1.0000000000000000555111512312578270211815834045410156250*** Using Fraction0.1 = 0.10.1 + 0.1 = 0.20.1 +...+ 0.1 = 110 * 0.1 = 1Fraction is a very simple class that solves that specific problem. Fraction has overflow limits and BigFraction doesn't because it is implemented on top of BigInteger.You can download both from: http://sourceforge.net/projects/securecollect/You may use it as needed in developing your Currency class. Please don't forget to share, if possible, your solution with us.Cheers,gfgschwarz at yahoo dot com
Rather than BigDecimal z = new BigDecimal(0.1)
Use BigDecimal z = new BigDecimal("0.1")
Then the following produces the correct answer:
BigDecimal b1 = new BigDecimal("0.1");
BigDecimal b2 = b1.add(b1);
BigDecimal b3 = b2.add(b2);
BigDecimal b4 = b3.add(b3);
BigDecimal b5 = b4.add(b2);
System.out.println(b5);
Cheers, Neil -
BigDecimal hasn't any rounding errors :)[ Go to top ]
- Posted by: Elijah Epifanov
- Posted on: September 02 2005 02:00 EDT
- in response to Guillermo Schwarz
You say that following code incurs rounding error?
BigDecimal z = new BigDecimal( 0.1 );
System.out.println( "0.1 = " + z );
Try this:
BigDecimal z = new BigDecimal("0.1");
System.out.println( "0.1 = " + z );
This could help ;) -
Monetary Calculation Pattern[ Go to top ]
- Posted by: Rishi Shankar Rengasamy
- Posted on: October 14 2004 08:16 EDT
- in response to henry voyer
Hi
Instead of a double a BigDecimal would be better.
I have worked on this and have implemented a great deal abt the monetary pattern u r talking abt.
I also have a curreny rate maintaince utility which will maintain the buy rate and sell rate of a particualar currency against a currency.
Would like to participate and contribute a lot in case u r coming up with some open source project.
Thanxs
Rishi -
Interesting idea.[ Go to top ]
- Posted by: Neil Roy
- Posted on: August 17 2004 11:36 EDT
- in response to Bengt Hammarlund
This is a good idea for the projects out there that use multiple currencies. Here is an easy way to add double values without losing precision:
double x = 25.29;
double y = 104.34;
double total;
long totalLg;
long xLg = Math.round(x* 100);
long yLg = Math.round(y* 100);
totalLg = xLg + yLg;
total = totalLg/100d;
Of course you could do this on one line, but I just did this for clarity's sake :). -
Monetary Calculation Pattern[ Go to top ]
- Posted by: Tomas Karlsson
- Posted on: August 17 2004 15:12 EDT
- in response to Bengt Hammarlund
Hi!
Great idea to do this once as an open source project. Maybe something that can be included in the Java standard in the future? Or is some business extension?
I have some comments:
- As Henry already has said, the Currency concept must be added to the design.
- Then you also need some persistent storage for all available currencies.
- You must handle active (possible to use now) and passive (impossible to use not, but can still exist) currencies. For example, when Sweden will change from Swedish kronor (SEK) to Euros around year 2020 or so (internal Swedish joke!), you will still be able to handle old records in the old currency although you should not be able to select it for new Money objects.
The Currency stuff can be handled with a CurrencyFactory interface with factory methods (and possible a cache since data is not expected to change that often). Implementations can be done for:
- Some predefined database table using JDBC.
- Properties file.
- XML file.
Other implementations have to be written to legacy system or new business systems. For example towards existing tables in Oracle eBS or SAP. I have written such factories with cach in one project. It worked fine, and I can do it again.
/Tomas -
Monetary Calculation Pattern[ Go to top ]
- Posted by: henry voyer
- Posted on: August 19 2004 08:18 EDT
- in response to Bengt Hammarlund
So the steps could be the following.
- Design an API (Conceptual model, diagram classes, etc)
This should take in considerations implementations for accessing currencys,
storing data, etc.
- Follow up the design with some algorithms. Do a discussion about the pro and cons of using different calculation methods. Ex. BigDecimal ? primitives calc, etc.
- Distribute the task among open source programmers
- Do some different implementations on acessing the data. Prevayler etc etc.
Any comment ? -
Found this ![ Go to top ]
- Posted by: henry voyer
- Posted on: August 19 2004 11:09 EDT
- in response to Bengt Hammarlund
http://sourceforge.net/projects/timeandmoney
Still they dont offer conversion. But is better than nothing. -
Double?[ Go to top ]
- Posted by: David Bates
- Posted on: August 22 2004 07:18 EDT
- in response to Bengt Hammarlund
I agree with the post suggesting that you at least start with using BigDecimal for the internal representation - this is an implementation detail - encapsulation means that you should be able to change the internal implementation later without an impact to the outside world.
Later, why not just hold the internal value in an int? This int would hold the smallest unit of the currency. For example, 525 would represent $5.50 or £5.50 depending upon currency type.
The currency type itself should probably be indicated by a java.util.Currency reference. -
Monetary Calculation Pattern[ Go to top ]
- Posted by: Alan Borsato
- Posted on: August 31 2004 14:17 EDT
- in response to Bengt Hammarlund
I use a simple RPN (Reverse Polish Notation) calculator object. The calculator can be configured to round, truncate, and other capabilities.
My simple test case:
/**
* Calcula (30+40)x100/(20+5) = 280
*/
public void testCalculoComplexo() {
CalculadoraRPN calc = new CalculadoraRPN();
calc.push(new BigDecimal("30"));
calc.add(new BigDecimal("40"));
calc.multiply(new BigDecimal("100"));
calc.push(new BigDecimal("20"));
calc.add(new BigDecimal("5"));
calc.divide();
assertEquals(new BigDecimal("280.00"), calc.pop());
} -
Why not use integer arithmetic then[ Go to top ]
- Posted by: Guillermo Schwarz
- Posted on: September 02 2004 14:58 EDT
- in response to Alan Borsato
You code snippet:
calc.push(new BigDecimal("30"));
calc.add(new BigDecimal("40"));
calc.multiply(new BigDecimal("100"));
calc.push(new BigDecimal("20"));
calc.add(new BigDecimal("5"));
Uses only integer arithmetic. That has already been successfully solved by BigInteger, with no possibility of overflow. Why use BigDecimal 0.1 can't be represented acurately? -
Why not use integer arithmetic then[ Go to top ]
- Posted by: Alan Borsato
- Posted on: September 03 2004 14:34 EDT
- in response to Guillermo Schwarz
The point is:
You can delegate the knowledge for truncating and etc to another class
We know that there are problems with monetary calculation and we shoudnt be a jvm expert. So, we could move this responsibility to someone else.
calc.push(new BigDecimal("0.10"));
calc.push(new BigDecimal("0.10"));
calc.divide(); // assert a 0.20 result
we know that divide (double / double) is faulty, and the BigDecimal sintax for calculations is really verbose:
BigDecimal value = new BigDecimal("0.10").divide(new BigDecimal("0.10"));
well, this code doesnt seem that verbose, but try a realy complex average...
What do you think???? -
BigDecimal is not accurate enough (Was: Why not use integer ...)[ Go to top ]
- Posted by: Guillermo Schwarz
- Posted on: September 07 2004 10:10 EDT
- in response to Alan Borsato
The problem with BigDecimal is that BigDecimal( 0.1 ) is not really 0.1.
This has to do with the fact that using floating point arithmetic, 0.1 becomes an irrational number in binary, meaning that you need an infite series of digits to represent it, something that common hardware is not willing to implement at reasonable time and space constraints.
Using Fractions is as cumbersome as using BigDecimal, but with the added benefit that it has no precision problems as long as you are doing the 4 basic operations: +, -, * and /. When you want to obtain a root, then you need an approximation, but for most Money calculations applying roots is not required. -
Don't instantiate the BigDecimal with a double[ Go to top ]
- Posted by: James Watson
- Posted on: October 05 2004 23:24 EDT
- in response to Guillermo Schwarz
The problem with BigDecimal is that BigDecimal( 0.1 ) is not really 0.1.
You must use the String constructor of BigDecimal to get a true representation of 0.1. If you do so, floating point represtations do not come into play. If you use the double constructor, the floating point representation must be used because, well, you are using a double. Cut double out of the equation and BigDecimal is just fine for monetary calculations.
Not that BigDecimal is perfect. It has an extremely arcane API. -
Infinte precision?[ Go to top ]
- Posted by: James Watson
- Posted on: October 05 2004 23:27 EDT
- in response to Guillermo Schwarz
0.1 becomes an irrational number in binary, meaning that you need an infite series of digits to represent it, something that common hardware is not willing to implement at reasonable time and space constraints.
Is there any hardware that supports infinte precision? By time and space constraints do you mean in a cosmological sense? -
Infinte precision? Why not?[ Go to top ]
- Posted by: Guillermo Schwarz
- Posted on: October 06 2004 14:54 EDT
- in response to James Watson
Is there any hardware that supports infinte precision? By time and space constraints do you mean in a cosmological sense?
Let me explain with an example: You need PI, but there is no way to calculate it entirely to the last digit, but whenever you print it, you want to print exact substrings of PI.
No problem! You can always calculate what you are about to print, exactly up to that point (if you have a machine fast enough).
Then if you need to calculate 2/5, why do the calculation now? Why not wait until you have to print it? Ever heard of Lazy Evaluation? What if later you need to multiply that number by 5? Wouldn't it make sense to print exactly 2? If you are lazy evaluating your numbers, you can do it. -
Infinte precision? Why not?[ Go to top ]
- Posted by: James Watson
- Posted on: October 07 2004 11:03 EDT
- in response to Guillermo Schwarz
You seem to misunderstand what infinity is. You cannot reach the end of infinity. There's no way to have infinite precision. You would need infinte storage and time, neither of which exist in the universe.Is there any hardware that supports infinte precision? By time and space constraints do you mean in a cosmological sense?
Let me explain with an example: You need PI, but there is no way to calculate it entirely to the last digit, but whenever you print it, you want to print exact substrings of PI.No problem! You can always calculate what you are about to print, exactly up to that point (if you have a machine fast enough).Then if you need to calculate 2/5, why do the calculation now? Why not wait until you have to print it? Ever heard of Lazy Evaluation? What if later you need to multiply that number by 5? Wouldn't it make sense to print exactly 2? If you are lazy evaluating your numbers, you can do it. -
Infinte precision? Why not?[ Go to top ]
- Posted by: James Watson
- Posted on: October 07 2004 11:05 EDT
- in response to James Watson
Even if you had infinite storage and time, you'd never get to the 'end'.
For example, write a program to print all positive integers. Easy, right? Now print all the positive integers. When will the program complete? -
Infinte precision? Why not?[ Go to top ]
- Posted by: Guillermo Schwarz
- Posted on: October 12 2004 10:33 EDT
- in response to James Watson
Even if you had infinite storage and time, you'd never get to the 'end'.
You are absolutely right, but you are missing the point.
We are not trying to *reach to the end*. We are trying print *the right digits*, not matter how many of them are required in each printing, while at the same time, do not reduce precision of the calculation.
One example where this is important is when doing monetary calculation, another is when doing census/polling/voting/democracy... and another is when calculating planet orbits around the sun. -
Infinte precision? Why not?[ Go to top ]
- Posted by: James Watson
- Posted on: October 12 2004 12:28 EDT
- in response to Guillermo Schwarz
When I was a physics major, there was never a need to keep thngs as fractions. The precision needed is known up front. In fact using too much precision (i.e. precision that is beyond what is measurable) is a mistake and will produce incorrect answers.Even if you had infinite storage and time, you'd never get to the 'end'.
You are absolutely right, but you are missing the point.We are not trying to *reach to the end*. We are trying print *the right digits*, not matter how many of them are required in each printing, while at the same time, do not reduce precision of the calculation.One example where this is important is when doing monetary calculation, another is when doing census/polling/voting/democracy... and another is when calculating planet orbits around the sun.
In any event what you are describing is not infinte precision. You are describing indeterminate precision.
Bankers actually use rounding schems that not only reduce precision but also reduce accuracy. These methods are used to keep small amounts of money from being lost or created incorrectly. It doesn't make sense for monetary calculations to be stored as fractions.
For example. Let's say a dollar is split between three accounts. So using your methodology, you add 1/3 of a dollar to each one and leave it that way to determine precision later. Eventually that value has to be converted to a decimal because there is no such thing as a third of a dollar. So what is put in each account? $0.3333? $0.0001 just disappeared into the ether. 0.3334? $0.0002 was just created out of thin air. You cannot coordinate to give one account the extra $0.0001 because you left it for later. Unless you create some compicated database of where fractions came from and where their conterparts are allocated, keeping the values as fractions will cause errors. -
Accurate[ Go to top ]
- Posted by: Guillermo Schwarz
- Posted on: October 29 2004 10:39 EDT
- in response to James Watson
When I was a physics major, there was never a need to keep thngs as fractions. The precision needed is known up front. In fact using too much precision (i.e. precision that is beyond what is measurable) is a mistake and will produce incorrect answers.
This is accurate. You should not store more precision than you have measured. But you can't know exactly how accurate your measures are, you can only estimate accuracy, or in other words whenever you store a number you should also store +/- delta, where the delta is different for every number and all arithmetic operations are done using those deltas.In any event what you are describing is not infinte precision. You are describing indeterminate precision.Bankers actually use rounding schems that not only reduce precision but also reduce accuracy. These methods are used to keep small amounts of money from being lost or created incorrectly. It doesn't make sense for monetary calculations to be stored as fractions.For example. Let's say a dollar is split between three accounts. So using your methodology, you add 1/3 of a dollar to each one and leave it that way to determine precision later. Eventually that value has to be converted to a decimal because there is no such thing as a third of a dollar. So what is put in each account? $0.3333? $0.0001 just disappeared into the ether. 0.3334? $0.0002 was just created out of thin air. You cannot coordinate to give one account the extra $0.0001 because you left it for later. Unless you create some compicated database of where fractions came from and where their conterparts are allocated, keeping the values as fractions will cause errors.
Your example is using floating point to generate errors and you described very well how by using floating point $0.0002 was just created out of thin air.
Using fractions would solve the very problem you just mentioned. Also you mentioned that there is no such thing as a third of a dollar. Maybe there should be ( I mean a coin with 1/3 written on its face ), but then it would be impossible to represent 1/10 of a dollar using those coins. Actually using floating point binary numbers it is impossible to represent 1/10 of a dollar, but usually if you assign 1.0 / 10.0 to a float and print that number, you will see 0.1 even though it is not exactly 0.1.
Then why do you care if we store 1/3 as 1/3 and when printed we print 0.3333333? Where's the error, except in the eye of the beholder? The important aspect of storing 1/3 as 1/3 is that we reduce error propagation.
Bankers rounding makes no sense to me. If it produces even less accurate results, why would anyone want to use it? -
re: Accurate[ Go to top ]
- Posted by: James Watson
- Posted on: November 01 2004 09:51 EST
- in response to Guillermo Schwarz
This is accurate. You should not store more precision than you have measured. But you can't know exactly how accurate your measures are, you can only estimate accuracy, or in other words whenever you store a number you should also store +/- delta, where the delta is different for every number and all arithmetic operations are done using those deltas.
I don't understand what you are trying to get at. We are talking about precision; not accuracy.Your example is using floating point to generate errors and you described very well how by using floating point $0.0002 was just created out of thin air.Using fractions would solve the very problem you just mentioned.
I was not using floating point numbers. That was an example with decimals. If you still think that factions solve the problem, you need to really read what I wrote more carefully. The whole point of tyhe example is how fractions cuase a problem.Also you mentioned that there is no such thing as a third of a dollar. Maybe there should be ( I mean a coin with 1/3 written on its face ), but then it would be impossible to represent 1/10 of a dollar using those coins. Actually using floating point binary numbers it is impossible to represent 1/10 of a dollar, but usually if you assign 1.0 / 10.0 to a float and print that number, you will see 0.1 even though it is not exactly 0.1.
I understand how floating pioint numbers work, thanks. That's why everyone is recommending using BigDecimal (not floating point.)Then why do you care if we store 1/3 as 1/3 and when printed we print 0.3333333? Where's the error, except in the eye of the beholder?
I already explained that. If you divide a dollar between three parties and put a fraction in each of their accounts, at some point you must convert to decimal. When you do, you will either lose or gain a fraction of a dollar.The important aspect of storing 1/3 as 1/3 is that we reduce error propagation.Bankers rounding makes no sense to me. If it produces even less accurate results, why would anyone want to use it?
Wrong, it increases the error. Bankers must ensure that at the end of the day all the accounts, cash in and cash out square up or risk going to jail.
If you think you know more about banking than bankers you should become a banking consultant. I'm sure they'd really appreciate that you think they do things all wrong.
Here's a short explanation of banker's rounding:
http://thesaurus.maths.org/mmkb/entry.html?action=entryById&id=3064
And here's some information on significant digits:
http://en.wikipedia.org/wiki/Significant_figures -
re: Accurate[ Go to top ]
- Posted by: James Watson
- Posted on: November 01 2004 10:30 EST
- in response to Guillermo Schwarz
Then why do you care if we store 1/3 as 1/3 and when printed we print 0.3333333? Where's the error, except in the eye of the beholder
Just in case you are still not understanding:
1.0000000 / 3 ≈ 0.3333333
0.3333333+
0.3333333+
0.3333333=
----------
0.9999999
1.0000000 != 0.9999999 -
re: Accurate[ Go to top ]
- Posted by: Guillermo Schwarz
- Posted on: June 13 2005 00:53 EDT
- in response to James Watson
Then why do you care if we store 1/3 as 1/3 and when printed we print 0.3333333? Where's the error, except in the eye of the beholder
Just in case you are still not understanding:1.0000000 / 3 ≈ 0.33333330.3333333+0.3333333+0.3333333=----------0.99999991.0000000 != 0.9999999
1.0000000 / 3 = 1/3 (represented as a single object called fraction)
1/3+1/3+1/3=----------1
1 == 1 -
re: Accurate[ Go to top ]
- Posted by: James Watson
- Posted on: July 07 2005 17:45 EDT
- in response to Guillermo Schwarz
1.0000000 / 3 = 1/3 (represented as a single object called fraction)1/3+1/3+1/3=----------11 == 1Then why do you care if we store 1/3 as 1/3 and when printed we print 0.3333333? Where's the error, except in the eye of the beholder
Just in case you are still not understanding:1.0000000 / 3 ≈ 0.33333330.3333333+0.3333333+0.3333333=----------0.99999991.0000000 != 0.9999999
0.33333330 != 1/3 -
re: Accurate[ Go to top ]
- Posted by: James Watson
- Posted on: July 07 2005 17:49 EDT
- in response to Guillermo Schwarz
1.0000000 / 3 = 1/3 (represented as a single object called fraction)1/3+1/3+1/3=----------11 == 1Then why do you care if we store 1/3 as 1/3 and when printed we print 0.3333333? Where's the error, except in the eye of the beholder
Just in case you are still not understanding:1.0000000 / 3 ≈ 0.33333330.3333333+0.3333333+0.3333333=----------0.99999991.0000000 != 0.9999999
I don't know how else to explain this. You cannot pay someone a third of a dollar. At some point, these fractions must be converted to decimal, if you delay until the last moment, it is not feasible to reconcile the error. You don't know who to give the extra penny to. What you are recommending is extremely irresponsible. -
re: Accurate[ Go to top ]
- Posted by: william c
- Posted on: August 27 2005 18:51 EDT
- in response to James Watson
I don't know how else to explain this. You cannot pay someone a third of a dollar. At some point, these fractions must be converted to decimal, if you delay until the last moment, it is not feasible to reconcile the error. You don't know who to give the extra penny to. What you are recommending is extremely irresponsible.
1.0000000 / 3 = 1/3 (represented as a single object called fraction)1/3+1/3+1/3=----------11 == 1Then why do you care if we store 1/3 as 1/3 and when printed we print 0.3333333? Where's the error, except in the eye of the beholder
Just in case you are still not understanding:1.0000000 / 3 ≈ 0.33333330.3333333+0.3333333+0.3333333=----------0.99999991.0000000 != 0.9999999
In the specific domain of currency/money I don't see any point in deferring the resolution of a fraction; it just isn't an option in the monetary domain however great its merits elsewhere. So far as I know every monetary calculation is bound by the regulations of the monetary system(s) it operates in, which only allow a certain level of precision when recording the output of monetary calculations, and the precision used in a monetary transaction. So in the UK every account has to balance to the penny, therefore every monetary transaction has an output precision of one penny. One penny is the limit of accuracy at each step of a calculation where the value is recorded in an account. I don't know the precision allowed within a complex transaction or calculation, but I suspect that it is set by law or specific contract for each calculation type or particular instance.
Note that some currencies can have precision smaller than the smallest legal tender denomination in circulation; Australia has no coin smaller than 5 cents, but account balances are recorded at a precision of 1 cent. -
Infinte precision? Why not?[ Go to top ]
- Posted by: James Watson
- Posted on: October 12 2004 12:31 EDT
- in response to James Watson
Then if you need to calculate 2/5, why do the calculation now? Why not wait until you have to print it?
BTW: 2/5 = 0.4 Which can be stored exactly in a BigDecimal. -
Monetary Calculation Pattern[ Go to top ]
- Posted by: Risto Solman
- Posted on: October 19 2004 17:43 EDT
- in response to Bengt Hammarlund
I checked the "timeandmoney" project on sourceforge and it is kind of terrible. I think it would be a good idea for an open source project that would do it right, i would sure be willing to help.
It would be quite interesting to have CurrencyRateFactory implementations that operate on different providers: DB, XML files, SOAP, etc. -
Create a brand new fixed point datatype[ Go to top ]
- Posted by: Fernando Santucci
- Posted on: November 17 2004 11:04 EST
- in response to Bengt Hammarlund
This is the oppontunity of create a brand new fixed point datatype.
public class Money {
private long _integerNumber = 0; // Default value.
private long _decimalNumber = 0; // Default value.
public Money(long integerNumber, long decimalNumber) {
_integerNumber = integerNumber;
_decimalNumber = decimalNumber;
}
public Money(double value) {
if (value < 0) {
_integerNumber = (long)Math.ceil(value);
} else {
_integerNumber = (long)Math.floor(value);
}
_decimalNumber = (long)(value - _integerNumber);
}
}
Implementation Example:
----------------------
The Microsoft SQL Server and Visual Basic "Date" datatype on internals persist a "float" primitive datatype, where:
1. The integer value means the date value.
2. The decimal value means the time value.
Best regards,
Fernando Santucci
Rio de Janeiro - Brasil
. -
Open-Source monetary package.[ Go to top ]
- Posted by: Jean-Marie Dautelle
- Posted on: February 05 2005 21:38 EST
- in response to Bengt Hammarlund
Found your post by chance.
You may want to look at JScience monetary package. It uses interval arithmetic to guarantee quantities (such Money) accuracy.
http://jscience.org/api/org/jscience/economics/money/package-summary.html -
Don't take too much[ Go to top ]
- Posted by: Elijah Epifanov
- Posted on: September 02 2005 02:09 EDT
- in response to Bengt Hammarlund
I think that your framework should concentrate on data, not logic. IMO, it needs one class for monetary type and few helper classes. What it really needs is integration with things like EJB. The class then may be annotated as a complex entity (value + currency). Dunno what else it needs..
Maybe conversion framework, but I can't imagine what conversion framework needs except of multiplication/division/rounding:) -
Monetray Calculaiton Pattern[ Go to top ]
- Posted by: Robert Sachtjen
- Posted on: February 16 2006 17:00 EST
- in response to Bengt Hammarlund
Bengt, did you start an open source project for this? and if so how can I find it?
robert.sachtjen@sungard.com