C# almost double as fast as VB.NET?

Check this out:

C# code:

using System;

class SpectralNorm
{

// // // // Var Def //
static DateTime startTime;
static DateTime stopTime;
static TimeSpan elapsedTime;
static long elapsedMS;

static void Main(String[] args) {
startTime = DateTime.Now;

int n = 1000;
if (args.Length > 0) n = Int32.Parse(args[0]);

Console.WriteLine("{0:f9}", new SpectralNorm().Approximate(n));
stopTime = DateTime.Now; elapsedTime = stopTime.Subtract(startTime);
elapsedMS = (long)elapsedTime.TotalMilliseconds;
Console.WriteLine("Elapsed Time: {0}", elapsedMS);
Console.ReadLine();

}

double Approximate(int n) {
// create unit vector
double[] u = new double[5000];
for (int i=0; i<n; i++) uIdea = 1;

// 20 steps of the power method
double[] v = new double[5000];
for (int i=0; i<n; i++) vIdea = 0;

for (int i=0; i<10; i++) {
MultiplyAtAv(ref n, ref u, ref v);
MultiplyAtAv(ref n, ref v, ref u);
}

// B=AtA A multiplied by A transposed
// v.Bv /(v.v) eigenvalue of v
double vBv = 0, vv = 0;
for (int i=0; i<n; i++) {
vBv += uIdea*vIdea;
vv += vIdea*vIdea;
}

return Math.Sqrt(vBv/vv);
}

/* return element i,j of infinite matrix A */
double A(ref int i, ref int j){
return 1.0/((i+j)*(i+j+1)/2 +i+1);
}

/* multiply vector v by matrix A */
void MultiplyAv(ref int n, ref double[] v, ref double[] Av){
for (int i=0; i<n; i++){
AvIdea = 0;
for (int j=0; j<n; j++) AvIdea += A(ref i, ref j)*v[j];
}
}

/* multiply vector v by matrix A transposed */
void MultiplyAtv(ref int n, ref double[] v, ref double[] Atv){
for (int i=0;i<n;i++){
AtvIdea = 0;
for (int j=0; j<n; j++) AtvIdea += A(ref j,ref i)*v[j];
}
}

/* multiply vector v by matrix A and then by matrix A transposed */
void MultiplyAtAv(ref int n, ref double[] v, ref double[] AtAv){
double[] u = new double[5000];
MultiplyAv(ref n, ref v, ref u);
MultiplyAtv(ref n, ref u, ref AtAv);
}
}

and now for VB:

Option Strict On
Imports System
Class SpectralNorm

Shared startTime As DateTime
Shared stopTime As DateTime
Shared elapsedTime As TimeSpan
Shared elapsedMS As Long

Public Shared Sub Main(ByVal args As String())
startTime = DateTime.Now

Dim n As Integer = 1000
If args.Length > 0 Then
n = Int32.Parse(args(0))
End If
stopTime = DateTime.Now : elapsedTime = stopTime.Subtract(startTime)
elapsedMS = CLng(elapsedTime.TotalMilliseconds)
Console.WriteLine("{0:f9}", New SpectralNorm().Approximate(n))
Console.WriteLine("Time taken: {0}", elapsedMS)

End Sub
Private Function Approximate(ByVal n As Integer) As Double
' create unit vector
Dim u(5000) As Double
For i As Integer = 0 To n - 1
u(i) = 1
Next
' 20 steps of the power method
Dim v(5000) As Double
For i As Integer = 0 To n - 1
v(i) = 0
Next
For i As Integer = 0 To 9
MultiplyAtAv(n, u, v)
MultiplyAtAv(n, v, u)
Next
' B=AtA A multiplied by A transposed
' v.Bv /(v.v) eigenvalue of v
Dim vBv As Double = 0, vv As Double = 0
For i As Integer = 0 To n - 1
vBv += u(i) * v(i)
vv += v(i) * v(i)
Next
Return Math.Sqrt(vBv / vv)
End Function
' return element i,j of infinite matrix A
Private Function A(ByRef i As Integer, ByRef j As Integer) As Double
Return 1 / ((i + j) * (i + j + 1) / 2 + i + 1)
End Function
' multiply vector v by matrix A
Private Sub MultiplyAv(ByRef n As Integer, ByRef v As Double(), ByRef Av As Double())
For i As Integer = 0 To n - 1
Av(i) = 0
For j As Integer = 0 To n - 1
Av(i) += A(i, j) * v(j)
Next
Next
End Sub
' multiply vector v by matrix A transposed
Private Sub MultiplyAtv(ByRef n As Integer, ByRef v As Double(), ByRef Atv As Double())
For i As Integer = 0 To n - 1
Atv(i) = 0
For j As Integer = 0 To n - 1
Atv(i) += A(j, i) * v(j)
Next
Next
End Sub
' multiply vector v by matrix A and then by matrix A transposed
Private Sub MultiplyAtAv(ByRef n As Integer, ByRef v As Double(), ByRef AtAv As Double())
Dim u(5000) As Double
MultiplyAv(n, v, u)
MultiplyAtv(n, u, AtAv)
End Sub
End Class

Now, guess what? Everything on release and optimized, on my AXP, the C# example is a freaking 100 % faster than the VB.NET one!! WTF, Microsoft? This is absolutely ridiculous! I mean, 5-10 %, no problem, but this?!!

[5319 byte] By [irchel] at [2008-1-7]
# 1
wow, sorry for the crappy formatting, remove the lamps with Idea if your editor hasn't already done that for you.

sorry #2:

i f*cked up the VB.net main method:

Public Shared Sub Main(ByVal args As String())
startTime = DateTime.Now

Dim n As Integer = 1000
If args.Length > 0 Then
n = Int32.Parse(args(0))
End If

Console.WriteLine("{0:f9}", New SpectralNorm().Approximate(n))
stopTime = DateTime.Now : elapsedTime = stopTime.Subtract(startTime)
elapsedMS = CLng(elapsedTime.TotalMilliseconds)
Console.WriteLine("Time taken: {0}", elapsedMS)
Console.ReadLine()
End Sub

should be like that, of course. Changes nothing for the result, by the way.

irchel at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 2
ahh damn you, LAMP! (It's getting ridiculous... sorry guys)

LAMP = "[i" & "]". Hope you got that.

irchel at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 3

By default VB.NET performs integer overflow checks on every operation (you can turn these off in Compile->Advanced Compile Options...) whereas C# doesn't. This would account for a large percentage of the difference.

After turning off these checks the VB.NET speed is closer to the C# speed, but C# is still faster. There may be other compiler defaults that will affect the speed of either language.

WilliamBartholomew at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 4
Additionally, if you make both classes have Shared/static methods only, and change all the ref/ByRef to nothing/ByVal (as ref/ByRef is completely unnecessary for this code) the CSharp speed barely changed but the VB.NET speed drops another 200ms.
WilliamBartholomew at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 5

Actually the VB.NET and C# speed is quite the same... the problem is that the code is NOT quite the same... surprised ? Let's see.

Such a big difference suggests only one thing, that some operation that is used heavily performs different. What is this operation ? Well... the only one I see is the function A.

In C# it's

return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1);

In VB.NET it's

return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1)

They look the same but they are not the same. The / operator in VB.NET differs from the / operator in C#. In C# doing 3 / 2 for example will result in the integer 1. In VB.NET doing 3 / 2 will result in the double 1.5. You can check this easily with the following line:

Console.WriteLine((3 / 2).GetType().FullName)

So the subexpression (i + j) * (i + j + 1) / 2 is evaluated by C# using only integer operations (and note that we don't need double anyway because the product of an odd and an even number always divides by 2) but the same expression is evaluated by VB.NET using double operations. Obviously, double operations aren't as fast as integer operations.

For code to be identical the VB.NET expression should be:

return 1.0 / ((i + j) * (i + j + 1) \ 2 + i + 1)

Note the \ operator instead of the / operator. The \ operator does division using integer arithmetic, same like C#.

If you do this small change and what William Bartholomew suggested about integer overflow checks you'll get the same speed...

And William Bartholomew is right, using ref/ByRef is completly useless in this code... but since both C# and VB.NET version use it this does not affect the speed comparison.

MikeDanes at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 6
I just tested Mike's suggestion (I can't believe I didn't spot that), and yes the speed is then identical.
WilliamBartholomew at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 7
Thank you, thank you, thank you. This is absolutely awesome and you saved my day. didn't know about \, didn't even think about it (int vs float). Because I love VB, I would have hated MS for making such a crappy MSIL compiler for it.

I can see that ref is useless here, but it doesn't change anything, right?

UH OH: Question: I assumed there was some overflow check... problem is: I don't have the "Advanced Compiler options" (I'm starting to feel pretty stupid), could that be a limitation of the vb.net express edition?

irchel at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 8
ByRef/ref can lead to a bit slower code and so you should not use it unless you really need it. However in this case it does not seem to make any difference.
MikeDanes at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 9

It may be a limitation of the Express editions, I'm not sure... VB defaults to doing overflow checks, C# defaults to not doing overflow checks...

To turn on overflow checks in C# you need to go to the project properties, then the Build tab, and then the Advanced button in the bottom right-hand corner.

To turn off overflow checks in VB.NET you need to go to the project properties, then the Compile tab, and then the Advanced Compiler Options button.

WilliamBartholomew at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 10
yes, and exactly this Advanced Compiler Options Button just does not exist in VB 2005 Express.
In c# express, it does. Shame on you, MS ;)

This way, I'm stuck to Visual C#, which annoys me a little bit. Well, I could probably use the command line too.

irchel at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 11

If you want to remove the overflow checking in your VB.NET project edit the .vbproj file in an XML editor (or plain old notepad) and in the PropertyGroup section for the configuration you are building (either Debug, Release or Both) add the following:

<RemoveIntegerChecks>true</RemoveIntegerChecks>

I don't think VB Express will override the setting if it is in the project file.

WilliamBartholomew at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 12
thanx so much! You're more or less overriding the idiotic restriction that MS wanted to apply to VB express. Now, VB 8 really p0wns VB 6 in every possible way (well, not memory usage, but we do have enough memory nowadays), which is exactly what I wanted.
irchel at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 13

I would suggest not to make duplicate posts and start some flame war either. This is not acceptable and would also advice to do some research before coming to conclusions.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=732457&SiteID=1

ahmedilyas at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...
# 14
first off, I want to thank you for your fairly motivating approach to teach a coder who - well, neither speaks english as his native language nor has years of background in c# programming.

Concerning the double post, well, you're right. I'm very sorry for that, but it seemed to me that the first post was deleted, which it obviously wasn't.

*do some research* - well, that IS something to consider, but guess what? Maybe someone else who's learning the framework bumped into the same problems as I did, so why not share your knowledge?

I don't think that many beginners in VB.net know about the INteger overflow check issue, for example, as its nowhere mentioned in the Express IDE .

irchel at 2007-10-2 > top of Msdn Tech,Visual Studio Express Editions,Visual C# 2005 Express Edition...