Making variables in a procedure global - vb.net

I know the title seems pretty trivial but i have an issue and i can't seem to get round it, i have the following code within one sub procedure..
Dim X, Y As Integer
X = 32
Y = 285
X_coords(0) = X ' x1 (a1)
X_coords(1) = X - 13 ' x2 (a2)
X_coords(2) = X + 16 ' x3 (a3)
X_coords(3) = X + 63 ' x4 (b1)
X_coords(4) = X + 45 ' x5 (b2)
X_coords(5) = X + 74 ' x6 (b3)
X_coords(6) = X + 124 ' x7 (c1)
X_coords(7) = X + 103 ' x8 (c2)
X_coords(8) = X + 132 ' x9 (c3)
X_coords(9) = X + 63 ' x10 (b4)
X_coords(10) = X + 76 ' x11 (y3)
X_coords(11) = X + 21 ' x12 (n1)
X_coords(12) = X + 9 ' x13 (q1)
X_coords(13) = X + 65 ' x14 (q3)
X_coords(14) = X + 117 ' x14 (q5)
X_coords(15) = X + 87 ' x14 (q4)
X_coords(16) = X + 31 ' x13 (q2)
X_coords(17) = X + 139 ' x13 (q6)
X_coords(18) = X + 76 ' x13 (q6)
X_coords(19) = X + 129 ' x13 (q6)
Y_coords(0) = Y ' y1s1
Y_coords(1) = Y - 23 ' y1s2
Y_coords(2) = Y - 11.5 ' y1,2s
Y_coords(3) = Y - 47 ' y2s1
Y_coords(4) = Y - 70 ' y2s2
Y_coords(5) = Y - 59 ' y2,2s
Y_coords(6) = Y - 132 ' y4s1
Y_coords(10) = Y - 152 ' y4s2
Y_coords(7) = Y - 140 ' y4 30cred
Y_coords(8) = Y - 127 ' y4s1, 10cred
Y_coords(9) = Y - 105 ' y3
Dim a1 As New posData("a1", X_coords(0), Y_coords(0))
Dim a2 As New posData("a2", X_coords(1), Y_coords(0))
Dim a3 As New posData("a3", X_coords(2), Y_coords(0))
Dim a4 As New posData("a4", X_coords(0), Y_coords(0))
I do know how to create global variable within your class, I want to make a1, a2 etc global but they must take the values of the said X_coords and Y coords, i dont know how to make this global so that it will do so.. the values are blank because i cannot initialize them globally?
Any Help?

Declare a1, a2... as a global variable (whatever you mean by global). Then in the class' constructor you can assign a value to them:
Sub New()
'....
a1 = New ...
'....
If these variables are shared, you can use the shared constructor.
If the variables need to be recalculated, it probably would be a good idea to make them readonly properties.

The question would be global to what? The class itself?
Public Class MyClass
Private a1 As posData
Private a2 As posData
Private a3 As posData
Private a4 As posData
Public Function SetVariables()
'blah blah
a1 = New posData("a1", X_coords(0), Y_coords(0))
a2 = New posData("a2", X_coords(1), Y_coords(0))
a3 = New posData("a3", X_coords(2), Y_coords(0))
a4 = New posData("a4", X_coords(0), Y_coords(0))
End Function
End Class
The variables are available to any function in the current instance of that class.
Global to your application?
Public Class MyClass
Public Shared a1 As posData
Public Shared a2 As posData
Public Shared a3 As posData
Public Shared a4 As posData
Public Function SetVariables()
'blah blah
a1 = New posData("a1", X_coords(0), Y_coords(0))
a2 = New posData("a2", X_coords(1), Y_coords(0))
a3 = New posData("a3", X_coords(2), Y_coords(0))
a4 = New posData("a4", X_coords(0), Y_coords(0))
End Function
End Class
Now they are static and shared across all instances of the class.
Hope that helps.

Related

Adding 4 byte values causes Overflow Exception

The following code raises a System.OverflowException
Dim b1 As Byte = 13
Dim b2 As Byte = 26
Dim b3 As Byte = 125
Dim b4 As Byte = 225
Dim i As Integer = (b1 + b2 + b3 + b4) \ 2
Why does this happen?
The value(s) doesn't get converted into an Integer until you assign it to the variable. This means that up until, and including, the \ 2 part everything is still of type Byte.
To make this work you've got to convert at least the first variable into an Integer, so that additional numbers can be added to it and go beyond 255.
Dim i As Integer = (CType(b1, Integer) + b2 + b3 + b4) \ 2
Online test: https://dotnetfiddle.net/Lxmx2S
Be aware that since this respects the order of mathematical operations, you must convert all the instances of too small types that are calculated before the others. For instance if you changed your operation to this:
Dim i As Integer = (CType(b1, Integer) + b2 * b3 + b4) \ 2
It would also throw an error because b2 * b3 is calculated before b1 + b2, and thus you would have to change it to:
Dim i As Integer = (CType(b1, Integer) + CType(b2, Integer) * b3 + b4) \ 2

Any way to call Excel functions in VB.NET as Microsoft.Office.Interop.Excel throws Class not registered (REGB_E_CLASSNOTREG) in Server?

The application needs to use some Excel functions (NormSDist, NormSInv) to calculate some result. There is slight difference between the results by Excel and .NET equivalent of these functions. As it is a banking application the user wants exact match. So by referring Microsoft.Office.Interop.Excel and calling Excel functions NormSDist, NormSInv return exact result.
By referring Microsoft.Office.Interop.Excel
Dim appExcel As Microsoft.Office.Interop.Excel.Application = New Microsoft.Office.Interop.Excel.Application()
Dim wsf As Microsoft.Office.Interop.Excel.WorksheetFunction = appExcel.WorksheetFunction()
decOne = wsf.NormSInv(someValue) + wsf.NormSInv(someValue)
decTwo = 12.5 * wsf.NormSDist(decNorm)
.NET equivalent functions
Public Shared Function NORMSDIST(z As Double) As Double
Dim sign As Double = 1
If z < 0 Then
sign = -1
End If
Return 0.5 * (1.0 + sign * erf(Math.Abs(z) / Math.Sqrt(2)))
End Function
Private Shared Function erf(x As Double) As Double
Dim a1 As Double = 0.254829592
Dim a2 As Double = -0.284496736
Dim a3 As Double = 1.421413741
Dim a4 As Double = -1.453152027
Dim a5 As Double = 1.061405429
Dim p As Double = 0.3275911
x = Math.Abs(x)
Dim t As Double = 1 / (1 + p * x)
Return 1 - ((((((a5 * t + a4) * t) + a3) * t + a2) * t) + a1) * t * Math.Exp(-1 * x * x)
End Function
' This function is a replacement for the Microsoft Excel Worksheet function NORMSINV.
' It uses the algorithm of Peter J. Acklam to compute the inverse normal cumulative
' distribution. Refer to http://home.online.no/~pjacklam/notes/invnorm/index.html for
' a description of the algorithm.
' Adapted to VB by Christian d'Heureuse, http://www.source-code.biz.
Public Shared Function NormSInv(ByVal p As Double) As Double
Const a1 = -39.6968302866538, a2 = 220.946098424521, a3 = -275.928510446969
Const a4 = 138.357751867269, a5 = -30.6647980661472, a6 = 2.50662827745924
Const b1 = -54.4760987982241, b2 = 161.585836858041, b3 = -155.698979859887
Const b4 = 66.8013118877197, b5 = -13.2806815528857, c1 = -0.00778489400243029
Const c2 = -0.322396458041136, c3 = -2.40075827716184, c4 = -2.54973253934373
Const c5 = 4.37466414146497, c6 = 2.93816398269878, d1 = 0.00778469570904146
Const d2 = 0.32246712907004, d3 = 2.445134137143, d4 = 3.75440866190742
Const p_low = 0.02425, p_high = 1 - p_low
Dim q As Double, r As Double
Dim strErrMsg As String = ""
If p < 0 Or p > 1 Then
strErrMsg = "NormSInv: Argument out of range."
ElseIf p < p_low Then
q = Math.Sqrt(-2 * Math.Log(p))
NormSInv = (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /
((((d1 * q + d2) * q + d3) * q + d4) * q + 1)
ElseIf p <= p_high Then
q = p - 0.5 : r = q * q
NormSInv = (((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q /
(((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1)
Else
q = Math.Sqrt(-2 * Math.Log(1 - p))
NormSInv = -(((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) /
((((d1 * q + d2) * q + d3) * q + d4) * q + 1)
End If
End Function
But as Excel is not in the server, it throws
Retrieving the COM class factory for component with CLSID{} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG))
Is there any way to use Excel functions in .NET or is there any library to consume these Excel functions?
Note: This application just requires the Excel functions and it doesn't interact with any excel files
MathNet.Numerics library (https://numerics.mathdotnet.com/) works as expected.
Install-Package MathNet.Numerics -Version 3.20.0
In .vb file,
Imports MathNet.Numerics
As ExcelFunctions is a static class, directly call the methods as
decOne = ExcelFunctions.NormSInv(someValue) + ExcelFunctions.NormSInv(someValue)
decTwo = 12.5 * ExcelFunctions.NormSDist(decNorm)
The below link has the list of methods available
https://numerics.mathdotnet.com/api/MathNet.Numerics/ExcelFunctions.htm

VB.NET spirograph program

I'm trying to create a a program that will draw hypotrochoids (spirograph). The program below compiles fine. But when I run it I only get a portion of the drawing.. I'm not sure what I'm doing wrong. I'm fairly new to VB.. Any help is appreciated. Thanks.
Here is the screenshot http://imgur.com/a/KxFWk
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
Dim x As Integer
Dim y As Integer
Dim p As Integer
Dim x1 As Integer
Dim y1 As Integer
Dim x2 As Integer
Dim y2 As Integer
x = 75
y = 15
p = 15
x1 = (x + y) * Math.Cos(0) + p * Math.Cos(0)
y1 = (x + y) * Math.Sin(0) + p * Math.Sin(0)
For t = 0 To 500 Step 0.1
x2 = (x + y) * Math.Cos(t) + p * Math.Cos((x + y) * t / y)
y2 = (x + y) * Math.Sin(t) + p * Math.Sin((x + y) * t / y)
e.Graphics.DrawLine(Pens.Blue, x1, y1, x2, y2)
x1 = x2
y1 = y2
Next
End Sub
End Class
The results of the Sin and Cos calculations result in negative numbers where the parameter is greater than 90 for cos and greater than 180 for sin.
To see the whole image, you need to change the offset for x2 and y2 - see the code below. Alter the number 200 in each of the four lines to a value appropriate for your picturebox
x1 = 200 + CInt((x + y) * Math.Cos(0) + p * Math.Cos(0))
y1 = 200 + CInt((x + y) * Math.Sin(0) + p * Math.Sin(0))
For t As Double = 0 To 500 Step 0.1
x2 = 200 + CInt((x + y) * Math.Cos(t) + p * Math.Cos((x + y) * t / y))
y2 = 200 + CInt((x + y) * Math.Sin(t) + p * Math.Sin((x + y) * t / y))
e.Graphics.DrawLine(Pens.Blue, x1, y1, x2, y2)
x1 = x2
y1 = y2
Next

Return a array of result from function

Private Function lang_array(ByVal temp As Double) As Double
'This program call the subroutine langmuir to calculate langmuir constants
'of each molecule for the small cage and for the large cage
Dim molenum As Integer = 1 ' Number of molecular species
Dim sigma(10) As Double ' value of sigma for each species
sigma(0) = 0.00000000030197
Dim radius(10) As Double ' value of core radius for each species
radius(0) = 0.000000000072
Dim edep_div_k(10) As Double ' value of energy depth/k for each species
edep_div_k(0) = 171.3
Dim z_small As Double = 20 ' coordination number for small cage
Dim z_large As Double = 24 'coordination number for large cage
Dim r_small As Double = 0.000000000391 ' radius of small cage
Dim r_large As Double = 0.000000000433 ' radius of large cage
Dim n_small As Double = 1.0 / 23.0 'number of small cage per one water molecule
Dim n_large As Double = 3.0 / 23.0 'number of large cage per one water molecule
'In langmuir constant array c[k][i], suffix k changes with molecular species
' and suffix i changes with cavity type
'In suffix i, 0 indicates small cavity and 1 indicates large cavity.
Dim c1, c2, c3, c4, c5 As Double
Dim c(2, 2) As Double
Dim k As Integer
For k = 0 To molenum
c1 = z_small
c2 = r_small
c3 = sigma(k)
c4 = radius(k)
c5 = edep_div_k(k)
c(k, 0) = langmuir(temp, c1, c2, c3, c4, c5)
Next
' Calculate langmuir constant for large cavity
For k = 0 To molenum
c1 = z_large
c2 = r_large
c3 = sigma(k)
c4 = radius(k)
c5 = edep_div_k(k)
c(k, 1) = langmuir(temp, c1, c2, c3, c4, c5)
Next
**Return (c)**
End Function
' All I am trying to return the value of array (c(k,0) & c(k,1)) but I unable to do that. Can you help please
change the signature to:
Private Function lang_array(ByVal temp As Double) As Double(,)
should work then

What could be slowing down my Excel VBA Macro?

This function goes through all integers and picks out binary values with only five ones and writes them to the spreadsheet.
To run this For x = 1 To 134217728 would take 2.5 days!!!! Help!
How could I speed this up?
Function D2B(ByVal n As Long) As String
n = Abs(n)
D2B = ""
Do While n > 0
If n = (n \ 2) * 2 Then
D2B = "0" & D2B
Else
D2B = "1" & D2B
n = n - 1
End If
n = n / 2
Loop
End Function
Sub mixtures()
Dim x As Long
Dim y As Integer
Dim fill As String
Dim mask As String
Dim RowOffset As Integer
Dim t As Date
t = Now
fill = ""
For x = 1 To 134217728
mask = Right(fill & CStr(D2B(x)), Len(fill & CStr(D2B(x))))
Debug.Print mask
If x > 100000 Then Exit For
If Len(mask) - Len(WorksheetFunction.Substitute(mask, "1", "")) = 5 Then _
RowOffset = RowOffset + 1
For y = 1 To Len(mask)
If Len(mask) - Len(WorksheetFunction.Substitute(mask, "1", "")) = 5 Then _
Range("mix").Offset(RowOffset).Cells(y) = Mid(mask, y, 1)
Next
Next
Debug.Print DateDiff("s", Now, t)
End Sub
By first sight guess, I think the problem lies in the fact that you do that cell by cell, which causes many read and write accesses.
You should do it range by range, like
vArr = Range("A1:C1000").Value
' it is array now, do something here effeciently
Range("A1:C1000").Value = vArr
You want find all 28bit numbers with 5 1s
There are 28*27*26*25*24/5/4/3/2=98280 such numbers
The following code took ~10 seconds on my PC:
lineno = 1
For b1 = 0 To 27
For b2 = b1 + 1 To 27
For b3 = b2 + 1 To 27
For b4 = b3 + 1 To 27
For b5 = b4 + 1 To 27
Cells(lineno, 1) = 2 ^ b1 + 2 ^ b2 + 2 ^ b3 + 2 ^ b4 + 2 ^ b5
lineno = lineno + 1
Next
Next
Next
Next
Next
mask = Right(fill & CStr(D2B(x)), Len(fill & CStr(D2B(x))))
The above line of code does the same thing (CStr(D2B(x))) twice.
Store the result of CStr(D2B(x)) in a variable & use that variable in the above line of code.
I've got 2 suggestions:
Get rid of the substitution command by counting the ones/zeroes in D2B and return an empty string if the count does not equal 5
Write these pre-filtered bitstrings to an array first and copy the array directly to the cells when finished.
Something like
ws.Range(ws.cells(1, 1), ws.cells(UBound(dstArr, 1) + 1, UBound(dstArr, 2) + 1)) = dstArr
The array-copy-trick greatly improves performance!