Skip to main content

[JSR-354] Re: Number representation on MonetaryAmount

  • From: Werner Keil <werner.keil@...>
  • To: "jcurrency_mail@..." <jcurrency_mail@...>
  • Subject: [JSR-354] Re: Number representation on MonetaryAmount
  • Date: Wed, 2 Oct 2013 09:55:07 +0200

I guess I could use the long German weekend for that.

 Werner Keil | JCP Executive Committee Member | Eclipse UOMo Lead, Babel
Language Champion | Java Godfather

Twitter @wernerkeil | @JSR354 | #EclipseUOMo | #Java_Social | #DevOps
Skype werner.keil | Google+ gplus.to/wernerkeil

* JMaghreb 2.0: Nov 7-8 2013, Casablanca, Morocco. Werner Keil, JCP EC
Member, JSR 354 EG Member will present "Java Social", "JSR 354"


On Tue, Oct 1, 2013 at 12:11 PM, Anatole Tresch <atsticks@...> wrote:

> Hi Werner
> Can you make a code proposal ? This would make it clearer...
>
> Thanks.
> Anatole
>
> -
> Anatole Tresch
> Glärnischweg 10
> 8620 Wetzikon
> Tel +41 (43) 317 05 30
> -
> Send from Mobile
>
> Am 01.10.2013 um 03:00 schrieb Werner Keil <werner.keil@...>:
>
> Anatole/Stephen,
>
> Thanks for the update. Some contributors to Unit-API, especially the ones
> using it or precursors like JSR-275 at GeoAPI and related OGC standards and
> projects provided similar benchmarks there. Comparing e.g. the use of
> primitive types with use of something like BD.
>
> Number even it if was internally represented as BigDecimal is the de facto
> standard of JavaFX in Java 8
>
> http://download.java.net/jdk8/jfxdocs/javafx/beans/value/ObservableNumberValue.html
>
> There is no API baking BD into the API, but there are some variants with
> primitive types like double or long and their wrappers.
>
> JavaFX tries to bridge the gap between different representations, as there
> is no reason in the API why DoubleBinding.add(FloatBinding) wouldn't work.
> In the most recent  approach where implementations like FastMoney, Money
> or others (e.g. BitcoinMoney) no longer share anything other than an
> adjust() method this means they are separated and one will not be able to
> mix them in real life operations. Probably safer when you look at precision
> or performance, but it also means a drawback for some use cases. Whether
> Java 9 might use the BD-backed default Money or something else, it is
> unlikely a class like FastMoney or BigMoney becomes part of the JDK, unless
> you think along the lines of BigDecimal vs. BigInteger?<35F.gif>
>
> While Bitcoin can use multiple sub-units (see
> http://en.wikipedia.org/wiki/Bitcoin for all that are currently used) if
> the fractionDenominator goes to 100.000.000 then the current definition of
> MonetaryAmount would allow to represent an amount in (whole) BTC plus
> "Satoshis", the smallest representable sub-unit so far.
> Of course both millis and micros (somewhat similar to seconds in 310,
> technically nanos would work but don't seem in use) are also applied, so
> while storing a smaller part in the form of Satoshi it may not even be the
> long value people care, so an  equivalent to get(TimeUnit) for some
> MonetaryAmounts looks advisable. Otherwise we're likely to see forks, Btw.
> Bitcoin isn't the only currency with more than one subunit, see Japanese
> Yen: http://en.wikipedia.org/wiki/Japanese_yen
>
> Since the CurrencyUnit is so minimalistic, it seems possible to build
> something like a FractionUnit (the relevant methods in MonetaryAmount all
> call it "fraction") While multiplied by whatever (Metric or other, see
> India<347.gif>) prefix, the same does not seem necessary for the whole
> amount. This is where date often has different requirements, e.g. looking
> at how many Centuries or Decades you get from a number of years<329.gif>
>
> Werner
>
>
>
> On Mon, Sep 30, 2013 at 8:53 AM, Anatole Tresch <atsticks@...>wrote:
>
>> Hi Stephen
>>
>> OK, seems reasonable, so I will include your conversion proposal within
>> next days and see, how much faster we get.
>> Thanks for that input and enjoy your day!
>>
>> Anatole
>>
>>
>> 2013/9/30 Stephen Colebourne <scolebourne@...>
>>
>>> These results are probably about what I'd expect except that the basic
>>> Money case using BD is faster than expected at 20 times slower.
>>>
>>> It is a natural expectation that mixing types will result in a slower
>>> answer, because the from() method has a greater conversion to do. Most
>>> users of the API will be using a single money implementation - it will
>>> be rare for them to be using more than one implementation. If they do
>>> use more than one implementation, it is likely that the second one
>>> will be the JDK9 implementation which a 3rd party library would be
>>> able to refer to and optimise for.
>>>
>>> asNumber() has never been an acceptable thing to use because the
>>> Number interface is useless. Given a Number, there is no way to
>>> accurately extract the numerical value. The best that can be done (and
>>> what I assume you did) was to check instanceof BD and cast. Simply
>>> calling doubleValue() or longValue() will never be sufficient,
>>> especially for a money API.
>>>
>>> In JDK9 there will be the possibility to add a factory to BD that can
>>> create from the three arguments. Alternately, a Rational class could
>>> be developed and proposed to the JDK separate to this JSR.
>>>
>>> The fastest BD constructor is the (long,int) one - (unscaled, scale).
>>>
>>> Thus the fastest BD conversion is likely to involve special casing.
>>> Something like (but handling negatives):
>>> if (denom == 100 && whole < Long.MAX_VALUE / 1000) {
>>>  return BD.valueOf(whole * 100 + numerator, 2);
>>> } else if (denom == 1) {
>>>  return BD.valueOf(whole, 0);
>>> } else if (denom == 1000 && whole < Long.MAX_VALUE / 10000) {
>>>  return BD.valueOf(whole * 1000 + numerator, 3);
>>> } else {
>>>  ... create slow
>>> }
>>>
>>> or something like this
>>> array = {1, 10, 100, 1000, ...}
>>> for (int i = 0; i < array.length; i++) {
>>>   if (denom == array[i]) {
>>>     try {
>>>       long total = Math.multiplyExact(whole, denom)
>>>       total = Math.addExact(total, numerator);
>>>       return BD.valueOf(total, i);
>>>     } catch (ArithmeticException ex) {
>>>       ... create slow
>>>     }
>>>   }
>>> }
>>>  ... create slow
>>>
>>> Stephen
>>>
>>>
>>> On 29 September 2013 16:58, Anatole Tresch <atsticks@...> wrote:
>>> > Hi all/Stephen/Werner
>>> >
>>> > I was playing aroung with different variants of money implementations,
>>> one
>>> > using BD, one using a single long hereby using s scale of 5 digits for
>>> > representation of the minor units.
>>> >
>>> > I then measured performance for 1.000.000 executions of some arithmetic
>>> > functions as follows:
>>> >
>>> > Money money1 = Money.of(EURO, BigDecimal.ONE);
>>> > for (int i = 0; i < NUM; i++) {
>>> > money1 = money1.add(Money.of(EURO, 1234567.3444));
>>> > money1 = money1.subtract(Money.of(EURO, 232323));
>>> > money1 = money1.multiply(3.4);
>>> > money1 = money1.divide(5.456);
>>> > }
>>> >
>>> > FastMoney money1 = FastMoney.of(EURO, BigDecimal.ONE);
>>> > for (int i = 0; i < NUM; i++) {
>>> > money1 = money1.add(FastMoney.of(EURO, 1234567.3444));
>>> > money1 = money1.subtract(FastMoney.of(EURO, 232323));
>>> > money1 = money1.multiply(3.4);
>>> > money1 = money1.divide(5.456);
>>> > }
>>> >
>>> > This gaves me different execution times (and results):
>>> >
>>> > Duration for 1000000 operations (Money/BD): 3557 ms (3 ns per loop) ->
>>> EUR
>>> > 1657407.962529182
>>> > Duration for 1000000 operations (FastMoney/long): 178 ms (0 ns per
>>> loop) ->
>>> > EUR 1657407.96251
>>> >
>>> > When only slightly adapting the code above to:
>>> >
>>> > FastMoney money1 = FastMoney.of(EURO, BigDecimal.ONE);
>>> > for (int i = 0; i < NUM; i++) {
>>> > money1 = money1.add(Money.of(EURO, 1234567.3444));
>>> > money1 = money1.subtract(FastMoney.of(EURO, 232323));
>>> > money1 = money1.multiply(3.4);
>>> > money1 = money1.divide(5.456);
>>> > }
>>> >
>>> > we have quite an unexpected impact (we are ten times slower!):
>>> >
>>> > Duration for 1000000 operations (FastMoney/Money mixed): 1524 ms (1 ns
>>> per
>>> > loop) -> EUR 1657407.96251
>>> >
>>> > The issue is, that FastMoney must convert from Money in the
>>> > FastMoney.from(MoneytaryAmount)  using the numeric representation as
>>> > whole,nominator/denominator . The acceptable result shown above, was
>>> > possible, beacuse I added temporarely the method
>>> >
>>> > Number asNumber()
>>> >
>>> > to the interface and used this one, instead of creating a new Number
>>> > instance myself. When using BigDecimal within from you are
>>> significantly
>>> > slower (about 12 ns/loop).
>>> >
>>> > So question: WDYT on using asNumber() instead of the methods returning
>>> longs
>>> > for whole, fraction nominator, fraction denominator? This would allow
>>> us to
>>> > support a real high speed money implementation (compared to only fast
>>> one).
>>> >
>>> > Or can somebody provide me with code that is capable of creating a
>>> Number
>>> > real fast from the current interface...?
>>> >
>>> > Or other ideas, hints?
>>> >
>>> > Cheers,
>>> > Anatole
>>> >
>>> > PS.: Hope all is clear, its late now, and I have to end my night's
>>> hacking
>>> > tour......
>>> >
>>> >
>>> > --
>>> > Anatole Tresch
>>> > Java Lead Engineer, JSR Spec Lead
>>> > Glärnischweg 10
>>> > CH - 8620 Wetzikon
>>> >
>>> > Switzerland, Europe Zurich, GMT+1
>>> > Twitter:  @atsticks
>>> > Blogs: http://javaremarkables.blogspot.ch/
>>> > Google: atsticks
>>> > Mobile  +41-76 344 62 79
>>>
>>
>>
>>
>> --
>> *Anatole Tresch*
>> Java Lead Engineer, JSR Spec Lead
>> Glärnischweg 10
>> CH - 8620 Wetzikon
>>
>> *Switzerland, Europe Zurich, GMT+1*
>> *Twitter:  @atsticks*
>> *Blogs: **http://javaremarkables.blogspot.ch/*
>> *Google: atsticks
>> Mobile  +41-76 344 62 79*
>>
>
>


[JSR-354] Re: Number representation on MonetaryAmount

Werner Keil 10/01/2013

[JSR-354] Re: Number representation on MonetaryAmount

Anatole Tresch 10/01/2013

[JSR-354] Re: Number representation on MonetaryAmount

Werner Keil 10/02/2013
 
 
Close
loading
Please Confirm
Close