By Brad Gile

salmonbrisketSoftware and s/w Development

Nov 2, 2013 (4 years and 11 months ago)

549 views

RAW PERFORMANCE: VB6.0 VS. VB.NET AND C#

By Brad Gile

(
http://www.vb
-
faq.com/Articles/Gile/raw_performance.asp

)



Microsoft introduced the .NET framework and language specifications

for it that seemed
to place high emphasis on (1) web services and applications or (2) database applications
on the desktop. This, of course, is quite natural because almost all apps fall into one of
these categories. There are, however, VB programmers who

write good old fashioned
extreme number crunching mathematical apps, who might reasonably ask, “OK, so
VB.NET (or C#) is great. Will I lose performance with pure mathematical apps if I move
from VB 6 to VB.NET or C#?”



This question was my primary concer
n, so I decided to test it after the
final release of Visual Studio.NET. I have been programming in Visual
Basic since version 1.0 and various DOS versions of BASIC since the
early 1980s, so I have a very strong interest in the question whether
VB.NET (or
C#) traded mathematical performance for other features.



The answer, in short, is a resounding “NO!”. Just the opposite! Here
are the basic results of my testing:

1.

Run times may be cut by 50% or more using VB.NET or C#.


2.

It doesn’t matter which language y
ou use. C# and VB.NET
generate essentially the same performance.




In my testing, I wanted to use code that would be useful in a real application. So, I
decided to use the most important probability distribution in mathematics: the Standard
Normal Distrib
ution and its Inverse. These functions are central to statistical analyses and
Monte Carlo simulations. It was, of course, helpful that I already had VB 6 code for
these.



The test itself is quite simple. From a command button, generate 100,000 numbers th
at
are normally distributed with mean zero and variance 1. This is done by selecting
100,000 values between zero and 1 and calculating the Standard Normal Inverse of each
one. I selected 100,000 as a number that would be large enough that would take at le
ast a
couple seconds to loop through with my 2.0 Ghz Pentium 4. The time taken to do this is
displayed in a text box.



The Results on my PC: Execution times of 3.475 seconds in VB 6, 1.162 seconds in
VB.NET and the 1.232 seconds in C#
! Both .NET versions
were compiled in release
mode, and the VB 6 code was compiled with all error checking removed!

This result is nothing less than astonishing! We get a 65% reduction in
run time, and the difference between VB.NET and C# is negligible!
Now this is not to say
that there are no differences between VB.NET
and C#; there undoubtedly are, but Microsoft has stated that
performance differences between the two should be minimal. This is
the case here.



But the differences between VB6 and VB.NET/C# with respect to pu
re
performance are HUGE! This is undoubtedly due to both (1) new
compilers and (2) the new and massive .NET framework for which they
are designed.



The code in each of the three languages is shown below. The code
itself is quite straightforward, but I do

have a few comments on it.

VB.NET does allow you to use legacy VB6 code using Option Explicit
instead of Option Strict AND has a whole namespace for backward
compatibility with VB6. In my analysis here (and in ALL VB.NET code I
write), I use Option Strict

everywhere and I do not invoke the special
namespace for legacy code. I do this because it seems logical and
likely that constructs designed to support legacy VB 6 code will either
not work sometime in the future or cause hard to find bugs. Moreover,
for
new code, such crutches are totally unnecessary.



C# has no options because it is, by default, a strongly typed language.
C# also has no exponentiation operator and must use the Math.pow
function. Accordingly, I did the VB.NET code using both the usual ^
operator and, alternatively, Math.pow as shown here. There is no
difference in performance between the two.



THE CODE:



1.

VB 6.0




Option Explicit

Private Declare Function GetTickCount Lib "kernel32" () As
Long



Private Sub Command1_Click()

Dim BeginTime

As Long, EndTime As Long

Dim J As Long

Dim X As Double, Y As Double

Dim z As Double

'Create 100,000 Normally Distributed numbers with

'Mean 0 and Standard Deviation 1.

'VB 6.0 Version..................................

'THIS WILL BE DONE IN VB.NET AND C# F
OR COMPARISON!



BeginTime = GetTickCount()

For J = 1 To 100000

X = 0.00001 * (J
-

0.5)

Y = StandardNormalInverse(X)

Next J

EndTime = GetTickCount()

z = 0.001 * (EndTime
-

BeginTime)

Text1.Text = "Run time = " & CStr(z) & " seconds."



End Sub



Option Exp
licit

Public Const Pi As Double = 3.14159265358979



Private Function Density(ByVal X As Double) As Double

Density = 1 / (2 * Pi) ^ 0.5 * Exp(
-
0.5 * X ^ 2)

End Function



Public Function StandardNormal(ByVal X As Double) As Double

Dim a(4) As Double, K As
Double

Dim L As Double

Dim q As Double

Dim nx As Double

Dim SND As Double

Dim J As Integer

Dim S As Double



a(0) = 0.31938153

a(1) =
-
0.356563782

a(2) = 1.781477937

a(3) =
-
1.821255978

a(4) = 1.330274429

K = 0.2316419

L = Abs(X)

q = 1 / (1 + K * L)

nx = D
ensity(L)



'nx == f(abs(x))



For J = 0 To 4

S = S + a(J) * q ^ (J + 1)

Next J



SND = 1
-

nx * S

'SND = PHI(abs(x))



If (X < 0) Then

SND = 1
-

SND

End If



'NOW SND = PHI(x)



StandardNormal = SND



End Function



Public Function StandardNormalInverse(B
yVal R As Double) As
Double


Dim Delta As Double


Dim X As Double, Y As Double




X = 0


Delta = 1


Do Until Delta <= 0.000000001




Y = X
-

(StandardNormal(X)
-

R) / Density(X)





Delta = Abs(Y
-

X)




X = Y


Loop




StandardNormalInverse = Y




End Function

**************END VB 6.0 CODE******************



2.

VB.NET




Option Strict On



Private Sub But
ton1_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles Button1.Click


Dim BeginTime As Long, EndTime As Long


Dim J As Long


Dim X As Double, Y As Double


Dim z As Double




'Create 100,000 Normally

Distributed numbers with


'Mean 0 and Standard Deviation 1.


'VB.NET Version..................................


BeginTime = System.Environment.TickCount()


For J = 1 To 100000


X = 0.00001 * (J
-

0.5)


Y =

NormalFunctions.StandardNormalInverse(X)


Next J


EndTime = System.Environment.TickCount()


z = 0.001 * (EndTime
-

BeginTime)


TextBox1.Text = "Run time = " & CStr(z) & "
seconds."


End Sub



Public Class NormalFunctions



Private Shared Function Density(ByVal X As Double) As
Double


Dim Y As Double


Y = Math.Pow(2 * Math.PI,
-
0.5) * Math.Exp(
-
0.5 * X
* X)


Return Y


End Function


Public Shared Function StandardNormal(ByVal X As
Double) As Double


Dim a(4) As Double, K As Double


Dim L As Double


Dim q As Double


Dim nx As Double


Dim SND As Double


Dim J As Integer


Dim S As Double




a(0) = 0.31938153


a(1) =
-
0.356563782


a(2)

= 1.781477937


a(3) =
-
1.821255978


a(4) = 1.330274429


K = 0.2316419


L = Math.Abs(X)


q = 1 / (1 + K * L)


nx = Density(L)


'nx == f(abs(x))




For J = 0 To 4


S = S + a(J) * q ^ (J + 1)


Next J




SND = 1
-

nx * S


'SND = PHI(abs(x))




If (X < 0) Then


SND = 1
-

SND


End If


'NOW SND = PHI(x)




Return SND




End Function




Public Shared Function StandardNormalInverse(By
Val R As
Double) As Double


Dim Delta As Double


Dim X As Double, Y As Double




X = 0


Delta = 1


Do Until Delta <= 0.000000001


Y = X
-

(StandardNormal(X)
-

R) / Density(X)


Delta = Math.Abs(Y
-

X)



X = Y


Loop




Return Y




End Function



End Class

*****************END VB.NET CODE***************



3.

C#:




private void button1_Click(object sender, System.EventArgs
e)



{




int BeginTicks=System.Environment.TickCount;





for(int j=1
;j<100001;j++)





{






double x=.00001*(j
-
.5);






double
y=NormalFunctions.StandardNormalInverse (x);







}




int EndTicks=System.Environment.TickCount;





double Elapsed=.001*(EndTicks
-
BeginTicks);




textBox1.Text ="Run Time = " +
Elapsed.ToStri
ng ();





using System;



namespace CsharpNormal

{


/// <summary>


/// Summary description for NormalFunctions.


/// </summary>


public class NormalFunctions


{




//Define density function as private static



private static double Density(double x)



{do
uble y=Math.Pow (2*Math.PI ,
-
.5)*Math.Exp(
-
.5*x*x);




return y;



}


//Define cumulative distribution as public static



public static double StandardNormal(double x)



{




double [] a=new double[5];




a[0]=.31938153;




a[1]=
-
.356563782;




a[2]=1.7814
77937;




a[3]=
-
1.821255978;




a[4]=1.330274429;






double K=.2316419;




double L=Math.Abs(x);




double nx=Density(L);




double q=1/(1+K*L);




double S=0;




for(int j=0;j<5;j++)




{





S+= a[j]*Math.Pow(q,j+1);




}




double SND=1
-
nx*S;




if(x<
0)




{





SND=1
-
SND;




}




return SND;





}















public static double StandardNormalInverse(double R)



{




double Delta=1;




double X=0;




double Y=0;




do




{





Y=X
-
(StandardNormal(X)
-
R)/Density(X);





Delta=Math.Abs (Y
-
X);





X=
Y;




}




while (Delta>.000000001);







return Y;





}





public NormalFunctions()



{




//




// TODO: Add constructor logic here




//



}



}




}



***************END C# CODE********************