OASIS Mailing List ArchivesView the OASIS mailing list archive below
or browse/search using MarkMail.

 


Help: OASIS Mailing Lists Help | MarkMail Help

ubl-dev message

[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]


Subject: Re: [Fwd: Re: [ubl-dev] ExchangeRate amounts]


Roberto Cisternino wrote:

> you are right this is an important issue, however when
> you use BigDecimal for calculations in order to be "more precise" than
> float and double, then you need to make sure that you never use a float or
> double to initialize the BigDecimal.
> 
> You should use the constructor that takes a String:
> 
> new BigDecimal("1.5")
> 
> instead of
> 
> new BigDecimal(1.5)
> 
> as this last will generate:
> 0.1499999999999999944488848768742172978818416595458984375
> 
> BigDecimal is good to control the rounding and the error you achieve
> should be small...
> 
> Let me know if this way your calculation is better.

BigDecimal is still subject to the limitations of base-10 arithmetic,
switching from base-2 arithmetic (which double and float use) to base-10
arithmetic won't help you at all, the basic mathematical limitations are
the same.

The example you've posted above highlights the limitations of base-2
arithmetic, one of the key problems there being that "10 cents" (and
certain multiples thereof) cannot be expressed exactly as a binary number.

The example I posted earlier shows a limitation of base-10 arithmetic
("one third" cannot be represented exactly as a base-10 number), which
leads to rounding errors and makes the remittance advice inaccurate when
multiple currencies are used.

Try compile and run this code, you will end up with an EUR100 rounding
error:

		BigDecimal gbp = new BigDecimal("300000");
		BigDecimal rate = new BigDecimal("1.3333");
		BigDecimal eur = eur.multiply(rate);
		System.out.println(eur.toPlainString());

399990.0000

Try compile and run this code, BigDecimal will throw an exception,
because it cannot accurately calculate the rate without rounding:

		BigDecimal eur = new BigDecimal("400000");
		BigDecimal gbp = new BigDecimal("300000");
		BigDecimal rate = eur.divide(gbp, RoundingMode.UNNECESSARY);

java.lang.ArithmeticException: Rounding necessary
	at java.math.BigDecimal.divideAndRound(BigDecimal.java:1435)
	at java.math.BigDecimal.divide(BigDecimal.java:1381)
	at java.math.BigDecimal.divide(BigDecimal.java:1541)

The use of BigDecimal makes no difference, the only way to express a
currency exchange is by specifying the source and the target currency
amounts exactly, as well as the rate, so that there is no scope for
errors to be introduced through rounding.

Regards,
Graham
--


[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]