Random number generation with user-defined Mean and StdDev - vba

I am attempting to generate normally distributed random variables.
I have a user input for the total number of variables (M), the number of sets of random variables (N). I am using the formula =NORM.INV(RAND(),0,1) and it works fine.
However when I want to have a user input Mean and StdDev, I declare a variable for each. The cell that is bring referenced by the variable I put say a 0 for Mean and 1 for StdDev.
The code will run, however the output of the random variables is the good old #NAME?.
I do not understand why referencing a cell if just entering the formula on the worksheet works, but in VBA it does not?
The code is:
Sub RandomNorm()
Dim WS_W As Worksheet: Set WS_W = ActiveWorkbook.Worksheets("Working") ' Sheet for calculations
Dim WS_Rand As Worksheet: Set WS_Rand = ActiveWorkbook.Worksheets("Random Generated") ' Sheet for random variable generation
Application.ScreenUpdating = False
Dim N As Long: N = WS_W.Range("B3").Value ' Number of random variable sets
Dim M As Long: M = WS_W.Range("C3").Value ' Number of simulations
WS_W.Select
Dim Mean As Double: Mean = WS_W.Cells(3, 4).Value ' Mean of Normal distribution
Dim StdDev As Double: StdDev = WS_W.Cells(3, 5).Value ' Standard Deviation of normal distribution
Dim i As Long
Dim j As Long
WS_Rand.Select
WS_Rand.Cells.Select
Selection.ClearContents ' Prepare for generation by clearing Generation sheet
For i = 1 To N
For j = 1 To M
WS_Rand.Cells(j, i).Select
ActiveCell.FormulaR1C1 = "=NORM.INV(RAND(),Mean,StdDev)"
Next
Next
End Sub

The Excel worksheet formula calculation engine does not know anything about your VBA variables.
You are assigning a formula to cells and attempting to use variables from VBA in the formula. Since Excel does not recognize the literal text of each variable name this results in a #NAME? error.
The fix is to replace the variable names with their values:
ActiveCell = "=NORM.INV(RAND()," & Mean & "," & StdDev & ")"
As a side note... you can assign the formula to the entire range of cells in one go rather than looping the assignment cell by cell, and nothing needs to be selected in order to assign the formula.

Related

How do I fix this compile error - Expected end of statement? Inputting a formula into a cell with VBA that passes a VBA variable into that formula

I've got a variable that adds 3 to a number that a user inputs on a userform. Then, I create a table with that many rows on another sheet. Then, I want a cell on that sheet to count the cells that are in the table and tell the user. I want to do this in VBA because this Sub generates a new sheet/table each time it's run so I can't just enter the formula in the cell and keep it there.
Dim Qnum as Integer 'Defined the integer
Dim ws as Worksheet
Set ws = Sheets("Test")
Qnum = 3 + GenTest.txtNum 'adding three to the number of rows the user has requested
with ws
.Range("C1").Formula = "=Counta(D4:D" & Qnum")" 'This gives a compile error - expected end of statement
This is just the part of the code that's returning the error. The rest of the code (not shown) creates a table from the A:D column with the amount of rows that the Qnum variable has.
What am I missing here?
You need an & after Qnum
.Range("C1").Formula = "=Counta(D4:D" & Qnum & ")"

Excel VBA - Compile Error - Object Required

This is my first post to this wonderful forum . I am new to VBA and have been writing my first meaningful macro beside doing some practice while learning.
While the WIP code is reproduced below, let me give you a background.
Have a a sheet to calculation investment maturity based on various inputs like Term of Payment and term of Maturity.
This sheet has all the formule in place to compute the maturity value.
Now on sheet 2, I am creating a matrix structure with a intersection of payment term and term of maturity. For ex combination of 1 Yr of Payment term with maturity ( 1...25) and next Payment term and so on.
I am writing a macro which will pick up the user choice from sheet 1 and then loop the macro in matrix and capture the result and paste it to sheet two .
I am still far away from what i have to achive but got a code in first few line of selecting and setting the payment term and maturity terms
Error is Compile error- Object required. I am not able to figure out what it it. WIP code is reproduced below
Private Sub Simulation_Click()
Dim PPT As String
Dim Term As String
MsgBox (" The Programme is starting now")
Set PPT = Workbooks("himanshu.xlsm").Worksheet("Sheet1").Range("G2").Value
Set Term = Workbooks("himanshu.xlsm").Worksheet("Sheet1").Range("G3").Value
For PPT = 1 To PPT
For Term = 1 To Term
' Do something here
Next Term
Next PPT
End Sub
Please help
EDIT # 1- September 19,2017, 3.10 AM IST
Hi Experts,
Finally my first VBA code is running . Its slow but its running. One last problem
I have issue in Code line "Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2").Copy Workbooks("himanshu.xlsm").Sheets("What if").Cells(cols, Rowsh)" where while to source carries the right value( checked in debug Mode) but when it is pasted to target, it is pasted as 0. When I checked the target sheet , somehow it is showing me a formula (= Max( R1C1 :X1Y1). Please note that from where I am copyiong the value ( Source) , its a excel calculation which is arrived as a formula of selecting max of col J . I suspect that code is copying the formula instead of value. Please advice
Option Explicit
Sub macro21()
'MsgBox ("Start")
Dim i As Integer, j As Integer
Dim PPT As Integer
Dim Term As Integer
Dim pptrange As Range ' Address of the Cell where PPT is maintained in Sheet 1
Dim termrange As Range ' Address of the Cell where Term is maintained in Sheet 1
Dim cols As Integer
Dim Rowsh As Integer
PPT = 3
Term = 5
cols = 3
Rowsh = 3
For i = 1 To PPT
For j = 1 To Term
Set pptrange = Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("G2") ' Set pptrange and termrange locations
Set termrange = Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("G3") ' Set pptrange and termrange locations
pptrange.Value = i
termrange.Value = j
***Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2").Copy Workbooks("himanshu.xlsm").Sheets("What if").Cells(cols, Rowsh)***
' MsgBox ("Value is " & Cells(cols, Rowsh).Value)
MsgBox ("Value is " & Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2"))
If j < Term Then
cols = cols
Rowsh = Rowsh + 1
End If
Next j
cols = cols + 1
Rowsh = 3
Next i
End Sub
I have issue in Code line "Workbooks("himanshu.xlsm").Sheets("Sheet1").Range("J2").Copy Workbooks("himanshu.xlsm").Sheets("What if").Cells(cols, Rowsh)" where while to source carries the right value( checked in debug Mode) but when it is pasted to target, it is pasted as 0. When I checked the target sheet , somehow it is showing me a formula (= Max( R1C1 :X1Y1). Please note that from where I am copyiong the value ( Source) , its a excel calculation which is arrived as a formula of selecting max of col J . I suspect that code is copying the formula instead of value. Please advice
PPT is a string so you should use:
PPT = ...
and not
Set PPT =
Set is used to assign object variables such as workbooks, worksheets, etc.
Edit: as Jeeped mentioned in his comment you have to change data type. You cannot use string in a loop like that. Change Term and PPT to Integer or Long.

Trying to create a macro to perform 100 iterations and paste resulting values (2 adjacent row cells) to a 2 x 100 array

I have a worksheet that uses randomly generated numbers in calculations to produce results in two adjacent cells (let's say A1 and A2). I am trying to perform 100 iterations where I'm simply "Calculating Formulas" on the worksheet and then trying to store the results of each iteration next to A1 and A2 (so iteration 1 would be in B1 and B2 and iteration 100 would be in CW1 and CW2). Thanks in advance for your help. Using Excel 2010 if that matters.
Dim Iteration As Integer, i As Integer
Dim val As Variant
Iteration = 100
For i = 1 To Iteration
Calculate
Range("A1:A2").Select
Selection.Copy
Range("B" & Rows.Count).End(x1Up).Offset(0, 1).PasteSpecial
Paste:=xlPasteValues
Next i
End Sub
I think your major problem was with the location you were selecting for the destination address - you were finding the last unused cell in column B, then shifting over one column (i.e. to column C) and pasting the first set of results. Then you were using that same location for the second set of results, etc.
Sub Test()
Dim Iteration As Integer, i As Integer
Dim val As Variant
Iteration = 100
'Use a "With" block so that it can be easily changed in the future
'to refer to a specific sheet if needed
With ActiveSheet
For i = 1 To Iteration
Calculate
'Determine the last used column on row 1,
' offset 1 column to the right,
' resize to refer to 2 rows,
' set values to the values in A1:A2
.Cells(1, .Columns.Count).End(xlToLeft).Offset(0, 1).Resize(2, 1).Value = .Range("A1:A2").Value
Next i
End With
End Sub
As pointed out by Steve Lovell, you also had a typo in your original code. It is a good habit to include Option Explicit as the first line in every code module. That will force you to declare all the variables that you use, and the compiler would have highlighted x1Up and given a "Variable not defined" error.

Excel 2007 using VBA write formula to merged cells

I have a list of values starting at G11 and extending a variable length down column G. I have a string array which contains the addresses of ranges of the G column data to be averaged. In the H column starting at H11 I have merged cells where I want the averaged values to appear. The number of G column cells to be averaged together also varies. The following code I tried failed since the formula was entered as is, rather than having the ranges(i) array value placed into the formula.
For i = 0 To range_num
ActiveCell.Formula = "=AVERAGE(ranges(i))"
Next i
ranges() contains the ranges (in string form) to be averaged. And for example:
ranges(i) = "G11:G15"
fori = 0 and range_num is the number of averages that will be done.
Each G column value is only included in 1 average, each group of values to be averaged is consecutive, and each group is directly to the left of the merged cell where I want the average to appear. Does anyone have some insight on how I could better format my code to achieve this? Any ideas are appreciated, thanks.
The reason the formula is entering 'as is' is because you'd need to concatenate it into the string.
For i = 0 To range_num
ActiveCell.Formula = "=AVERAGE(" & ranges(i) & ")"
Next i
If I have interpreted correctly, you are looking for a code snippet that will loop through a range of cells and set the formula based on the literal string found in another cell. Try the following:
sub SetCellFormulas()
dim sWS as worksheet
dim aCell as range
dim aRange as range
dim Lrow as long
set sws = thisworkbook.sheets("yourworksheetname")
'*** Locate last cell with values in column G
lrow = sws.Range("G11").end(xldown).row
'*** Set range to loop through
set arange = sws.Range("G11:G" & Lrow)
for each acell in arange
'*** set formula of cell 1 to the left of G to the concatenated formula
aCell.offset(0,1).formula = "=AVERAGE(" & acell.value & ")"
next acell
end sub

Formula using Cells in the spreadsheet

I am looking for a way to set a variable equal to the number of non-empty cells in Column A using Excel VBA.
So pseudo code
Dim j As Integer
j = CountA(A:A)
This however does not work. Neither does j = "=CountA(A:A)"
Something like this will do the trick.
The VBA functions don't work exactly the same as in the spreadsheets themselves. You need to first select the range of the active worksheet and then call the counta function.
Dim j = Application.WorksheetFunction.counta(activeworksheet.range("A:A"))
Paste this into a module in Excel VBA.
Function CountNonEmptyCells(ColId As Integer) As Integer
Dim r As Range
Dim Count As Integer
Set r = Sheet1.Columns(ColId)
For Each cell In r.Cells
If cell.Value <> "" Then
Count = Count + 1
End If
Next
CountNonEmptyCells = Count
End Function
My end result:
You can also use Evaluate Function like this:
Dim j As Long
j = [CountA(A:A)] 'brackets are shortcut for Evaluate
or explicitly like this:
j = Evaluate("CountA(A:A)")
Essentially, you can either Evaluate the formula as it would appear on the worksheet or you can adapt the syntax to use as an adopted VBA command. Here are a couple variations of each. Note that I am explicitly including a reference to the parent worksheet. This is particularly important for the first two evaluate methods and desirable for all four variations in order that you are not counting column A from the wrong worksheet.
Dim j As Long
j = [COUNTA(Sheet1!A:A)]
Debug.Print j
j = Evaluate("COUNTA(Sheet1!A:A)")
Debug.Print j
j = Application.CountA(Sheets("Sheet1").Columns(1))
Debug.Print j
j = Application.CountA(Range("Sheet1!A:A"))
Debug.Print j
The first simply uses [ and ] as wrappers around the COUNTA formula as it would appear on the worksheet. This forces evaluation of the formula to a result. The second is another evaluation of the formula but using the .Evaluate command allows you the option to construct the formula as a string using concatenation, replacement and other text parsing methods. You can include an equals sign (e.g. =) as a prefix if that makes more sense to you, (e.g. j = [=COUNTA(Sheet1!A:A)]) but it is not necessary.
In the last two, VBA adopts the native worksheet COUNTA function by prefacing it with either Application.Worksheetfunction. or (as above) just Application.. The cell range also moves from worksheet cell notation to VBA style cell notation.