Why is a ByVal function changing my variable? - math.net

Calling divsig(h) results in changes to h. But divsig is a function that takes a matrix by value and not by reference. How can this happen?
I'm trying to use the sig/divsig functions on matrices of data, for example:
DenseMatrix 4x4-Double ' h before divsig(h)
0.5 0.5 0.5 0.5
0.568811 0.995811 0.418727 0.987232
0.65701 0.269138 0.990942 0.99298
0.716466 0.988705 0.98747 0.999909
divsig(h)
DenseMatrix 4x4-Double ' h after divsig
0.25 0.25 0.25 0.25
0.245265 0.00417185 0.243395 0.0126045
0.225348 0.196703 0.00897602 0.00697036
0.203142 0.0111678 0.0123732 9.14075E-05
Makes no sense to me what so ever, i'm even setting up a new variable called matrix in the function instead of editing 'mat' it's self.
Function divsig(ByVal mat As LinearAlgebra.Double.Matrix)
Dim matrix = mat
For _x = 0 To matrix.RowCount() - 1
For _y = 0 To matrix.ColumnCount() - 1
matrix(_x, _y) = derivsigmoid(matrix(_x, _y))
Next
Next
Return matrix
End Function
Function sigmoid(ByVal x As Double) As Double
Return 1 / (1 + Math.Exp(-x))
End Function
Function derivsigmoid(ByVal x As Double) As Double
Return x * (1 - x)
End Function
Function sig(ByVal mat As LinearAlgebra.Double.Matrix)
Dim matrix = mat
For _x = 0 To matrix.RowCount() - 1
For _y = 0 To matrix.ColumnCount() - 1
matrix(_x, _y) = sigmoid(matrix(_x, _y))
Next
Next
Return matrix
End Function

I have fixed it, turns out matrixes are classes which means passing them ByVal passes the reference anyway. I fixed it by replacing the Dim matrix = mat with
Dim matrix As LinearAlgebra.Double.Matrix = LinearAlgebra.Double.Matrix.Build.DenseOfMatrix(mat)
So matrix becomes a copy of mat instead of just giving the same reference a different identifier.

Related

Take only non zero and non negative arguments in UDF of excel VBA

I have created a UDF to iterate an equation. The UDF is working fine. But, if the argument(s) is assigned zero or negative, say W = 0, then the excel freezes completely. I want to stop the execution of UDF or display errors if the argument(s) is zero or negative and prevent the file from freezing. Please help
Function myfunc(Q, W, n, s As Double) As Double
Dim Q_Cal As Double
' to initialize the loop
D = 0.001
Q_Cal = 0.001
While Q_Cal < Q
D = D + 0.001
Q_Cal = ((W * D) / n) * ((W * D) / (2 * D + W)) ^ (2 / 3) * s ^ 0.5
Wend
myfunc = Round(D, 3)
End Function

Calculating value of two-variable function in VBA function

I have a function f(x,y) = e^(x+y) and function in VBA like this:
Function Test(n As Integer, x0 As Double, xk As Double, y0 As Double, yk As Double) As Double()
Dim i As Integer
Dim j As Integer
Dim Tablica() As Double
ReDim Tablica(0 To n, 0 To n)
For i = 0 To n
For j = 0 To n
Tablica(j, i) = Exp(x0 + i * (xk - x0) / n + y0 + j * (yk - y0) / n)
Next j
Next i
Test = Tablica
End Function
Is there any way to rewrite this code to work with any function like f(x,y) = x+y etc.?
I interpret your question as how to make the mathematical function an input parameter to the function test. There is no very good way to do this in VBA, but what you can do is to define the function in the code module and then use Application.Run to invoke the function by name from inside test.
Proof of concept:
Function test(f As String, n As Integer, x0 As Double, xk As Double, y0 As Double, yk As Double) As Double()
Dim i As Long, j As Long
Dim Tablica() As Double
ReDim Tablica(0 To n, 0 To n)
For i = 0 To n
For j = 0 To n
Tablica(j, i) = Application.Run(f, x0 + i * (xk - x0) / n, y0 + j * (yk - y0) / n)
Next j
Next i
test = Tablica
End Function
'used like:
Function g(x As Double, y As Double) As Double
g = x - y
End Function
Sub test2()
Range("A1:D4").Value = test("g", 3, 0, 1, 3, 4)
End Sub
Note that you don't need to name the called function f, so that test can work with multiple functions. Unfortunately, VBA lacks a notion of anonymous functions, so you still need to defined your functions as VBA functions (or write your own parser).

Excel VBA method ROUND is incorrect

Public Function foo()
Dim x As Double, y As Double, z As Double
x = 1.26
y = 3.175
z = Round(x + y, 2)
foo = z
End Function
Running Excel 2007 on Windows 7. This function returns 4.43 into a cell with =foo() which is annoying as I want 4.44. I found some documentation claiming VBA ROUND uses even rounding but here the last digit is odd. What is wrong here?
You can always use the Worksheet Round Function instead of VBA's built-in one
Public Function foo2()
Dim x As Double, y As Double, z As Double
x = 1.26
y = 3.175
z = Application.WorksheetFunction.Round(x + y, 2)
foo2 = z
End Function
foo2 will result in 4.44 (tested on my machine). I don't know if this would affect performance at all.
You will need to use decimal types to accomplish this which uses integer based arithmetic as opposed to floating point based.
Excel doesn't have a native data type for this, so you have to use a Variant and then convert to a decimal using the CDec function.
Public Function foo()
Dim x As Variant, y As Variant, z As Variant
x = CDec(1.26)
y = CDec(3.175)
z = Round(x + y, 2)
foo = z
End Function
While Excel.WorksheetFunction.Round does perform correct 4/5 rounding, it is terribly slow and, of course, requires Excel to be installed.
For fast and precise rounding of any value - up, down, 4/5, Banker's, significant digits, Base 2 or Base 10, and more - go to my project VBA.Round.

MATLAB: Transforming a combination of strings as one

Let's say I have
a = [ 'i=' num2str(0)]
a =
i=0
and
A = zeros(2);
B = num2str(A)
B =
0 0
0 0
This i=0 is considered a 1x3 matrix: [ i, =, 0]. Now how do I transform this into one element so that I can replace B(1,1) with i=0? I want to get
B =
i=0 0
0 0
(This is the reason why I converted A into string.)
I kept getting this error:
Assignment has more non-singleton rhs dimensions than non-singleton
subscripts
which I suspect was due to a's dimension.
I've tried strcat(a), and some other methods.
Edit:
The motivation behind it is from my attempt to put in labels into a matrix while executing a loop.
This is the last portion of my code:
n5 = length(X(1, :));
n6 = length(X(:, 1)) + 1;
Y = zeros(n6, n5);
Y(2:n6, :) = X;
Z = num2str(Y, 4);
for i = 0:K
a = ['i=' num2str(i)];
Z(1,i+1) = a;
end
X = Z
end
I want the output to show:
i=0 i=1 ... i=K
1.0022 1.0000 ... 1.0000
2.0081 2.0000 ... 2.0000
4.0011 4.0000 ... 4.0000
3.9811 4.0000 ... 4.0000
I'm aware we can format the output in another way, but not in loops. I want to use loops.
Take 2:
I find it difficult to find a way to store in a matrix both strings (i=0...) as well as numbers. I would recommend the use of cell array
sz = size( X );
Z(2,:) = mat2cell( X, sz(1), ones(1,sz(2)) ); % convert each column of X into cell
Z(1,:) = arrayfun( #(x) sprintf('i=%d',x), 0:(sz(2)-1), 'uni', false );
The resulting cell array Z is of size 2x(n5) and would look like:
'i=0' 'i=1' 'i=2' 'i=3' 'i=4'
[5x1 double] [5x1 double] [5x1 double] [5x1 double] [5x1 double]
Where Z{2,ii} is the ii-th column of matrix X.

Convert string to long in excel macro

How can I convert string to long in excel macro. CLng is giving me type mismatch error
Dim wStr As String
Dim w As Long
wStr = "=RAND() * 0.3 + 0.35"
w = CLng(wStr)
The root cause of your error is that CDbl expects a numeric value or a string that looks like a number. the string "=RAND() * 0.3 + 0.35" itself does not look like a number, even though it will evaluate to a number.
What are you actually trying to achieve here?
If its to get a long integer result from the formula =RAND() * 0.3 + 0.35, use
Dim w as Long
w = Rnd() * 0.3 + 0.35
If its to emulate a cell formula use
Dim w as Long
w = Application.Evaluate("=RAND() * 0.3 + 0.35")
As to the formula itself, why this construct? It will return Single in the range [0.35, 0.65) which when rounded to a Long will return 0 or 1 at 50% probability of each.
Why not use
w = Rnd()
or
w = Application.Evaluate("=RAND()")
or
w = Application.WorksheetFunction.RandBetween(0, 1)
or is there some other reason I've missed?
Try the formula for w below.
w = CLng(Evaluate(wStr))
Or forget trying to use an "Excel formula", and go straight to VBA with with its random function counterpart
w = CLng(Rnd() * 0.3 + 0.35)

Resources