Errors using Arrays in VBA - vba

I am new to VBA ans really appreciate your help.
I am writing a custom function. I am trying to use arrays to store values from the for loop and retrieve the values based on their location on the array.
Please refer to the code below
Function Amounttopay(Original_Principal As Integer, APR As Double, Npayperyear As Integer, term As Integer, Paydone As Integer)
Dim strinitialamount() As Integer
Dim strInterestp() As Integer
Dim strendamount() As Integer
Dim i As Integer
r = (APR / Npayperyear)
n = Npayperyear * term
emi = (Original_Principal * r) / (1 - ((1 + r) ^ (-1 * n)))
ReDim strinitialamount(n)
ReDim strInterestp(n)
ReDim strendamount(n)
strinitialamount(0) = Original_Principal
strInterestp(0) = (Original_Principal * r)
strendamount(0) = (Original_Principal - (emi - strInterestp(0)))
For i = 1 To (n - 1)
strinitialamount(i) = strendamount(i - 1)
strInterestp(i) = (strinitialamount(i)) * r
strendamount(i) = (strinitialamount(i)) - (emi - strInterestp(i))
Next i
Amounttopay = strendamount(Paydone)
End Function

You need change it to Long because an integer only goes between -32,768 to 32,767.
I ran this with your values:
Function Amounttopay(Original_Principal As Long, APR As Variant, Npayperyear As Integer, term As Integer, Paydone As Integer)
Dim strinitialamount() As Long
Dim strInterestp() As Long
Dim strendamount() As Long
Dim i As Integer
r = (APR / Npayperyear)
n = Npayperyear * term
emi = (Original_Principal * r) / (1 - ((1 + r) ^ (-1 * n)))
ReDim strinitialamount(n)
ReDim strInterestp(n)
ReDim strendamount(n)
strinitialamount(0) = Original_Principal
strInterestp(0) = (Original_Principal * r)
strendamount(0) = (Original_Principal - (emi - strInterestp(0)))
For i = 1 To (n - 1)
strinitialamount(i) = strendamount(i - 1)
strInterestp(i) = (strinitialamount(i)) * r
strendamount(i) = (strinitialamount(i)) - (emi - strInterestp(i))
Next i
Amounttopay = strendamount(Paydone)
End Function
Sub TestFunction()
Debug.Print Amounttopay(1000000, 0.1, 12, 1, 6)
'Original_Principal = 1000000, APR = 0.1, Npayperyear = 12, term = 1, Paydone = 6
End Sub
I received this as a result: 428798

Related

Excel VBA #Value! Error

I have the following function that when I run it says #value! error.
I would appreciate any help.
Function Bootstrap(S As Object, Z As Object, L As Double)
Dim j As Integer
Dim a() As Double
Dim b() As Double
Dim n As Integer
Dim Q() As Double
Dim sum As Double
Dim P As Double
ReDim a(1 To n)
ReDim b(1 To n)
ReDim Q(1 To n)
dt = 1
sum = 0
Q(0) = 0
For j = 1 To n - 1
S.Cells(j, 1).Value = a(j)
Z.Cells(j, 2).Value = b(j)
P = Z(j) * (L * Q(j-1) - (L + dt * a(n) * Q(j))
sum = sum + P
Next j
Bootstrap = sum
End Function
Bootstrapping function calculates the following value
In fact I am trying to calculate this formula
Q(t,Tn)=(∑(j=1)to(n-1) Z(t,Tj)[LQ(t,Tj-1)-(L+dtSn)Q(t,Tj)]/[Z(t,Tn)(L+dt*Sn)] +(Q(t,Tn-1)L)/(L+dtSn)
Inputs given are[S1 ,S2,….Sn ],[Z(t,T1),Z(t,T2)…..Z(t,Tn)]and and L=0.4
Try this code : entered as =Bootstrap(A1:B1,A2:B2,0.4)
I have corrected the following
- Assigning the ranges to variants
- defining dt as double
- Dim Q() as 0 to n
- using A() and b() in the formula
- the input ranges are rows not columns
Function Bootstrap(S As Range, Z As Range, L As Double) As Double
Dim j As Integer
Dim a As Variant
Dim b As Variant
Dim n As Integer
Dim Q() As Double
Dim sum As Double
Dim P As Double
Dim dt As Double
n = Application.WorksheetFunction.Max(S.Columns.Count, Z.Columns.Count)
a = S.Value
b = Z.Value
dt = 1
sum = 0
ReDim Q(0 To n)
Q(0) = 0
For j = 1 To n - 1
P = b(1, j) * (L * Q(j - 1)) - (L + dt * a(1, j) * Q(j - 1))
sum = sum + P
Q(j) = sum
Next j
Bootstrap = sum
End Function
Take the habit to format and increment your code, especially before posting it!
You need to type the output of the function (on the line of the function name)
A parenthesis is missing from the line P = Z(j) * (L*Q(j-1)-(L+ dt * a(n) * Q(j))
n is empty (and so are a, b and Q) when you try to redim your arrays, so you need to define them!
Z(j) will also give you an error, because it is a Range, you need Z.Cells(i,j)
Try this :
Function Bootstrap(S As Range, Z As Range, L As Double) As Double
Dim j As Integer
Dim a() As Double
Dim b() As Double
Dim n As Integer
Dim Q() As Double
Dim sum As Double
Dim P As Double
n = Application.WorksheetFunction.Max(S.Columns.count, Z.Columns.count)
a = S.Value
b = Z.Value
dt = 1
sum = 0
ReDim Q(1 To n)
Q(0) = 0
'Q(1) = "??"
For j = 1 To n - 1
P = b(1, j) * (L * Q(j - 1)) - (L + dt * a(1, j) * Q(j - 1))
sum = sum + P
Q(j) = sum
Next j
Bootstrap = sum
End Function

Excel VBA: Variable as First Row of Selection?

I am creating a function in Excel VBA. I am trying to set a variable equal to the first cell in a selection on the worksheet. Basically the equivalent of something like
x = Worksheets("Data").Range("D2").Offset(i - 1, 0)
y = Worksheets("Data").Range("E2").Offset(i - 1, 0)
z = Worksheets("Data").Range("F2").Offset(i - 1, 0)
except I want "Range("D2")" E2 and F2 to instead refer to the first, second and third cell of whatever I've got highlighted on the sheet, rather than a preset cell.
The specific code I've got is:
Function VarunModel(Table As Range, Optional EndCondition As Integer = 0) As Variant
Dim iNumCols As Integer, iNumRows As Integer
Dim i As Integer
Dim SelectedRange As Range
Set SelectedRange = Selection
iNumCols = Table.Columns.Count
iNumRows = Table.Rows.Count
maturity = Worksheets("KMV-Merton").Range("B2").Value
For i = 1 To iNumRows
equity(i) = SelectedRange.Cells(1).Value
debt(i) = SelectedRange.Cells(2).Value
riskFree(i) = Selection.Cells(3).Value
Next i
Dim equityReturn As Variant: ReDim equityReturn(2 To iNumRows)
Dim sigmaEquity As Double
Dim asset() As Double: ReDim asset(1 To iNumRows)
Dim assetReturn As Variant: ReDim assetReturn(2 To iNumRows)
Dim sigmaAsset As Double, meanAsset As Double
Dim x(1 To 1) As Double, n As Integer, prec As Double, precFlag As Boolean, maxDev As Double
For i = 2 To iNumRows: equityReturn(i) = Log(equity(i) / equity(i - 1)): Next i
sigmaEquity = WorksheetFunction.StDev(equityReturn) * Sqr(260)
sigmaAsset = sigmaEquity * equity(iNumRows) / (equity(iNumRows) + debt(iNumRows))
NextItr: sigmaAssetLast = sigmaAsset
For iptr = 1 To iNumRows
x(1) = equity(iptr) + debt(iptr)
n = 1
prec = 0.00000001
Call NewtonRaphson(n, prec, x, precFlag, maxDev)
asset(iptr) = x(1)
Next iptr
For i = 2 To iNumRows: assetReturn(i) = Log(asset(i) / asset(i - 1)): Next i
sigmaAsset = WorksheetFunction.StDev(assetReturn) * Sqr(260)
meanAsset = WorksheetFunction.Average(assetReturn) * 260
If (Abs(sigmaAssetLast - sigmaAsset) > prec) Then GoTo NextItr
Dim disToDef As Double: disToDef = (Log(asset(iNumRows) / debt(iNumRows)) + (meanAsset - sigmaAsset ^ 2 / 2) * maturity) / (sigmaAsset * Sqr(maturity))
Dim defProb As Double: defProb = WorksheetFunction.NormSDist(-disToDef)
VarunModel = defProb
End Function
Thanks.
Try the below code
Dim SelectedRange As Range
Set SelectedRange = Selection
x = SelectedRange.Cells(1).Value
y = SelectedRange.Cells(2).Value
z = SelectedRange.Cells(3).Value
try this:
Dim Row as integer
Dim Col as Integer
Row = 2
Col = 4 'column "D"
x = Worksheets("Data").cells(row, col).Offset(i - 1, 0)
col = col + 1
y = Worksheets("Data").cells(row, col).Offset(i - 1, 0)
col = col + 1
z = Worksheets("Data").cells(row, col).Offset(i - 1, 0)
See the example below for using the selection on the excel, you can control the column you want by changing the column index. If you select only 1 cell, it will also work:
Sub Solution()
x = Selection.Cells(1, 0) 'By using the zero index on the column, it will get the left cell from the selected one.
y = Selection.Cells(2, 0)
Z = Selection.Cells(3, 0)
End Sub

The results of my functions when I call a spline function gives wrong values

I have a function that only call the spline function when something happens..in this case when a division is less than zero..the inputs for the function is the same that for the spline function(called CUBIC), the spline was tested and works well when I call it direct! someone can help me?...follows a party of the code
Function NDF6(T As Variant, dias As Variant, taxas As Variant)
If T <= dias(1) Then
NDF6 = taxas(1)
Exit Function
End If
If T >= dias(tam) Then
NDF6 = taxas(tam)
Exit Function
End If
For i = 1 To tam
If T <= dias(i) Then
If taxas(i) / taxas(i - 1) < 0 Then
Call CUBIC(T, dias, taxas)
Else
i0 = ((taxas(i - 1) * dias(i - 1)) / 360) + 1
i1 = ((taxas(i - 1) * dias(i - 1)) / 360) + 1
irel = i1 / i0
i2 = irel ^ ((T - dias(i - 1)) / (dias(i) - dias(i - 1)))
i2rel = i2 * i0
i2real = i2rel - 1
NDF6 = i2real * (360 / T)
End If
Public Function CUBIC(x As Variant, input_column As Variant, output_column As Variant)
The function returns a zero value when I call the cubic function. The inputs are a cell with a value with a value equivalent a day and two arrays(DUONOFF and ONOFF) equivalent a days and rates, I call the function like:
NDF6(512,DUONOFF,ONOFF)
follows the CUBIC function
Public Function CUBIC(x As Variant, input_column As Variant, output_column As Variant)
'Purpose: Given a data set consisting of a list of x values
' and y values, this function will smoothly interpolate
' a resulting output (y) value from a given input (x) value
' This counts how many points are in "input" and "output" set of data
Dim input_count As Integer
Dim output_count As Integer
input_count = input_column.Rows.Count
output_count = output_column.Rows.Count
Next check to be sure that "input" # points = "output" # points
If input_count <> output_count Then
CUBIC = "Something's messed up! The number of indeces number of output_columnues don't match!"
GoTo out
End If
ReDim xin(input_count) As Single
ReDim yin(input_count) As Single
Dim c As Integer
For c = 1 To input_count
xin(c) = input_column(c)
yin(c) = output_column(c)
Next c
values are populated
Dim N As Integer 'n=input_count
Dim i, k As Integer 'these are loop counting integers
Dim p, qn, sig, un As Single
ReDim u(input_count - 1) As Single
ReDim yt(input_count) As Single 'these are the 2nd deriv values
N = input_count
yt(1) = 0
u(1) = 0
For i = 2 To N - 1
sig = (xin(i) - xin(i - 1)) / (xin(i + 1) - xin(i - 1))
p = sig * yt(i - 1) + 2
yt(i) = (sig - 1) / p
u(i) = (yin(i + 1) - yin(i)) / (xin(i + 1) - xin(i)) - (yin(i) - yin(i - 1)) / (xin(i) - xin(i - _1))
u(i) = (6 * u(i) / (xin(i + 1) - xin(i - 1)) - sig * u(i - 1)) / p
Next i
qn = 0
un = 0
yt(N) = (un - qn * u(N - 1)) / (qn * yt(N - 1) + 1)
For k = N - 1 To 1 Step -1
yt(k) = yt(k) * yt(k + 1) + u(k)
Next k
now eval spline at one point
Dim klo, khi As Integer
Dim h, b, a As Single
first find correct interval
klo = 1
khi = N
Do
k = khi - klo
If xin(k) > x Then
khi = k
Else
klo = k
End If
k = khi - klo
Loop While k > 1
h = xin(khi) - xin(klo)
a = (xin(khi) - x) / h
b = (x - xin(klo)) / h
y = a * yin(klo) + b * yin(khi) + ((a ^ 3 - a) * yt(klo) + (b ^ 3 - b) * yt(khi)) * (h ^ 2) _/ 6
CUBIC = y
out:
End Function

Normal Distributed Random Number in VB.NET

Is there anybody know how to make normal distributed random number in vb.net?
thank you
From this forum post :
Usage:
GaussNumDist(Mean, Standard Deviation, Sample Size)
Code example below, which will populate GaussNumArray() with the sample of numbers, whose distribution will have the mean and standard deviation specified:
Imports System.Math
Module Module1
Friend GaussNumArray() As Double
Friend intICell As Long
Friend Function GaussNumDist(ByVal Mean As Double, ByVal StdDev As Double, ByVal SampleSize As Integer)
intICell = 1 'Loop variable
ReDim GaussNumArray(SampleSize)
Do While (intICell < (SampleSize + 1))
Call NumDist(Mean, StdDev)
Application.DoEvents()
Loop
End Function
Sub NumDist(ByVal meanin As Double, ByVal sdin As Double)
'---------------------------------------------------------------------------------
'Converts uniform random numbers over the region 0 to 1 into Gaussian distributed
'random numbers using Box-Muller algorithm.
'Adapted from Numerical Recipes in C
'---------------------------------------------------------------------------------
'Defining variables
Dim dblR1 As Double
Dim dblR2 As Double
Dim mean As Double
Dim var As Double
Dim circ As Double
Dim trans As Double
Dim dblY1 As Double
Dim dblY2 As Double
Dim Pi As Double
Pi = 4 * Atan(1)
'Get two random numbers
dblR1 = (2 * UniformRandomNumber()) - 1
dblR2 = (2 * UniformRandomNumber()) - 1
circ = (dblR1 ^ 2) + (dblR2 ^ 2) 'Radius of circle
If circ >= 1 Then 'If outside unit circle, then reject number
Call NumDist(meanin, sdin)
Exit Sub
End If
'Transform to Gaussian
trans = Sqrt(-2 * Log(circ) / circ)
dblY1 = (trans * dblR1 * sdin) + meanin
dblY2 = (trans * dblR2 * sdin) + meanin
GaussNumArray(intICell) = dblY1 'First number
'Increase intICell for next random number
intICell = (intICell + 1)
GaussNumArray(intICell) = dblY2 'Second number
'Increase intICell again ready for next call of ConvertNumberDistribution
intICell = (intICell + 1)
End Sub
Friend Function UniformRandomNumber() As Double
'-----------------------------------------------------------------------------------
'Outputs random numbers with a period of > 2x10^18 in the range 0 to 1 (exclusive)
'Implements a L'Ecuyer generator with Bays-Durham shuffle
'Adapted from Numerical Recipes in C
'-----------------------------------------------------------------------------------
'Defining constants
Const IM1 As Double = 2147483563
Const IM2 As Double = 2147483399
Const AM As Double = (1.0# / IM1)
Const IMM1 As Double = (IM1 - 1.0#)
Const IA1 As Double = 40014
Const IA2 As Double = 40692
Const IQ1 As Double = 53668
Const IQ2 As Double = 52774
Const IR1 As Double = 12211
Const IR2 As Double = 3791
Const NTAB As Double = 32
Const NDIV As Double = (1.0# + IM1 / NTAB)
Const ESP As Double = 0.00000012
Const RNMX As Double = (1.0# - ESP)
Dim iCell As Integer
Dim idum As Double
Dim j As Integer
Dim k As Long
Dim temp As Double
Static idum2 As Long
Static iy As Long
Static iv(NTAB) As Long
idum2 = 123456789
iy = 0
'Seed value required is a negative integer (idum)
Randomize()
idum = (-Rnd() * 1000)
'For loop to generate a sequence of random numbers based on idum
For iCell = 1 To 10
'Initialize generator
If (idum <= 0) Then
'Prevent idum = 0
If (-(idum) < 1) Then
idum = 1
Else
idum = -(idum)
End If
idum2 = idum
For j = (NTAB + 7) To 0
k = ((idum) / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
If (j < NTAB) Then
iv(j) = idum
End If
Next j
iy = iv(0)
End If
'Start here when not initializing
k = (idum / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
k = (idum2 / IQ2)
idum2 = ((IA2 * (idum2 - (k * IQ2))) - (k * IR2))
If (idum2 < 0) Then
idum2 = idum2 + IM2
End If
j = (iy / NDIV)
iy = (iv(j) - idum2)
iv(j) = idum
If (iy < 1) Then
iy = (iy + IMM1)
End If
temp = AM * iy
If (temp <= RNMX) Then
'Return the value of the random number
UniformRandomNumber = temp
End If
Next iCell
End Function
End Module
You can use following line
Dim x1 as Double = MathNet.Numerics.Distributions.Normal.Sample(MEAN, STDEV)
Math.Net Numeric package can be installed using following NuGet command
Install-Package MathNet.Numerics -Version 4.9.0
You can found more information on NuGet site

Why does the getArea((l / 3), (n - 1) return only null value?

Why does the function getArea return NULL/Nothing
Module Module3
Dim noOfTriangles As Integer = (3 / 2)
Sub main()
Dim l As Single
Dim n As Integer
l = Console.ReadLine()
n = Console.ReadLine()
Console.WriteLine(getArea(l, n))
Console.ReadKey()
End Sub
Function getArea(ByVal l As Single, ByVal n As Integer)
Dim area As Single = 1
If n = 0 Then
Return Nothing
Else
noOfTriangles = noOfTriangles * 2
Return (((3 ^ (1 / 2)) / 4) * (l ^ 2) + (noOfTriangles * getArea((l / 3), (n - 1))))
End If
End Function
End Module
Try this and see if it gets you any closer to what you're looking for:
Module Module3
Dim noOfTriangles As double = (3 / 2)
Sub main()
Dim l As Single
Dim n As Integer
l = Single.Parse(Console.ReadLine())
n = Integer.Parse(Console.ReadLine())
Console.WriteLine(getArea(l, n))
Console.ReadKey()
End Sub
Function getArea(ByVal l As Single, ByVal n As Integer) as Double
Dim area As Single = 1
If n = 0 Then
Return Nothing
Else
noOfTriangles = noOfTriangles * 2
Return (((3 ^ (1 / 2)) / 4) * (l ^ 2) + (noOfTriangles * getArea((l / 3), (n - 1))))
End If
End Function
End Module