My early days of computing large numbersWhen I was 7, I heard from my school teacher the story of the inventor of the chess game, and the price he asked for it. He asked his shah to pay him one grain for the first field of the chess board, two for the next, and then four, eight, and so on. The total amount of grains would have equalled the crop of three years, it is told. If the shah would have used a Java long to calculate the number of grains owned, he would have got -1 as result, so the inventor would have paid 1 grain to the shah; instead he paid with his head, for the shah was angry he could not pay his debt. If you are not in a mood to think about it at the moment, the total number of grains owned was 2.pow(64) - 1. I didn't know this at that age, so I took a big piece of paper and calculated it by hand. Quite proud I showed the result to my teacher. He wasn't any wiser than to ask me mockingly to pronounce that number.
Years later I started my professional career at the IT department of an insurance company, as contact for the user departments. For reporting we used Culprit, the late Cullinet's (IDMS) reporting language. Though Culprit was not really fit for anything beyond that, it was the only language I had access to, so I used it to program my first large number program, and printed out the then newly found largest prime number, something in the order of 2.pow(102000) - 1. The department also used that program as a benchmark for comparing the new mainframe with the old one; with 7sec versus 14sec the performance was exactly the double, as expected from the megaHertz rating, or was it still Hertz? My current PC does it in less than 2sec.
Java's large numbersOn first use, some 2 years ago, I was quite disappointed in java.math.BigDecimal. A java.math.BigDecimal number does not work like you would expect of a decimal number, and it is no replacement for a float either. It does not even accept the scientific notation of numbers we've got used to. It appears java.math.BigDecimal is just a wrapper around java.math.BigInteger, with some added magic acting on an 'int scale' field for justifying the decimal in it's name. BigInteger in turn is only a quite large but rather thin Java wrapper around Colin Plumb's BigNum C-library for large numbers. Apparently the Javasoft guys needed a large number math fast (for JDBC probably), whereas we needed a fast large number math (for our own database stuff). So we had to write one ourselves (someone told me this reinventing the weel is the big advantage of object-oriented programming, but I guess I misunderstood).
We decided to go for a class that internally uses a decimal notation, for which we found inspiration in Cobol's packed decimal as well as in the BCD instructions in the Intel x86 CPUs. Using BCD coding enables easy decimal point positioning, and by packing the BCD in ints, you can still move them around fast. Memory usage is at 1 byte per 2 decimal digits only slightly more than that of java.math.BigDecimal, and even less for short numbers as we do not need a second (BigInteger) object. All this enabled us to reach our main goal, going to and from String at an acceptable speed (especially as we also have a constructor directly from the ASCII bytes we read in our database).
IBM's new BigDecimalWe had been using this code happily in our own private little database for over a year, when IBM came with its Java Specification Request for an enhanced BigDecimal. You can read it at http://www2.hursley.ibm.com/decimal or http://www.alphaWorks.ibm.com/formula, and download IBM's implementation of it. We liked the spec's, and we are convinced you will as well. But though the implementation has some very strong points, especially for going to and from String (as did our original class) and for the common 'short' numbers, the performance as Big Decimal is no match for java.math's native C-library, nor, as it appeared, for our own 100% Java class.
We decided to adhere to IBM's proposed specifications, which also ensures compatibility with java.math.BigDecimal, and so we succeeded in creating a better BigDecimal than java.math at a better speed than com.ibm.math (and than java.math as well). We tested on a large set of carefully selected special cases and a massive 'random' sampling of both (very) long and small numbers, with exponents you couldn't dream of if using doubles or java.math.BigDecimals. Overall we executed well over 225 million different operations under both IBM's and our BigDecimal class, and under java.math.BigDecimal for compatibility mode operations, and compared the results. Apart from some differences in Exception message texts we found not a single discrepancy.