Archive for April 2007
The Evil BigDecimal Constructor
One of the first things that most people learn as software developers, quite probably by accident, is that thanks to the binary representation that computers use for numbers, floating point operations are really kind of screwed up. So Java programmers learn early that if the calculation involves floating point numbers, it’s better to use java.math.BigDecimal to preserve all those fractions exact value to get the correct calculation result.
Which is correct. Except that some developers mistakenly use the BigDecimal(double) constructor, like the snippets below:
js> importPackage(java.math);
js> var oneTenth = new BigDecimal(0.1);
js> var oneMillion = new BigDecimal(1000000);
js> oneTenth.multiply(oneMillion)
100000.0000000000055511151231257827021181583404541015625000000
Which brings them back to square one, really. The reason is that when you call BigDecimal(double), the BigDecimal instance that you get back is the exact representation of that double value you’re passing in. In other words, you’re just reproducing the inaccuracy that you get when you try to represent 0.1 in binary. Pity.
To get what you really want, remember to use the other constructor, which accept a String. This is more like it:
js> var oneTenth = new BigDecimal("0.1");
js> var oneMillion = new BigDecimal(1000000);
js> oneTenth.multiply(oneMillion)
100000.0
Note that we can still pass 1000000 to BigDecimal, because we can represent integers in binary exactly. Likewise, those fractions that can be represented exactly in binary (such as 0.5, 0.25, 0.125, 0.0625, and so on) are fine:
js> var oneSixtyFourth = new BigDecimal(0.015625);
js> oneSixtyFourth.multiply(oneMillion)
15625.000000
But why bother wasting your brain cycles to keep track of this? It’s much easier to just remember this simple rule: when you want exact calculation results the way you want it, use BigDecimal(String). When in doubt, use BigDecimal(String). In fact, I can’t think of a case where one has to use BigDecimal(double). If you know of a legitimate case for using it, I’ll be grateful if you leave a comment about it.
I’m Singing 99 Bottles of Beer!
Man! Just when I thought things couldn’t get any better with the publication of my article, the gentlemen at 99 Bottles of Beer sent me a mail, telling me that my E4X submission had been accepted! Damn that feels good
My MSDN Magazine JavaScript Article, Published!
Woohooo!!! Few things are more satisfying than seeing your article being published in a respectable magazine like MSDN Magazine. Without further ado, ladies and gentlemen, I present you with… JavaScript: Create Advanced Web Applications With Object-Oriented Techniques.
In fact, let me be cheesy for a while and save a screenshot of MSDN Magazine with my name on it to, er, show my future children or something…
Singing 99 Bottles of Beer With E4X (And How Mozilla Lied To Me)
How would you generate a song about 99 bottles of beer programmatically? This site holds a collection of the song in 1071 languages (and counting!) at the time of this writing. I was thinking of submitting a tail recursive implementation in JavaScript… but that’s kinda boring. Besides, the submission page says: “Your example should demonstrate the main advantages and features of the language“. Hmmm. JavaScript and tail recursion are kinda too… well-known.
And then it hit me: nobody has submitted E4X implementation of the Beer Song! E4X is one of the more interesting new features of Rhino: JavaScript for Java, which was excluded from the version of Rhino that comes bundled with Java SE 6.0. Luckily, getting E4X is not difficult. In minutes I’m ready to do my beer song.
Setting E4X In 3 Simple Steps
- Download Rhino here. By the way, ignore what they say about how you need xbean.jar from XMLBeans. They lied to you, you need an extra jar to get it working. I banged my head against the wall for about an hour wondering what could I’ve done wrong with such a simple line: java -cp xbean.jar;js.jar org.mozilla.javascript.tools.shell.Main, until I found out that another JAR was required. Grrr.
- E4X requires xbean.jar AND jsr173_1.0_api.jar from XMLBeans. You can download it here, and get the 2 JARs from the “lib” directory.
- Type the following command (assuming that all those 3 JARs are in the same directory):
java -cp js.jar;xbean.jar;jsr173_1.0_api.jar org.mozilla.javascript.tools.shell.Main
And you’re set. Try this out at the prompt:
js> var me = <person><name>Ray</name></person>;
js> me.name
Ray
Shweet!
Beer Drinkin’ Rhino
OK, once we’ve configured this thing, the rest is easy. Here’s the code, in it’s full glory:
var rawLyrics = readUrl(“http://99-bottles-of-beer.net/lyrics.html”);
var wellFormedRawLyrics = rawLyrics.replace(/<br>/gi, “<br/>”);
var xmlLyrics = new XML(wellFormedRawLyrics);
default xml namespace = xmlLyrics.namespace();
var songVerses = xmlLyrics..*.(/^99 bottles of beer/.test(p.text()));
for each(var verse in songVerses.children()) {
var verseText = verse.text().toString().replace(“\.”, “.\n”);
print(verseText + “\n”);
}
I saved this snippet into a file, and run the following command:
java -cp js.jar;xbean.jar;jsr173_1.0_api.jar org.mozilla.javascript.tools.shell.Main -f 99BottlesOfBeer_E4X.js
to generate (or rather, rip) the full song from the 99 bottles website. Let’s hope they’ll take in my submission!
Slimming Your JavaScript Files Down
When you have hundreds of thousands of users accessing your website, even a seemingly small difference in file size can add up to eat a LOT of bandwidth. A friend told me that in his company, they even wrote their own JavaScript library from scratch to squeeze away those tens of kilobytes (which amounts to saving a lot of bandwidth money in their case).
Personally, I wouldn’t do such a thing, though. I have more faith on widely tested libraries like this one instead of a homegrown JavaScript library written specifically for size. So I googled around a bit for JavaScript compressors, of which there are many. But in this post I’ll just take a look at two of them.
One Can Never Be Too Slim
Prototype 1.5.0 is 70kb. Prototype 1.5.1 rc2 is 92kb in size. I think it’s quite reasonable to assume that by the time it’s released it’ll probably break the 100kb barrier. Some slimming sessions are certainly in order here! Let’s take a look at a few alternatives. Before slimming down Prototype, I’ll test the minifiers discussed in this article using my own JavaScript-Commons StringUtils, simply because I have the unit test written for it and I can check for the minification accuracy.
JSMin, The JavaScript Minifier
JSMin is written by none other than Douglas Crockford. After you’ve downloaded it, running it is easy. My StringUtil.js is originally 17,415 bytes. After running it:
C:\Documents and Settings\schemer\jsmin>jsmin <StringUtils.js >MinifiedStringUtis.js
C:\Documents and Settings\schemer\jsmin>dir
03/31/2007 11:52 AM 17,415 StringUtils.js
03/31/2007 12:27 PM 7,379 MinifiedStringUtils.js
Ain’t that sweet? JSMin reduces the size of StringUtils by more than half. But a small JS file is of no use if it’s broken…
And turned out JSMin’s output passed all StringUtils’s JSUnit tests with flying colours. Sweet! It surely looks ugly though…
Now let’s try it with Prototype 1.5.0 and 1.5.1. The result:
C:\Documents and Settings\schemer\jsmin>jsmin <prototype-1.5.0.js >prototype-min-1.5.0.js
C:\Documents and Settings\schemer\jsmin>jsmin <prototype-1.5.1_rc2.js >prototype-min-1.5.1_rc2.js
C:\Documents and Settings\schemer\jsmin>dir
03/31/2007 12:47 PM 71,260 prototype-1.5.0.js
03/31/2007 12:49 PM 54,193 prototype-min-1.5.0.js
03/31/2007 12:47 PM 94,024 prototype-1.5.1_rc2.js
03/31/2007 12:49 PM 70,353 prototype-min-1.5.1_rc2.js
Hmmm, not bad. 24% and 25% for 1.5.0 and 1.5.1_rc2, respectively. Douglas Crockford is a very intelligent guy, but the fact that JSMin does its minification using text manipulation means that we can’t be sure that the result of JSMin will be 100% functionally identical to the original file. For minification fidelity, we have Dojo ShrinkSafe.
Shrink Your JavaScript Safely
First of all, if all you care about is just slimming your JavaScript file RIGHT NOW, go here to do it without any download or configuration whatsoever. The compression result of the three files above are shown below (note that the online compressor seems to have a maximum file name length set to 31–as you can see the name of the shrunk prototype 1.5.2 gets truncated in the beginning):
C:\Documents and Settings\schemer\shrinksafe>dir
03/31/2007 11:52 AM 17,415 StringUtils.js
03/31/2007 12:27 PM 7,379 MinifiedStringUtils.js
04/01/2007 10:18 AM 6,762 StringUtils.compressed.js
03/31/2007 12:47 PM 94,024 prototype-1.5.1_rc2.js
03/31/2007 12:49 PM 70,353 prototype-min-1.5.1_rc2.js
04/01/2007 10:22 AM 64,332 ototype-1.5.1_rc2.compressed.js (truncated name?)
03/31/2007 12:47 PM 71,260 prototype-1.5.0.js
03/31/2007 12:49 PM 54,193 prototype-min-1.5.0.js
04/01/2007 10:21 AM 49,059 prototype-1.5.0.compressed.js
So, Dojo ShrinkSafe actually outperforms JSMin in all cases. Not surprising, because instead of doing text manipulation, Dojo ShrinkSafe is based on Rhino, a true JavaScript engine. Which means that ShrinkSafe has much more knowledge about your JavaScript file compared to your regular text manipulation compressor–it knows with a lot more certainty the context of a variable, function, and so on.
Ah, so there. Next time I’m creating another release of JavaScript-Commons, I know which compressor I’ll be using.