Windows Phone 7 Developer Launch - Learn More

Wednesday, June 01, 2011

Java: using BigDecimal instead of double

For the last two months I've been using Linux and Java exclusively. For the times I still need to do .NET development, my laptop is setup to dual-boot into Windows 7. But since I'm learning a lot, I really want to try and catalog my experience of transitioning from Windows/.NET developer to Linux/Java developer.

Am I giving up on .NET and Windows? No, but because I've been moved to a Java project deployed on Linux I decided to jump in with both feet. I'm enjoying how much I'm learning and hopefully as I get back in the habit of blogging, I'll include stuff I'm doing with .NET as well.

However, I first started playing with .NET during it's beta stage and have been using it on a daily basis since v1.1. So, at least for the time being, I'm likely to include comparisons with .NET when I post about Java in as much as I see it will benefit .NET developers who are making the same transition I am. Who knows, maybe my perspective will also be interesting to some Java developers as well.

Primitive Java Types

I've been working on a test harness that publishes rates and at the moment all it does is publish a rate and check to see if the same value comes out the other end. I have a instance of a log4j Logger that I'm using to output debug info to the console as I develop this and I was noticing that when I would add two doubles together the results were imprecise. For example, the following:


private void doubleOutput(){
        double rate = 1.37000;
        double adjustment = 0.00001;
        try {
            while(System.in.available() == 0){
                rate += adjustment;
                log.debug("The new rate is: " + rate);
                pause(500);
            }
        } catch (IOException e) {
            log.error("IOException: " + e);
        }
    }

would give the these results:

2011-06-01 10:56:42,011 DEBUG [Main] The new rate is: 1.3700100000000002
2011-06-01 10:56:42,512 DEBUG [Main] The new rate is: 1.3700200000000002
2011-06-01 10:56:43,012 DEBUG [Main] The new rate is: 1.3700300000000003
2011-06-01 10:56:43,513 DEBUG [Main] The new rate is: 1.3700400000000004
2011-06-01 10:56:44,013 DEBUG [Main] The new rate is: 1.3700500000000004

It's been a while since I've really looked into the issue. In .NET the de facto standard for monetary calculations is the decimal type (System.Decimal). System.Float and System.Double are binary floating types and will result in rounding errors. So in this sense, Java is the same: the double types on both platforms are binary floating types implemented according to the IEEE 754 standard.

So what is the equivalent of System.Decimal in Java?

BigDecimal

The Java equivalent of System.Decimal is java.math.BigDecimal. Here's the equivalent of the above method, using BigDecimal:

 private   void  roundingTests(){
        BigDecimal rate = new BigDecimal("1.37000");
        BigDecimal adjustment = new BigDecimal("0.00001");
        try {
            while(System.in.available() == 0){
                rate = rate.add(adjustment);
                log.debug("The new rate is: " + rate.doubleValue());
                pause(500);
            }
        }  catch  (IOException e) {
            log.error( "IOException: "  + e);
        }
    }

Which will give you this output:

2011-06-01 11:19:24,715 DEBUG [Main] The new rate is: 1.37001
2011-06-01 11:19:25,216 DEBUG [Main] The new rate is: 1.37002
2011-06-01 11:19:25,716 DEBUG [Main] The new rate is: 1.37003
2011-06-01 11:19:26,217 DEBUG [Main] The new rate is: 1.37004

This is more what I was expecting. However, BigDecimal has some important differences with System.Decimal. First of all, and what took me the longest to catch on to, is that BigDecimal is immutable. Just like System.String in .NET. So how does this affect you? Look at the first line inside the loop above. What do you notice? Instead of using the standard addition operator, there's an "add" method. Also, I'm assigning the result back to the "rate" variable, just like if I were doing string manipulations.

If you modify the above sample and remove the assignment, and leave just the "add" operation the result you'll see in the console is that the rate is always "1.37000".

The second thing to note is the constructor. Notice how I am passing in a string representation of the values 1.37000 and 0.0001. The reason is (I'm pretty sure about this) because if I were to pass in the values without the quotes I would be passing in double values and my results would be as follows:

2011-06-01 11:26:20,639 DEBUG [Main] The new rate is: 1.3700100000000002
2011-06-01 11:26:21,141 DEBUG [Main] The new rate is: 1.37002
2011-06-01 11:26:21,641 DEBUG [Main] The new rate is: 1.37003
2011-06-01 11:26:22,142 DEBUG [Main] The new rate is: 1.3700400000000001
2011-06-01 11:26:22,642 DEBUG [Main] The new rate is: 1.3700500000000002

All of a sudden I'm back to my original problem. So I pass in my string representation to prevent my values from behaving like binary floating types.

Performance and Accuracy

A note about performance. Something I didn't know about System.Decimal (or at least it never occurred to me) was that it is an 128 bit value, capable of storing up to 29 significant digits. System.Double is 64 bits. java.lang.BigDecimal however is represented internally as an array of integers (java.lang.BigInteger) which has no size limit. So the size of it depends upon how large the number is. My assumption is that this also applies to accuracy such that there is no limit on the number of significant digits. I had been wondering why there was just BigDecimal and no Decimal class, my guess is that because it uses BigInteger internally and it really can be BIG, it makes sense to call it BigDecimal and with that, there's really no need for just Decimal since not only can it be really big, but it will also contract (I'm not saying it actually trims the internal array, just that smaller values will result in less memory consumption) for smaller values.

Either way there are implications on performance due to the implementations. If performance is really a concern then there are alternatives, but for most applications BigDecimal (and System.Decimal) should be just fine.

Update 6/2/11: Looking around some more today I noticed that if you don't want to use BigDecimal if you're just passing values around, but want to use it just when you're doing calculations you can use the static method BigDecimal.valueOf(double); According to javadocs this is the equivelent of new BigDecimal(Double.toString(double)); Either way, as far as I can tell you can do this without running into rounding errors. If you're still worried about possible rounding errors you can use the BigDecimal instance method setScale which allows you to set the scale you want and optionally the RoundingMode. So when doing calculations your API can use "double" while you can use BigDecimal internally. In .NET you could do the same using the explicit IConvertable.ToDecimal(IFormatProvider) on an instace of System.Double (ex: ((IConvertable)rate).ToDecimal(null); ) and the static Decimal.ToDouble(Decimal) to convert back and forth between Double and Decimal.

References

For more information on System.Decimal see: http://csharpindepth.com/Articles/General/Decimal.aspxhttp://msdn.microsoft.com/en-us/library/system.decimal.aspx

For more information on java.math.BigDecimal see: http://firstclassthoughts.co.uk/java/traps/big_decimal_traps.htmlhttp://download.oracle.com/javase/1.4.2/docs/api/java/math/BigInteger.html

tags: , , ,

Friday, February 25, 2011

jQuery: Highlight table elements when a cell is clicked

In a recent interview I was given an assignment to be completed before the phone interview. The assignment was to highlight the appropriate cell, column and row elements in an HTML table when the table cell was clicked. I was allowed to use any JavaScript framework I wanted. The result was expected to look exactly like this when a cell was clicked:

Working demo

Rendering engine Browser Platform(s) Engine version CSS grade
Gecko Firefox 1.0 Win 98+ / OSX.2+ 1.7 A
Gecko Firefox 1.5 Win 98+ / OSX.2+ 1.8 A
Gecko Firefox 2.0 Win 98+ / OSX.2+ 1.8 A
Gecko Firefox 3.0 Win 2k+ / OSX.3+ 1.9 A
Gecko Camino 1.0 OSX.2+ 1.8 A

 

Those who know me well (as well as those observant enough to notice) know despite the blogging I’ve done on Silverlight/WPF and ASP.NET MVC and my knowledge of the subject matter I really don’t like working much in the UI layer. So much so that I’ve always been more than willing to let those more interested (and capable) to take the reigns and handle as much of the JavaScript code as I could avoid. I’m not saying I can’t write JavaScript, I’m just saying I make sure I can do what I need to get my job done and no more. As a good friend puts it – I’m lazy (about JavaScript anyway).

Back to the interview assignment. I was open about my JavaScript skills (or limitations thereof) with the interviewer and maybe that’s why the assignment involved JavaScript – they wanted to see where I was at. Well, I was able to get it done in a reasonable amount of time. Also since I was impressed with the result and the interviewer liked it as well, I thought I’d share it here.

There’s nothing fancy about it, although this was my first ever attempt at extending jQuery, but I like the result. Here’s the code:

$(function(){
    $("td").click(function(){
        var cell = $(this);
        var row = cell.parent();
        var col = cell.parents("table").find("td:nth-child(" + (cell.index() + 1) + ")");
        
        // make row yellow
        row.css({backgroundColor: "Yellow"}).resetBackground();
        // make column orange
        col.css({backgroundColor :"Orange"}).resetBackground();
        // make cell red
        cell.css({backgroundColor: "Red"}).resetBackground();
    });
});
 
(function($){
    $.fn.resetBackground = function() { 
        $(this).stop().animate({ backgroundColor : "#fff" }, 1500, function(){ 
            $(this).css({ backgroundColor : "" }); 
        });
    };
}(jQuery));

First, we’re just registering for the ‘click’ event of the ‘td’ element. Then storing references to the cell and row – easy enough. But then the next line took some digging for me to find. ‘Column’ is not an explicit element in an HTML table. Instead, you have a collection of vertically aligned ‘td’ elements (cells). So in order to get a reference to a ‘column’ you need to:

  1. Get a reference to the table element – cell.parents(“table”)
  2. Get the index of the td element that was clicked – $(this).index()
  3. Use the find() method to get the collection of cells with the same index  - td:nth-child(int)

A couple of caveats, the nth-child selector isn’t zero-based, it’s one-based, so you’ll need to increment #2 by a value of 1. Also, this method does not take the ‘colspan’ attribute into account. But other than that you now have a reference to the cell, row and column that were clicked.

Next, setting the background color is pretty simple using the css() method. But I wanted the demo to be usable – what application would ever just change the color and leave it? What happens when the next cell is clicked? You could reset the whole table, but I thought it would be fun to have the background fade back to white. So using the jQueryUI animate method I set the background color back to white with a timeout of 1500 milliseconds.

Lastly, once I had this working I found a weird behavior. The cells I had previously clicked remained white the next time a cell in the same row was clicked. The column background continued to work and didn’t behave this way, but because the cell’s background property overrides the background property of the row I had to reset the background-color property of the cell after the animation was complete. So that’s why I added a function to completely clear out the background color property of the cell to the complete parameter of the animate method.

Mostly, this is for my own benefit but I hope maybe this helps someone else with their jQuery adventures.

tags: ,

Wednesday, October 27, 2010

Mid-Senior .Net Services Developer Positon - CLOSED

We’re looking for a .Net services developer, mid-senior range: http://tbe.taleo.net/NA8/ats/careers/requisition.jsp?org=INTERBANK&cws=1&rid=86. I’m not interested in hearing from recruiters, and I’d prefer direct contact so if you know someone, have them contact me. The position is for Salt Lake City, UT local applicants only.

THIS POSITION IS CLOSED

 

 

Copyright © Mark J. Miller