What I currently have:
Option Explicit
Function Triangular(a As Double, b As Double, c As Double) As Double
Randomize
Application.Volatile
Dim d As Double
Dim uniform As Double
Dim retval as Double
d = (b - a) / (c - a)
uniform = Rnd()
If uniform <= d Then
Triangular = a + (c - a) * Sqr(d * uniform)
Else
Triangular = a + (c - a) * (1 - Sqr(1 - d) * (1 - uniform))
End If
End Function
I'm having trouble in regards to creating a triangular distribution function in VBA, which calculates a random number from arguments made from:
Calculate d = ( b - a )/( c - a )
Generate a uniformly distributed random number U between 0 and 1 with VBA's Rnd function.
If U <= d, return a + ( c - a ) × sqr(d×U) as the random number. (Sqr(x) is a VBA function which returns the square root of x.
If U > d , return a + ( c - a ) × (1 - sqr((1- d )×(1-U))) as the random number.
The parameters a and c are the minimum and maximum possible values respectively, and
the parameter b is the most likely value (where you see the high point in the triangle).
I'm unsure on how to create this function and was wondering if someone could lend a hand? In working on the function I realize I need to use randomize function in order to not generate similar results each time the function is called, as well as the application.volatile operation.
You have a bug in the code. Should be in second branch
Triangular = a + (c - a) * (1 - Sqr((1 - d) * (1 - uniform)))
Not sure of the correctness of your generating equations. Take a look Here for the correct equations; with the difference that b and c are switched with respect to your definition. Here's an implementation adapting the formulas of that page to your own definitions of a, b and c:
Function Triangular(a As Double, b As Double, c As Double) As Double
Application.Volatile
Dim U As Double: U = Rnd()
If U < (b - a) / (c - a) Then
Triangular = a + sqrt(U * (b - a) * (c - a))
Else
Triangular = c - sqrt(U * (c - b) * (c - a))
End If
End Function
To generate a sequence from the above distribution in a new Worksheet, you can
1- Create the new worksheet
2- Write your parameters in cells A1, B1 and C1
3- write this formula in A2: =Triangular($A$1, $B$1, $C$1)
4- Copy/Paste cell A2 down the column
Please notice (1-Prob) in the second case. The Wikipedia link shows the correct formula but it was not implemented correctly by A.S.H.
Function Triangular(ByVal Min As Single, ByVal ML As Single, ByVal Max As Single) As Single
Application.Volatile
Dim Prob As Single
Prob = Rnd
If Prob < (ML - Min) / (Max - Min) Then
Triangular = Min + Sqr(Prob * (ML - Min) * (Max - Min))
Else
Triangular = Max - Sqr((1 - Prob) * (Max - ML) * (Max - Min))
End If
End Function
Related
I have a table consisting of 3 different categories : MainLand, Island, City ; each one has 2 different possible values where one is assigned to them depending on 'weight'. If 'Weight' <= 2kg then our output, 'Cost', is eg. 1.2 (for Mainland or 1.3 for island etc). If 'weight' >2kg , we need to round it to the nearest integer , then calculate 0.3(for mainland or 0.9 for island etc) times the extra integers above 2kg. The cost then will be the original value for the first 2kg and then add up the decimal of each area times the extra integers . I tried creating my own function to select 3 cells and do the calculation since it seemed too complex for linear functions given from excell.
But I always get an error...
Note all variable values are from user-selected cells and the Location value simply checks which text there is inside the cell to assign the proper numbers for calculation.
Thats what I have so far... Any tips?
Function TotalCost(ByVal tmx As Integer, ByVal weight As Double, _
ByVal Location As Text)
Dim b As Integer
Dim c As Integer
Dim d As Integer
d = 0
c = 0
f = 0
If Location Like "Mainland" And weight <= 2 Then
TotalCost = 1.2
ElseIf Location Like "Mainland" And weight > 2 Then
weight = Round(weight, 0)
c = weight - 2
Do While c > 0
c = c - 1
d = d + 1
Loop
TotalCost = tmx * ((d * 9.55) + 1.2)
ElseIf Location Like "City" And weight <= 2 Then
TotalCost = 1.1
ElseIf Location Like "City" And weight > 2 Then
weight = Round(weight, 0)
c = weight - 2
Do While c > 0
c = c - 1
d = d + 1
Loop
TotalCost= tmx * ((d * 0.55) + 1.1)
ElseIf Location Like "Island" And weight <= 2 Then
TotalCost = 1.3
ElseIf Location Like "Island" And weight > 2 Then
weight = Round(weight, 0)
c = weight - 2
Do While c > 0
c = c - 1
d = d + 1
Loop
TotalCost= tmx * ((d * 0.7) + 1.3)
End If
End Function
Something more like this might be better:
Function TotalCost(ByVal tmx As Integer, ByVal weight As Double, _
ByVal Location As String)
Dim base As Double, mult As Double, tot As Double, wtExtra As Double
Select Case Location
Case "Mainland"
base = 1.2
mult = 9.55
Case "City"
base = 1.1
mult = 0.55
Case "Island"
base = 1.3
mult = 0.7
Case Else
TotalCost = "?Location?"
Exit Function
End Select
If weight > 2 Then
'round up to nearest kg and subtract 2
wtExtra = Application.Ceiling(weight, 1) - 2
TotalCost = tmx * ((wtExtra * mult) + base)
Else
TotalCost = base
End If
End Function
You can do your calculation with a relatively simple formula but it needs a little preparation, some of which is the same you will need for the UDF as well. Here is the formula. I'll explain it in detail below.
=VALUE(INDEX(Rates,1,MATCH($F$2,$B$1:$D$1))+(INDEX(Rates,2,MATCH($F$2,$B$1:$D$1))*(-INT($G$2/-2)-1)))*INT(MAX($H$2,1))
First, the setup.
I placed the table you published in your question into a range A1:D3.
I created a named range for the numbers, B1:D3, and called it Rates
Then I created a Validation drop-down in F2 which refers to the range B1:D1 ("City", "Mainland" "Islands")
I marked cell G2 for entering the Weight
And H2 for entering the quantity of parcels.
Next the preparations.
[G6] =MATCH(F2,B1:D1) returns 1, 2 or 3 depending upon what is selected in F2
[G7] =(-INT(G2/-2)-1) returns the number of surcharges for extra weight, like 0 for anything up to 2(kg), 1 for 2.1 to 4.0, 2 for 2.1 to 6.0 etc.
[G5] =INT(MAX(H2,1))
All of these formulas must be tested individually by checking their results while F2:H2 are being changed. (I did that.) That leads to the basic formula.
=INDEX(Rates,1,G6)+(INDEX(Rates,2,G6)*G7)
and, because it's a string,
=VALUE(INDEX(Rates,1,G6)+(INDEX(Rates,2,G6)*G7))
and, to multiply with the number of parcels,
=VALUE(INDEX(Rates,1,G6)+(INDEX(Rates,2,G6)*G7))*G5
Now all that remains to be done is to replace G5, G6 and G7 in the above with the formulas in G5, G6 and G7. Then add $ signs to enable copying of the formula and you get the result first above offered.
I'm currently working on a program to do 4th order Runge Kutta calculations for ordinary differential equations., one of the requirements for the program is that the user will input the equation they want the 4th order operation to calculate. Is there a way to take the user inputted equation from a specific cell and use it in VBA sub to calculate the new y values?
The equations are going to be multi-variable polynomial equations containing x and y.
This is the loop I am hoping to use to perform the calculation, where equa is currently a function with a pre-established equation for testing, but is planned to be the user inputted equation.
n = (xf - xi) / h
For i = 1 To n
k1 = equa(x, y)
y1 = y + k1 * h / 2
k2 = equa(x + h / 2, y1)
y2 = y + k2 * h / 2
k3 = equa(x + h / 2, y2)
y3 = y + k3 * h / 2
k4 = equa(x + h, y3)
yf = y + ((k1 + 2 * k2 + 2 * k3 + k4) * (1 / 6) * h)
Cells(7 + i, 1).Value = y
x = x + h
Next i
Simple example using Evaluate:
Debug.Print Resolve("2*<x> + 3*<y>",1,2) '>>8
Function Resolve(sEq As String, x, y)
Resolve = Application.Evaluate(Replace(Replace(sEq, "<x>", x), "<y>", y))
End Function
Whenever I try to use RANDBETWEEN(Value1,Value2), it almost equally distribute the numbers randomly.
How to generate random number in an unequal manner?
Example -
The above randbetween formula distributed both "Yes" & "No" equally.
And I want more of "Yes" than "No"
You can skew your randbetween values in your favour with the following:
=IF(RANDBETWEEN(1,10)>2,"YES","NO")
You can change the >2 bit to any number between 1 and 10 to determine how much you want to go either side.
Use inverse functions to get different distributions. The function below shows how I implemented multiple inverse functions into one
Dist = the distribution type
a,b,c = parameters of the distribution like minimum, mode, maximum
Prob = rand()
If you pass multiple random values (between 0 and 1) the result from the function will end up with the shape of the distribution you've selected.
Function DistInv(Dist, a, b, c, Prob) As Single
If Dist = "Single" Then
' this is a single value to be used
DistInv = a
ElseIf Dist = "Binomial" Then
' binomial is like a coin flip. Only has a value of 1 or 0. 'a' determines the cut off point
If Abs(Prob) > a Then
DistInv = 0
Else
DistInv = 1
End If
ElseIf Dist = "Random" Then
' uniform distribution between 0% and 100%
DistInv = Prob
ElseIf Dist = "Rand Between" Then
' uniform distribution between the given parameters
DistInv = Prob * (b - a) + a
ElseIf Dist = "Triangular" Then
' Triangular distribution with a = lowest value, b = most likely value and c = highest value
a1 = 1 / ((b - a) * (c - a))
b1 = -2 * a / ((b - a) * (c - a))
C1 = a ^ 2 / ((b - a) * (c - a))
a2 = -1 / ((c - b) * (c - a))
b2 = 2 * c / ((c - b) * (c - a))
C2 = ((c - b) * (c - a) - c ^ 2) / ((c - b) * (c - a))
DistInv = ((-4 * a1 * C1 + 4 * a1 * Prob + b1 ^ 2) ^ (1 / 2) - b1) / (2 * a1)
If DistInv > b Then
DistInv = ((-4 * a2 * C2 + 4 * a2 * Prob + b2 ^ 2) ^ (1 / 2) - b2) / (2 * a2)
End If
ElseIf Dist = "Norm Between" Then
' normal distribution between the given parameters
DistInv = WorksheetFunction.NormInv(Prob, (a + b) / 2, (b - a) / 3.29)
ElseIf Dist = "Norm Mean Dev" Then
' Normal distribution with the average.norm and standard deviation
DistInv = WorksheetFunction.NormInv(Prob, a, b)
ElseIf Dist = "Weibull" Then
' Weibull distribution of probability
'
' inverse of Cumulative Weibull Function
' for a cumulative Weibull distribution F = 1- exp(-((x-c)/b)^a)
' where a is the shape parameter
' b is the scale parameter and
' c is the offset
'
' then solving for x
'
' x = c + b * (-log(1-Prob))^a
DistInv = c + b * (-Log(1 - Prob)) ^ (1 / a)
End If
End Function
To get twice as many "Yes" as "No":
=CHOOSE(RANDBETWEEN(1,3),"Yes","Yes","No")
If you want more Yes than No, make the formula in the Yes cell RANDBETWEEN(Value1,Value2)+RANDBETWEEN(Value3,Value4)
Try ROUND(RANDBETWEEN(RAND(),2),0)... there will be more values in the 1-2 interval than 0-1
Could you please give me vba code that can solve this problem:
I want remainder in Mod Function can become equal to divisor.
Example: In normal situation Mod(132,12)=0 but I want when remainder is equal to divisor, last step of dividing that is dividing 12 on 12 doesn't do and remainder becomes 12.
Example
I wrote this code but it seems something is wrong. What's the problem?
Function XLMod(a, b)
XLMod = Int(a - (b * Int(a / b)))
If XLMod(a / 10, b) = 1 And XLMod(a, 10) = 2 Then
XLMod = b
End If
End Function
You need a special exception of the standard modulo function.
If the result of a normal division (a / b) would result in a number ending with 1 (e. g. 1, 31, 10001, 12341, ...), then you want it to return b.
Function XLMod(a, b)
XLMod = a Mod b
If XLMod = 0 And (a / b) Mod 10 = 1 Then XLMod = b
End Function
Is it possible to solve a system of three equations in Excel, that contain x*y??
Let's suppose that my unknowns are a,b,x
The equations are
a + b = 1
a * x - 20y = 0
10x * a - 20a + b = 0
Is there a way to express the multiplier that is one of my unknowns??
here you can take z=x*a then your equations become:
a + b = 1
z - 20y = 0
10z - 20a + b = 0
Now solve these equation using simple method given here. You get value of z and a. Now you can find value x. So finally you get value of a, b, z, y