tags:

views:

984

answers:

6

I am considering writing two limited precision alternatives to BigDecimal, namely DecimalInt and DecimalLong. These would be capable of dealing with numbers within the real bounds of int and long with an arbitrary number of decimal places, creatable in both mutable and immutable form. My plan is to make DecimalInt support +/-999,999,999 to +/- 0.999999999 and DecimalLong the same, but with up to 19 digits.

This would be done by maintaining a decimal digit count value of 0-9 for DecimalInt and 0-19 for DecimalLong along side the actual value stored as a scaled int or long. The normal use would be for small numbers of decimals such as for money and stock prices, typically 2-4 decimal places.

The essential requirements are (a) lean footprint (2 classes, plus OverflowException), and (b) full support of all basic operations plus all of Math that makes sense.

Googling for results did not return any obvious hits - they all seemed to pertain to arbitrary decimals.

My questions are: Has this already been done? Are there hidden subtleties in this which is why it has not already been done? Has anyone heard rumors of Java supporting a decimal type like DotNet's.

EDIT: This is different from BigDecimal because it should be (a) a hell of a lot more efficient to not deal with an array of ints, and (b) it won't wrap BigInteger so it will be leaner on memory too, and (c) it will have a mutable option so it will be faster there as well. In summary - less overhead for the simple use cases like "I want to store a bank balance without the overhead of BigDecimal and the inaccuracy of double".

EDIT: I intend on doing all the math using int or long to avoid the classic problem of: 1586.60-708.75=877.8499999999999 instead of 877.85

A: 

If your focus is for portable devices look at Real. Real allows for the precision of the number to be set from 0 to 16. It is designed for MIDP cell phones.

Also of interest, look at the constructive reals library. It's not lightweight though.

In reference to the comment below, can you not use the Apache Commons Math Library to work with fractions? Is there some reason that won't work?

WolfmanDragon
Real looks good, but... it's GPL'd so can't use it commercially, and, isn't it still floating point math so it suffers from problems with decimal fractions which cannot be represented in binary?
Software Monkey
I did not realize that you had a license requirement.
WolfmanDragon
A: 

It seems to me that if you want arbitrary precision then you are going to need an undefined number of bits to represent the mantissa. That means that some sort of array allocation strategy is going to be necessary for the mantissa. You could craft your own here, but BigInteger does it fairly efficiently and it works

You need to specify what the smallest (non-zero) value you need to represent is. This will be 10^-(2^n), where n+1 is the number of bits you allocate to the exponent. With BigDecimal this is 10^-(2^31). You could use an arbitrary size exponent, but that range should be enough for anybody.

So what you need is an unbounded integer mantissa to give you the arbitrary precision, and a fixed size exponent, depending on what you want your minimum representable value to be. Essentially this is BigDecimal; the only change is you will use some smaller object rather than the int used by BigDecimal. I would doubt whether the space savings are worth it. I would think that BigDecimal is going to do what you need with barely any more memory usage than any solution you craft yourself.

Of course you could choose a maximum number of significant figures that you will need; then you need fixed size storage for both mantissa and exponent, and that's a whole lot less storage. Just use a fixed number of longs as the mantissa.

DJClayworth
Which is why my question said "limited precision", not "arbitrary precision".
Software Monkey
And stated that the precision of each would be limited to what int and long can hold, with a separate value hold the number of decimal places. To eliminate the complex hoops jumped through by BigInteger.
Software Monkey
Your question says "with an arbitrary number of decimal places". Please make your mind up.
DJClayworth
Arbitrary, but constrained to either 0-9 or 0-19 decimal places.
Software Monkey
A: 

If you are looking at a fixed, small number of decimal places for handling money, then this is usually done by holding integer (long if necessary) numbers of cents, or hundredths of a cent.

If you are dealing with money then you will need to be careful of how you handle rounding. If your calculations are going to be audited there are rules for how that sort of thing is done. Also I assume you are aware that some operations can't be done precisely (division being the obvious example).

DJClayworth
A: 

Its a pity you need 19 digits. If you needed 18 and were happy with a fixed implied number of decimal places, you could have just used a 'long'. A long might still do if all you numbers will be positive.

You're right, needs to be constrained to 18 digits to fit within long with each of the 19 being 0-9; forgot about the sign bit.
Software Monkey
+5  A: 

I strongly suspect the reason why this has not been done is that the overhead of BigDecimal and BigInteger is not as relevant as you think, and avoiding it not worth the effort and the risk of getting it wrong in some subtle way.

To use your example: for any financial application, saving a few dozen bytes is a non-issue and limited precision a deal-breaker (stock prices my have typically 2-4 digits in the USA, but if you want to deal with emerging markets, you'll encounter currencies with runaway inflation, where a 15-digit sum buys you half a loaf of bread).

Basically, it sounds like just another case of premature optimization.

Michael Borgwardt
A: 

Was any progress made on this implementation, or any luck finding an existing opensource one?

Tom Sorgie
No, it's still on my "personal project" backlog.
Software Monkey