Module Module1
Sub Main()
'program to display whether first number is divisible by second
Dim a, b As Integer
Console.WriteLine("enter first number ::")
Console.ReadLine(a).ToString()
Console.WriteLine("enter second number ::")
Console.ReadLine(b).ToString()
If a Mod b = 0 Then
Console.WriteLine("numbers are divisible!")
Else
Console.WriteLine("numbers are not divisible!")
End If
Console.ReadLine()
End Sub
End Module
I am having trouble getting past the first if statement. When I execute the program it doesn't display further information it just inputs the values and freezes. I am a newbie in visual basic, but I don't under stand whats going on.
Change if a Mod b=0 to if a Mod b==0
By using single = you are basically assigning the value instead of checking
Related
Hi all I have the strangest type mismatch in my VB Script. I have no idea what to do.
I define my global variables up top.
Preamble:
Public intX, intY, firstX,firstY
intX = CInt(InputBox("Set X Coordinate above ONE in Excel to Start pasting"))
intY = CInt(InputBox("Set Y Coordinate above ONE in Excel to Start pasting"))
firstX = intX
firstY = intY
firstY = CInt(firstY)
I then have some code running here (note:firstY and firstX go untouched, they are treated as anchors, in a way). Then I have the below loop which adds rows based on the count of existing rows (intY becoming the delimiter for the loop) and certain arguments. firstY exists to help this loop retrace to the starting position of the excel sheet so it can work its way down.
Dim x, y, adder, i
adder=1
i=0
x=0
y=0
Do While x<intY
If ws.Cells(firstY, IntX+3)+ws.Cells(firstY,IntX+5)>1 Then
adder=ws.Cells(firstY, IntX+3)+ws.Cells(firstY,IntX+5)-1
For i = 1 to adder
ws.Cells(firstY+1,IntX).EntireRow.Insert
Next
End If
firstY=firstY+adder+1
adder=0
x=x+1
Loop
I get the error Type mismatch: '[string: ""]' on line If ws.Cells(firstY, IntX+3)+ws.Cells... Then
Any ideas as to why this is occuring?
When I print the types they actually look OK (all int, but eventually firstY becomes type double as the loop keeps going)
' MsgBox TypeName(firstY) &" " & TypeName(x) &" " & TypeName(intY)
I'm sorry if I come off like a coding cretin but I really don't know what to do here.
Any help in troubleshooting is appreciated.
I have a dataset of names in a column in Excel.
However, only some but not all of the names have a letter attached to the end of it (e.g. John Doe A, Kai Jin, Johnny Desplat Lang B, etc).
Can anyone think of a method to remove the letter from the end of the name from each row, if it is there? Such that, using the example above, I will be left with: John Doe, Kai Jin, Johnny Desplat Lang, etc.
I am fairly familiar with VBA and Excel and would be open to trying anything at all.
Thank you for your help with this question! Apologies beforehand if this seems like an elementary question but I have no idea how to begin to solve it.
"I am fairly familiar with VBA and Excel and would be open to trying anything at all."
If so, then this can be done with a simple formula if you wish to avoid VBA. With your value in A1:
=IF(MID(A1,LEN(A1)-1,1)=" ",LEFT(A1,LEN(A1)-2),A1)
If you must use VBA, I think the Like operator comes in handy:
Sub Test()
Dim arr As Variant: arr = Array("John Doe A", "Kai Jin", "Johnny Desplat Lang B")
For Each el In arr
If el Like "* ?" Then 'Or "* [A-Z]" if you must check for uppercase alpha.
Debug.Print Left(el, Len(el) - 2)
Else
Debug.Print el
End If
Next
End Sub
Just for fun and in order to demonstrate another approach via the Filter() function:
Function ShortenName(ByVal FullName As Variant) As String
'Purpose: remove a single last letter
Dim n: n = Split(FullName, " "): n = Len(n(UBound(n)))
ShortenName = Left(FullName, Len(FullName) + 2 * (n = 1))
End Function
Explanation
Applying the Split() function upon the full name and isolating the last name token (via UBound()) allows to check for a single letter length (variable n).
The function result returns the entire string length minus 2 (last letter plus preceding space) in case of a single letter (the the condition n = 1 then results in True equalling -1). - Alternatively you could have coded: ShortenName = Left(FullName, Len(FullName) - IIf(n = 1, 2, 0))
This code used to work, but recently I am getting an error (out of stack space).
I think the code is failing because I am calling a function too many times without exiting/ending.
If that is the case, how many times can you call a function and is there something I can do to fix this?
I am not the original author of this code.
I included the sub where the error occurs.
Sub CalculatePct(e As Variant)
Dim G As Integer
Dim pct As Double
Dim Owned100Pct As Boolean
If entities(e) < 0 Then
pct = 0
Owned100Pct = True ' Keeps track if the entity exists in the table other than as a parent
For G = 1 To UBound(MainArray, 1)
If MainArray(G, colEntity) = e Then
Owned100Pct = False
If entities(MainArray(G, colParent)) = -1 Then
'If we don't know the parent's ownership percentage, go and calculate it
CalculatePct MainArray(G, colParent)
End If
pct = pct + CDbl(MainArray(G, colPct)) / 100 * entities(MainArray(G, colParent))
End If
Next
If Owned100Pct Then
'Assume 100% owned if we don't know the parentage
'("Outside" entities won't go through here as they are already set to 0%)
entities(e) = 1
Else
'Store the entity's percentage
entities(e) = pct
End If
End If
End Sub
A #TimWilliams noted in the comments - you have an endless recursion loop.
Highlighting the problem area:
Sub CalculatePct(e As Variant)
[...]
If entities(MainArray(G, colParent)) = -1 Then
CalculatePct MainArray(G, colParent)
End If
[...]
End Sub
e is the parameter, and entities(e) is checked. In the code, MainParent(G, colParent) is used in place of e, so the next call to the routine gives e = MainParent(G, colParent).
Up to the point in the code, you do not change the value of G, colParent. entities or MainArray. So if entities(MainArray(G, colParent)) = -1 it will be forever calling itself.
Without knowing anything else about the code (including if recursion is necessary) I cannot suggest any definitive solutions. However, some things to consider:
Rewriting to be a loop instead of a recursive call
Making the recursive call to a subset of MainArray
Doing any amendments to G or colParent prior to the recursive
call
You've offered no indication of what line the error occurs on nor what MainArray represents but I'm guessing that MainArray has grown to a size greater than what can be accessed with a signed short integer.
Change the declaration of your iteration variable to a Signed Long Integer. This raises the functional limit of the variable from 32,767 iterations to 2,147,483,647.
Dim G As Long
I'm quite stuck with a fairly simple task but I'm not entirely sure how to make this function. I have a simple string as seen below:
{
"0":{"variable1":"ABC1","variable2":"AA","variable3":"BB"},
"5":{"variable1":"ABC2","variable2":"AA","variable3":"BB"},
"3":{"variable1":"BC3","variable2":"AA","variable3":"BB"},
"1":{"variable1":"DC4","variable2":"AA","variable3":"BB"},
"4":{"variable1":"DD5","variable2":"AA","variable3":"BB"}
}
What I'm trying to do, in VB.NET, is to create a loop that finds each line and arranges those first numbers "0", "1", etc. in order depending on what line it is on then simply replaces whatever number is in it, with the correct order number.
In simple:
1) Find how many number of lines the string has. Let's say 20 lines for example.
2) Find and replace each number within "": starting point of the lines in order 1-20 for this example.
Output would look like if used the example at the top:
{
"2":{"variable1":"ABC1","variable2":"AA","variable3":"BB"}, //"2" because it is the second line within the string
"3":{"variable1":"ABC2","variable2":"AA","variable3":"BB"},
"4":{"variable1":"BC3","variable2":"AA","variable3":"BB"},
"5":{"variable1":"DC4","variable2":"AA","variable3":"BB"},
"6":{"variable1":"DD5","variable2":"AA","variable3":"BB"}
}
Any ideas for a quick fix?
The question may be a case of "I have X and I need Y" where X is the item which needs attention.
If the string really is as you presented it, then
Imports System.Text
Module Module1
Sub Main()
Dim s = "{
""0"":{""variable1"":""ABC1"",""variable2"":""AA"",""variable3"":""BB""},
""5"":{""variable1"":""ABC2"",""variable2"":""AA"",""variable3"":""BB""},
""3"":{""variable1"":""BC3"",""variable2"":""AA"",""variable3"":""BB""},
""1"":{""variable1"":""DC4"",""variable2"":""AA"",""variable3"":""BB""},
""4"":{""variable1"":""DD5"",""variable2"":""AA"",""variable3"":""BB""}
}"
Dim t = s.Split({vbCrLf}, StringSplitOptions.None)
Dim u As New StringBuilder
For i = 0 To t.Length - 1
If t(i).StartsWith("""") Then
Dim parts = t(i).Split({":"c}, 2)
If parts.Count = 2 Then
u.AppendLine($"""{i + 1}"":{parts(1)}")
End If
Else
u.AppendLine(t(i))
End If
Next
Console.WriteLine(u.ToString().TrimEnd())
Console.ReadLine()
End Sub
End Module
outputs:
{
"2":{"variable1":"ABC1","variable2":"AA","variable3":"BB"},
"3":{"variable1":"ABC2","variable2":"AA","variable3":"BB"},
"4":{"variable1":"BC3","variable2":"AA","variable3":"BB"},
"5":{"variable1":"DC4","variable2":"AA","variable3":"BB"},
"6":{"variable1":"DD5","variable2":"AA","variable3":"BB"}
}
I'm analyzing a code from the website and I tried it on my side as well but seems it doesn't work. Could you please tell me why? would greatly appreciate your help.
Thanks
Private Sub CommandButton1_Click()
Dim N, D As Single
Dim tag As String
N = Cells(2, 2)
Select Case N
Case Is < 2
MsgBox "It is not a prime number"
Case Is = 2
MsgBox "It is a prime number"
Case Is > 2
D = 2
Do
If N / D = Int(N / D) Then
MsgBox "It is not a prime number"
tag = "Not Prime"
Exit Do
End If
D = D + 1
Loop While D <= N - 1
If tag <> "Not Prime" Then
MsgBox "It is a prime number"
End If
End Select
End Sub
The single biggest problem I see is using Single instead of Integer or Long. Primes are positive integers and are not thought of in the context of decimal values (as far as I know). Thus by using a singles and comparing them to divided ints, you're opening yourself up to nasty edge-case rouding errors.
The line If N / D = Int(N / D) Then is using a poor method to see whether or not the numbers are prime. It's assuming that every time you divide a floating point number (in this case, the single) by the divisor, if it has a decimal remainder, then the integer conversion of that remainder will not be equal. However, I've run into rounding errors sometimes with floating point numbers when trying to compare answers, and in general, I've learned to avoid using floating point to int conversions as a way of comparing numbers.
Here's some code you might try instead. Some things to note:
I've changed the types of N and D so that they are Longs and not Singles. This means they are not floating point and subject to possible rounding errors.
I've also explicitly converted the cell value to a long. This way you know in your code that you are not working with a floating point type.
For the comparison, I've used Mod, which returns the remainder of the N divided by D. If the remainder is 0, it returns true and we know we don't have a prime. (Note: Remainder is often used with \, which only returns the integer value of the result of the division. Mod and \ are commonly used in precise division of integer types, which in this case is very appropriate.
Lastly, I changed your message box to show the actual number being compared. Since the number in the cell is converted, if the user enters a floating point value, it will be good for them to see what it was converted to.
You'll probably also note that this code runs a lot faster than your code when you get to high numbers in the hundreds of millions.
'
Sub GetPrime()
Dim N As Long
Dim D As Long
Dim tag As String
N = CLng(Cells(2, 2))
Select Case N
Case Is < 2
MsgBox N & " is not a prime number"
Case Is = 2
MsgBox N & " is a prime number"
Case Is > 2
D = 2
Do
If N Mod D = 0 Then
MsgBox N & " is not a prime number"
tag = "Not Prime"
Exit Do
End If
D = D + 1
Loop While D <= N - 1
If tag <> "Not Prime" Then
MsgBox N & " is a prime number"
End If
End Select
End Sub
NOTE: I changed the name of the procedure to be GetPrime. In your code, you had:
Private Sub CommandButton1_Click()
In the line above, you are defining a procedure (also called a method or sometimes just referred to as a sub). The word Sub indicates you are defining a procedure in code that returns no value. (Sometimes you might see the word Function instead of Sub. This means the procedure returns a value, such as Private Function ReturnANumber() As Long.) A procedure (Sub) is a body of code that will execute when called. Also worth noting, an excel macro is stored in VBA as a Sub procedure.
In your line of code, CommandButton1_Click() is the name of the procedure. Most likely, this was created automatically by adding a button to an Excel spreadsheet. If the button is tied to the Excel spreadsheet, CommandButton1_Click() will execute each time the button is pressed.
In your code, Private indicates the scope of the procedure. Private generally means that the procedure cannot be called outside of the module or class in which it resides. In my code, I left out Private because you may want to call GetPrime from a different module of code.
You mentioned in your comments that you had to change the name of my procedure from GetPrime() to CommandButton1_Click(). That certainly works. However, you could also have simply called GetPrime from within CommandButton1_Click(), like below:
Private Sub CommandButton1_Click()
'The following line of code will execute GetPrime() '
'Since GetPrime does not have parameters and does not return a value, '
'all you need to do is put the name of the procedure without the () '
GetPrime
End Sub
'Below is the entire code for the Sub GetPrime() '
Sub GetPrime()
'The body of the code goes below: '
' ... '
End Sub
Hopefully this helped to explain a little bit about VBA to further your understanding!
I'm not sure where you copied this code from, but it's terribly inefficient. If I may:
Dim N, D As Long will cause D to be a Long, and N to be a variant. As you may know, variants are one of the slowest data types available. This line should be: Dim N As Long, D As Long
You only need to test every other number as an even number will always be divisible by two. (Therefore can not possibly be prime).
You don't need to test all the way up to N. You only need to test up to the Square Root of N. This is because after the square root the factors just switch sides, so you are just retesting values.
For Loops only evaluate the For-Line once for the life of the loop, but Do and While loops evaluate their conditional on every loop, so N-1 is being evaluated many, many times. Store this value in a variable if you want to use a Do Loop.
Ok, so now that we have dispensed with the blah, blah, blah, here is the code. I structured it so you can use it as a UDF from Excel as well (Ex: =ISPRIME(A2)):
Option Explicit
Sub GetPrime()
Dim varValue As Variant
varValue = Excel.ActiveSheet.Cells(2&, 2&).Value
If IsNumeric(varValue) Then
If CLng(varValue) = varValue Then
If IsPrime(varValue) Then
MsgBox varValue & " is prime", vbInformation, "Prime Test"
Else
MsgBox varValue & " is not prime", vbExclamation, "Prime Test"
End If
Exit Sub
End If
End If
MsgBox "This operation may only be performed on an integer value.", vbCritical, "Tip"
End Sub
Public Function IsPrime(ByVal num As Long) As Boolean
Dim lngNumDiv As Long
Dim lngNumSqr As Long
Dim blnRtnVal As Boolean
''//If structure is to optimize logical evaluation as AND/OR operators do not
''//use short-circuit evaluation in VB.'
If num = 2& Then
blnRtnVal = True
ElseIf num < 2& Then 'Do nothing, false by default.
ElseIf num Mod 2& = 0& Then 'Do nothing, false by default.
Else
lngNumSqr = Sqr(num)
For lngNumDiv = 3& To lngNumSqr Step 2&
If num Mod lngNumDiv = 0& Then Exit For
Next
blnRtnVal = lngNumDiv > lngNumSqr
End If
IsPrime = blnRtnVal
End Function
You can optimise it further (and make it more readable, in my opinion) by making the following changes. First performance:
Use longs, not floats. This will result in a huge speed increase.
You don't need to check up to n-1, only the square root of n. That's because if a factor d greater than sqrt(n) exists, its counterpart n/d would have already been found under sqrt(n). We use a special variable for this so that we don't get overflow by calculating divisor2. It also speeds it up by calculating that once rather than calculating the square every time through the loop (even though getting the square root is undoubtedly slower than squaring, it only happens once).
Do a special check first for multiples of two then you need only check that your number is a multiple of an odd number, effectively doubling the speed (not checking if you're a factor of a multiple of two).
Use the modulo operator rather than division/multiplication.
Now readability:
Use descriptive variable names.
Use a boolean for boolean values (not a string like tag).
Move the message box logic down to the bottom, based on the isPrime boolean, rather than scattering the messages amongst your code.
With all those changes, the following code can detect a 9-digit prime number (795,028,841) in well under a second. In fact, we can detect the largest 31-bit prime (2,147,483,647) in the same time.
Based on benchmarks (putting a 10,000-iteration for loop around the select), it takes 35 seconds on my box to detect that 31-bit prime. That's about 285 times per second - hopefully that'll be fast enough for you :-)
Option Explicit
Public Sub Go()
Dim number As Long
Dim divisor As Long
Dim maxdivisor As Long
Dim isPrime As Boolean
number = CLng(Cells(2, 2))
Select Case number
Case Is < 2
isPrime = False
Case Is = 2
isPrime = True
Case Is > 2
isPrime = True
If number mod 2 = 0 Then
isPrime = False
Else
maxdivisor = CLng(Sqr(number)) + 1
divisor = 3
Do
If number mod divisor = 0 Then
isPrime = False
Exit Do
End If
divisor = divisor + 2
Loop While divisor <= maxdivisor
End If
End Select
If isPrime Then
MsgBox "Number (" & number & ") is prime"
Else
MsgBox "Number (" & number & ") is not prime"
End If
End Sub