2007년 7월 26일 목요일

Teaching IronRuby math tricks

The first release of IronRuby brought a lot of buzz, and in my opinion rightly so. However, if you expect it to run Rails, seemlessly integrating ASP.NET widgets today, I must say you're delusional. Have you tried to run it at all? People, there are reasons why it is versioned Pre Alpha.

In the post titled "Is IronRuby mathematically challenged?", Antonio Cangiano rightfully complains of these fads. He writes:

Well, I was very interested in trying out IronRuby, but I immediately discovered that it is very crippled from a mathematical standpoint, even for a pre-alpha version. (...) However after running some simple tests, it is clear that a lot of work is required in order for this project to live up to the buzz that is being generated online about it, when you take into account that even some simple arithmetic functionalities are either flawed or missing altogether.


To be fair, the focus of this release is working method dispatch core and built-in class Array and String, as John Lam himself wrote. But it is understandable for people to worry that these problems may be difficult to remedy. Fortunately, it is not the case, as I will demonstrate below.

Remember, IronRuby is open source, so you can fix problems yourself. Can't divide two floating numbers? It turns out to be as easy as adding one-line method to FloatOps class. Big numbers don't work? Conviniently, DLR provides a high performance class to deal with arbitrary precision arithmetic, namely Microsoft.Scripting.Math.BigInteger. This is how Python long type is implemented in IronPython.

Without further ado, here's a small patch (34 lines added, 1 lines deleted) to remedy problems Antonio pointed out. I think you will be able to understand it even if you don't know C#! It's that simple.

http://sparcs.kaist.ac.kr/~tinuviel/download/IronRuby/pre-a1/patch-math

If you are using a certain operating system which lacks such a basic tool like patch, I heartily recommend you to head to GnuWin32 and get it. Add it to your PATH. Let's assume that you extracted the zip file to C:\. You need to pass --binary option to patch because of different line endings; I generated the patch on Linux.

C:\IronRuby-Pre-Alpha1>patch --binary -p1 < patch-math
patching file Src/Ruby/Builtins/Bignum.cs
patching file Src/Ruby/Builtins/FixnumOps.cs
patching file Src/Ruby/Builtins/FloatOps.cs

After that, you need to build ClassInitGenerator. This is necessary because the patch adds new methods to built-in classes.

C:\IronRuby-Pre-Alpha1>cd Utils\ClassInitGenerator
C:\IronRuby-Pre-Alpha1\Utils\ClassInitGenerator>msbuild

Now it is built, you need to run it to regenerate Initializer.Generated.cs. There is a batch file to do this, GenerateInitializers.cmd, but for some inexplicable reasons it won't work because it got the parent directories(..) one too many. It seems that they haven't tested this.

C:\IronRuby-Pre-Alpha1\Utils\ClassInitGenerator>cd ..\..
C:\IronRuby-Pre-Alpha1>Bin\Debug\ClassInitGenerator > Src\Ruby\Builtins\Initializer.Generated.cs

Now to the main build.

C:\IronRuby-Pre-Alpha1>msbuild

Let's test! Did IronRuby learn the math we taught?

C:\IronRuby-Pre-Alpha1>cd Bin\Debug
C:\IronRuby-Pre-Alpha1\Bin\Debug>rbx

IronRuby Pre-Alpha (1.0.0.0) on .NET 2.0.50727.832
Copyright (c) Microsoft Corporation. All rights reserved.
>>> 1/3.0
=> 0.333333333333333
>>> 1.0/3.0
=> 0.333333333333333
>>> 2**3
=> 8
>>> 1_000_000 * 1_000_000
=> 1000000000000
>>> exit

It did!