# Math.BigMul Exposed

Today a friend and I were reflecting through System.Math (courtesy of IronPython) and we noticed the BigMul method:

`Math.BigMul(Int32, Int32) : Int64`

Why have a method just for multiplication? It seems to be a trivial reason to add a method to the .NET framework. After all, multiplication with casting does the same thing:

`(long)a * (long)b`

Being optimistic, I suggested that perhaps Microsoft’s BigMul is implementing a faster and more efficient multiplication algorithm. Maybe there is a clever way to multiply two 32 bit numbers without explicit casting to 64 bit. Naturally, I wrote a simple speed test.

`static void Main(string[] args)`
`{`
`    int a = 40993;`
`    int b = 69872;`
`    long c = 0;`
`    DateTime start;`
`    TimeSpan length;`
`    Console.WriteLine("Inline multiplication");`
`    start = DateTime.Now;`
`    for (int i = 0; i < 1000000000; i++)`
`        c = (long)a * (long)b;`
`    length = DateTime.Now - start;`
`    Console.WriteLine(c);`
`    Console.WriteLine(length.ToString());`
`    Console.WriteLine();`
`    Console.WriteLine("Math.BigMul");`
`    start = DateTime.Now;`
`    for (int i = 0; i < 1000000000; i++)`
`        c = Math.BigMul(a, b);`
`    length = DateTime.Now - start;`
`    Console.WriteLine(c);`
`    Console.WriteLine(length.ToString());`
`    Console.WriteLine();`
`    Console.Read();`
`}`

The results were not encouraging.

```Inline multiplication
2864262896
00:00:03.9375000

Math.BigMul
2864262896
00:00:07.2031250```

Then I remembered to do a Release build and run without debugging. :-D The real results:

```Inline multiplication
2864262896
00:00:01.9218750

Math.BigMul
2864262896
00:00:01.9375000```

After running it several times, I saw that they had basically the same performance. This begs the question: why did Microsoft even include BigMul? I cracked open Reflector and checked out the code myself. What I found surprised me.

`public static long BigMul(int a, int b)`
`{`
`    return (a * b);`
`}`

That looks like an unsafe operation to me! Disturbed, I wrote and tested my own static method using the exact same code (named BigMul2). Sure enough, my copy-cat code overflowed. Puzzled, I looked at the IL code for both methods:

`.method public hidebysig static int64 BigMul(int32 a, int32 b) cil managed`
`{`
`    .maxstack 8`
`    L_0000: ldarg.0`
`    L_0001: conv.i8`
`    L_0002: ldarg.1`
`    L_0003: conv.i8`
`    L_0004: mul`
`    L_0005: ret`
`}`
`.method public hidebysig static int64 BigMul(int32 a, int32 b) cil managed`
`{`
`    .maxstack 8`
`    L_0000: ldarg.0`
`    L_0001: ldarg.1`
`    L_0002: mul`
`    L_0003: conv.i8`
`    L_0004: ret`
`}`

Do you see the difference? Math.BigMul pushes a on the stack, casts a to long, pushes b on the stack, casts b to long, multiples them together and returns the result. This is a correct algorithm for multiplying two ints (but not what Reflector initially indicated). My BigMul2 method pushes a on the stack, then pushes b, multiples, then casts to long and returns the result. Apparently Reflector didn’t properly translated the code into C#. The actual C# code used by BigMul is exactly what you would expect it to be, there is nothing special going on here.

`public static long BigMul(int a, int b)`
`{`
`    return (long)a * (long)b;`
`}`

# What does this all mean?

I learned a few things from this exercise.

• Microsoft felt the need to include the trivial BigMul method although it does nothing special. It probably exists as a Best Practice device to ensure that integer multiplication is cast correctly.
• Reflector is not reliable. It apparently drops cast operation under certain conditions. It doesn’t express the cast in C#, VB, Delphi, MC++, or Chrome – only IL. This problem is reproducible, the explicit casts in my speed-test program are also missing when viewed in Reflector.
• I was reminded that debugging incurs a performance hit. What is especially noteworthy is the tremendous slowdown that comes from the debugger as it follows the execution stack into another method (in another assembly).