Monetary Calculation Pattern

Discussions

J2EE patterns: Monetary Calculation Pattern

  1. Monetary Calculation Pattern (38 messages)

    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 it’s 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 object’s 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. It’s not so bad but it’s 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 API’s 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 Money’s constructor. I’ll 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 it’s a good idea to implement it as a OpenSource project. Thanks a lot!

    Threaded Messages (38)

  2. Monetary Calculation Pattern[ Go to top ]

    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.
  3. Monetary Calculation Pattern - Framework[ Go to top ]

    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.
  4. BigDecimal has rounding errors[ Go to top ]

    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
  5. BigDecimal has rounding errors[ Go to top ]

    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)
  6. Re : Framework[ Go to top ]

    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.
  7. 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...
  8. 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
  9. 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 ;)
  10. 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
  11. Interesting idea.[ Go to top ]

    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 :).
  12. Monetary Calculation Pattern[ Go to top ]

    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
  13. Monetary Calculation Pattern[ Go to top ]

    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 ?
  14. Found this ![ Go to top ]

    http://sourceforge.net/projects/timeandmoney

    Still they dont offer conversion. But is better than nothing.
  15. Double?[ Go to top ]

    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.
  16. Monetary Calculation Pattern[ Go to top ]

    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());
    }
  17. 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?
  18. 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????
  19. 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.
  20. 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.
  21. Infinte precision?[ Go to top ]

    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?
  22. Infinte precision? Why not?[ Go to top ]

    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.
  23. Infinte precision? Why not?[ Go to top ]

    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.
    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.
  24. Infinte precision? Why not?[ Go to top ]

    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?
  25. Infinte precision? Why not?[ Go to top ]

    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.
  26. Infinte precision? Why not?[ Go to top ]

    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.
    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.

    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.
  27. Accurate[ Go to top ]

    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?
  28. re: Accurate[ Go to top ]

    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
  29. re: Accurate[ Go to top ]

    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
  30. re: Accurate[ Go to top ]

    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
  31. re: Accurate[ Go to top ]

    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=----------11 == 1

    0.33333330 != 1/3
  32. re: Accurate[ Go to top ]

    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=----------11 == 1

    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.
  33. re: Accurate[ Go to top ]

    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=----------11 == 1
    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.

    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.
  34. Infinte precision? Why not?[ Go to top ]

    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.
  35. Monetary Calculation Pattern[ Go to top ]

    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.
  36. 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
    .
  37. 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
  38. Don't take too much[ Go to top ]

    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:)
  39. Monetray Calculaiton Pattern[ Go to top ]

    Bengt, did you start an open source project for this? and if so how can I find it?

    robert.sachtjen@sungard.com