How can I write a code where the values are 'stepped'? - vba

I just started programming in Excel VBA and I have a question.
How can I write a code where the values are 'stepped'?
I want to code this by using do until, do while and for only.
I'm using two variables: x = 1 and y = 1. The value must be the number of the cycle.
The output would look like this:
cells(x,y). value = a
cells(2x,y). value = 2a
cells(2x,2y). value = 3a
cells(3x,2y). value = 4a
cells(3x,3y). value = 5a
cells(4x,3y). value = 6a
cells(4x,4y). value = 7a

This would be an alternative version to do it
Option Explicit
Public Sub Generate()
Dim a As Long: a = 1
Dim i As Long
For i = 1 To 7
Cells((i \ 2) + 1, ((i - 1) \ 2) + 1).Value = i * a
Next i
End Sub
Note that this uses the div Operator 5 \ 2 which is not a standard division 5 / 2. The div operator divides two numbers and returns an integer result.
Standard division of 5 / 2 = 2.5
Div Operator of 5 / 2 = 2
So (i \ 2) + 1, ((i - 1) \ 2) + 1 results in
1, 1
2, 1
2, 2
3, 2
3, 3
4, 3
4, 4

You can step through your sequence in VBA using arrays like so:
Sub StepAXY()
Dim Z As Long, A As Long, X As Long, Y As Long
Dim arrA() As Variant, arrX() As Variant, arrY() As Variant
arrA = Array(1, 2, 3, 4, 5, 6, 7)
arrX = Array(1, 2, 2, 3, 3, 4, 4)
arrY = Array(1, 1, 2, 2, 3, 3, 4)
For Z = 1 To 7 Step 1
A = arrA(Z - 1)
X = arrX(Z - 1)
Y = arrY(Z - 1)
Cells(X * 1, Y * 1) = A * 1
Next Z
End Sub

Here is a different approach. This will give you an extra row (5x,4y) so if this is not desired can be excluded using an If statement.
Sub Generate()
Dim x As Long, y As Long, a As Long, b As Long, c As Long
For b = 1 To 4
Cells(b * x, b * y) = (2 * b - 1) * a
Cells((b + 1) * x, b * y) = 2 * b * a
Next b
End Sub

Related

Recursive function structure in VBA

I'm trying to write a recursive function so that it calculates the sum of the products of the combinations of values in a dynamic array. Right now I've been trying to make it work for a simpler case, but I really don't quite understand the structure I should follow for a recursive function. In this case there's supposed to be the sum of 28 two factor products, resulting 1.4
Sub SuPC()
Dim k As Long
Dim s As Long
Dim i As Long
Dim j As Long
k = 8
s = 2
HSum i, j, s, k
End Sub
Function HSum(i As Long, j As Long, s, k) As Double
Dim P As Variant
Dim z() As Double
Dim Tot As Double
ReDim z(0 To (k * s) - 1)
P = Array(1 / 2, 1 / 3, 1 / 4, 1 / 5, 1 / 6, 1 / 7, 1 / 8, 1 / 9)
If i <= k Then
HSum i + 1, j, s, k
If j <= s Then
HSum i, j + 1, s, k
If z(i) = 0 Then z(i) = 1
z(i) = P(j) * z(i)
End If
Tot = z(i) + Tot
End If
Range("J11") = Tot
End Function
If s and k were low fixated values, I could use For loops but the point is for them to be variable.
You should try to use tail recursion as this is just a sum of the products,
see here an example for tail recursion factoring.
Public Function fact_tail(n As Double) As Double
'Tail Recursion
'fact 4 = 4 * fact 3
' = 4* 3 * fact 2
' = 4* 3 * 2 * fact 1
' = 4* 3 * 2 * 1
'fact 4 = go(4, 1)
' = go((n - 1), (a * n))
' = go((4-1),(1*4))
' = go(3, 4)
' = go(3-1, 3*4)
' = go(2, 12)
' = go(2-1, 12*2)
' = go(1, 24)
' = 4* 3 * 2 * 1 = 24
fact_tail = go_fact(n, 1)
End Function
Private Function go_fact(n, a)
If n <= 1 Then
go_fact = a
Else
go_fact = go_fact((n - 1), (a * n))
End If
End Function

Excel VBA how to set number sequence to start at middle of the row?

I previously have a Excel sheet with VBA coding that fills column, row 1 to 10 with the number 1, row 11 to 20 with number 2 and so on. The code I've used is as follows:
Sub fill()
Dim ID
ID = 1
For c = 1 To 34
ActiveWorkbook.Sheets("Sheet1").Cells(c, 1) = ID
ActiveWorkbook.Sheets("Sheet1").Cells(c + 1, 1) = ID
c = c + 1
If (c Mod 10) = 0 Then
ID = ID + 1
End If
Next c
End Sub
Now I want to change it so that the code starts at row 3 onwards. Meaning row 3 to 12 = 1, row 13 to 22 = 2 and so on. So I changed the 'For' statement to:
For c = 3 To 34
But what happens is that the number 1 appears from row 3 to row 10, and then continues with number 2 in row 11 to 20. Not what I was expecting.
Therefore, what would be the best method of changing the code?
If you want exactly the same output but two rows lower, you can use:
Sub fill()
Dim ID
ID = 1
For c = 1 To 34
ActiveWorkbook.Sheets("Sheet1").Cells(c + 2, 1) = ID
ActiveWorkbook.Sheets("Sheet1").Cells(c + 3, 1) = ID
c = c + 1
If (c Mod 10) = 0 Then
ID = ID + 1
End If
Next c
End Sub
If you still only want to go to row 34 but start in row 3, change the 34 to 32 in the above code.
You can also do it without looping and this is easier to adjust the parameters:
Sub fill()
Const NUMBER_OF_ROWS As Long = 34
Const START_ROW As Long = 3
Const ID As Long = 1
Const NUMBER_IN_GROUP As Long = 10
With ActiveWorkbook.Sheets("Sheet1").Cells(START_ROW, 1).Resize(NUMBER_OF_ROWS)
.Value = .Parent.Evaluate("INDEX(INT((ROW(" & .Address & ")-" & START_ROW & ")/" & _
NUMBER_IN_GROUP & ")+" & ID & ",)")
End With
End Sub
When i understand you write, this should work:
You can use the loop how you did at the beginning. and just add plus 2 to c in the ActiveWorkbook.Sheets("Tabelle1").Cells(c + 2, 1) = ID
Sub fill()
Dim ID
ID = 1
For c = 1 To 34
ActiveWorkbook.Sheets("Tabelle1").Cells(c + 2, 1) = ID
ActiveWorkbook.Sheets("Tabelle1").Cells(c + 3, 1) = ID
c= c+1
If (c Mod 10) = 0 Then
ID = ID + 1
End If
Next c
End Sub
something like that should be the simplest way:
Sub fill()
Dim i As Integer
Dim j As Integer
For i = 1 To 4
For j = 1 To 10
ActiveWorkbook.Sheets("Sheet1").Cells(j + (i - 1) * 10 + 2, 1) = i
Next j
Next i
End Sub
EDIT:
No, the simplest way would be type formula into A3:
=ROUNDDOWN(((ROW()-3))/10,0)+1
end drag it donw.

run time error 5 in VBA excel when working with array

I use vba on excel 2007, OS: windows vista, to make calculation using kinematic wave equation in finite difference scheme. But, when it runs the run-time 5 (invalid procedure call or arguments) message appears. I really don't what is going wrong. Anyone can help?
Sub kwave()
Dim u(500, 500), yy(500, 500), alpha, dt, dx, m, n, so, r, f, X, L, K As Single
Dim i, j As Integer
dx = 0.1
dt = 0.01
L = 10
m = 5 / 3
r = 1
f = 0.5
n = 0.025
so = 0.1 'this is slope
alpha = 1 / n * so ^ 0.5
X = 0
For i = 0 To 100
Cells(i + 1, 1) = X
u(i, 1) = L - so * X
X = X + dx
Cells(i + 1, 2) = u(i, 1)
Next i
For j = 0 To 100
For i = 1 To 100
'predictor step
u(i, j + 1) = u(i, j) - alpha * dt / dx * (u(i + 1, j) ^ m - u(i, j) ^ m) + (r - f) * dt
'corrector step
K = u(i, j + 1) ^ m - u(i - 1, j + 1) ^ m '<<<<----- RUNTIME ERROR 5 HAPPENS AT THIS LINE
yy(i, j + 1) = 0.5 * ((yy(i, j) + u(i, j + 1)) - alpha * dt / dx * K + (r - f) * dt)
Next i
Next j
End Sub
You are declaring the variables wrong- the array should store a double/single but it is defaulting to a variant. See this article.
http://www.cpearson.com/excel/declaringvariables.aspx -
"Pay Attention To Variables Declared With One Dim Statement
VBA allows declaring more than one variable with a single Dim
statement. I don't like this for stylistic reasons, but others do
prefer it. However, it is important to remember how variables will be
typed. Consider the following code:
Dim J, K, L As Long You may think that all three variables are
declared as Long types. This is not the case. Only L is typed as a
Long. The variables J and K are typed as Variant. This declaration is
functionally equivalent to the following:
Dim J As Variant, K As Variant, L As Long You should use the As Type
modifier for each variable declared with the Dim statement:
Dim J As Long, K As Long, L As Long "
Additionally, when i = 99 and j = 10, u(99,11), which is j+1, produces a negative number. Note that this does not fully cause the problem though, because you can raise negative numbers to exponents. Ex, -5^3 = -125

Macro returns #REF! in excel

I don't know if this is the place to ask such a question, but since it was regarding some VBA scripting, I thought it might.
I have been writing this Macro function:
Function Mod10(tl As String) As Byte
Dim c(13) As Integer
Dim er As Integer
c(13) = Mid(tl, 14, 1) * 2
c(12) = Mid(tl, 13, 1)
c(11) = Mid(tl, 12, 1) * 2
c(10) = Mid(tl, 11, 1)
c(9) = Mid(tl, 10, 1) * 2
c(8) = Mid(tl, 9, 1)
c(7) = Mid(tl, 8, 1) * 2
c(6) = Mid(tl, 7, 1)
c(5) = Mid(tl, 6, 1) * 2
c(4) = Mid(tl, 5, 1)
c(3) = Mid(tl, 4, 1) * 2
c(2) = Mid(tl, 3, 1)
c(1) = Mid(tl, 2, 1) * 2
c(0) = Mid(tl, 1, 1)
For i = 0 To 13
If c(i) > 9 Then
c(i) = CInt(Left(c(i), 1)) + CInt(Right(c(i), 1))
End If
Next
er = 0
For i = 0 To 13
er = er + c(i)
Next
Mod10 = 10 - er Mod 10
End Function
But as you can see here in this picture:
it returns an error saying #REF!. i am writing this in the fx: =Mod10(a1).
The script is found here: http://kronsell.net/fikkontrol.htm (a danish site)
It is used to calculate the final digit to a string. A bit like when calculating the EAN-13 code, just another kind of calculation.
If anybody with VBA or EXCEL knowledge could tell me what to do, I'd really appreciate it.
Not sure why, but it looks like Mod10 is a reserved keyword. I tried renaming the function to Mod_10 and it worked.
You may need to declare some variables if you hold Option Explicit at the top of your module.
Try this and call it from a cell with =MOD_10(A1)
Function MOD_10(tl As String) As Byte
Dim i As Long
Dim c(13) As Integer
Dim er As Integer
c(13) = Mid(tl, 14, 1) * 2
c(12) = Mid(tl, 13, 1)
c(11) = Mid(tl, 12, 1) * 2
c(10) = Mid(tl, 11, 1)
c(9) = Mid(tl, 10, 1) * 2
c(8) = Mid(tl, 9, 1)
c(7) = Mid(tl, 8, 1) * 2
c(6) = Mid(tl, 7, 1)
c(5) = Mid(tl, 6, 1) * 2
c(4) = Mid(tl, 5, 1)
c(3) = Mid(tl, 4, 1) * 2
c(2) = Mid(tl, 3, 1)
c(1) = Mid(tl, 2, 1) * 2
c(0) = Mid(tl, 1, 1)
For i = 0 To 13
If c(i) > 9 Then
c(i) = CInt(Left(c(i), 1)) + CInt(Right(c(i), 1))
End If
Next
er = 0
For i = 0 To 13
er = er + c(i)
Next
MOD_10 = 10 - er Mod 10
End Function

Simulation runs fine # 10k cycles, but gets error 13 (type mismatch) # 100k cycles

First off, here's my code:
Sub SimulatePortfolio()
Dim lambda As Double
Dim num As Integer
Dim cycles As Long
Column = 12
q = 1.5
lambda = 0.05
cycles = 100000
Dim data(1 To 100000, 1 To 10) As Integer
Dim values(1 To 10) As Double
For i = 1 To 10
values(i) = 0
Next i
temp = lambda
For i = 1 To cycles
lambda = temp
num = 10
t = 0
Dim temps(1 To 10) As Integer
For k = 1 To 10
temps(k) = 1000
Next k
Do While (t < 10 And num > 0)
t = t + tsim(lambda, num)
For j = 1 To 10
If (j > t) Then
temps(j) = temps(j) - 50
End If
Next j
num = num - 1
If (num <= 0) Then
Exit Do
End If
lambda = lambda * q
Loop
For l = 1 To 10
values(l) = values(l) + temps(l)
data(i, l) = temps(l)
Next l
Next i
For i = 1 To 10
Cells(i + 1, Column) = values(i) / cycles
'Problem occurs on this line:
Cells(i + 1, Column + 1).Value = Application.WorksheetFunction.Var(Application.WorksheetFunction.Index(data, i, 0))
Next i
End Sub
Function tsim(lambda As Double, num As Integer) As Double
Dim v As Double
Dim min As Double
Randomize
min = (-1 / lambda) * Log(Rnd)
For i = 1 To (num - 1)
Randomize
v = (-1 / lambda) * Log(Rnd)
If (min > v) Then
min = v
End If
Next i
tsim = min
End Function
When I set the value for cycles to 10000, it runs fine without a hitch. When I go to 100000 cycles, it gets an Error 13 at the indicated line of code.
Having been aware that Application.Tranpose is limited to 65536 rows with variants (throwing the same error) I tested the same issue with Index
It appears that Application.WorksheetFunction.Index also has a limit of 65536 rows when working with variants - but standard ranges are fine
So you will need to either need to dump data to a range and work on the range with Index, or work with two arrays
Sub Test()
Dim Y
Dim Z
'works in xl07/10
Debug.Print Application.WorksheetFunction.Index(Range("A1:A100000"), 1, 1)
Y = Range("A1:A65536")
`works
Debug.Print Application.WorksheetFunction.Index(Y, 1, 1)
'fails in xl07/10
Z = Range("A1:A65537")
Debug.Print Application.WorksheetFunction.Index(Z, 1, 1)
End Sub