Curtis
Curtis

Reputation: 253

How is a local variable in another function affecting a variable in my main function?

So I have a "main" function (SolveSixODES) that calls a secondary function (AllODEs). And when it does this, the x value in the main function gets modified. I don't understand how this can be possible, seeing as it is not a global variable.

Here is the code, my inputs I used are as follows:

x=0, xmax=3, y=0-6, h=0.1, error=0.1

Public Function SolveSixODE(x As Double, xmax As Double, Y As Range, h As Double, error As Double) 'Weird bug: You must leave the first y4 value blank

Dim i As Integer, k(7, 7) As Double, j As Integer, m As Integer                                             'k(Order #, equation #)
Dim Y5(7) As Double, Y4(7) As Double, Y4Old(7) As Double
Dim delta0(7) As Double, delta1(7) As Double, delRatio(7) As Double, Rmin As Double

For i = 1 To 6                  'Moving the input data so it can acutally be used
    Y4(i) = Y(i)
Next i

While x < xmax

    If x + h < xmax Then
        x = x + h
    Else
        h = xmax - x
        x = xmax
    End If

    For j = 1 To 6                                                          'j is the order i is equation number
        For i = 1 To 6                                                      'Calculating all of the k(1) values for eq 1 to 6
            k(j, i) = AllODES(x, Y4, i, j, k, h)    '!!!!!SOME HOW THIS LOOP MAKES X negative...!!!!!!!
        Next i
    Next j

    For i = 1 To 6
        Y4Old(i) = Y4(i)                                                    'Saving old y4 value to calc delta0
        Y4(i) = Y4(i) + h * (k(1, i) * (37 / 378) + k(3, i) * (250 / 621) + k(4, i) * (125 / 594) + k(6, i) * (512 / 1771))
        Y5(i) = Y4(i) + h * (k(1, i) * (2825 / 27648) + k(3, i) * (18575 / 48384) + k(4, i) * (13525 / 55296) + k(5, i) * (277 / 14336) + k(6, i) * (0.25))

        delta0(i) = error * (Abs(Y4Old(i)) + Abs(h * AllODES(x, Y4Old, i, 1, k, h)))  'First order because we don't want to use the k vals
        delta1(i) = Abs(Y5(i) - Y4(i))
        delRatio(i) = Abs(delta0(i) / delta1(i))                                'Ratio of errors
    Next i

    Rmin = delRatio(1)

    For i = 2 To 6
        If delRatio(i) < Rmin Then
            Rmin = delRatio(i)                                              'Determine the smallest error ratio
        End If
    Next i

    If Rmin < 1 Then                                                        'If this is true then the step size was too big must repeat step
        x = x - h                                                           'Set x and y's back to previous values
        For i = 1 To 6
            Y4(i) = Y4Old(i)
        Next i
        h = 0.9 * h * Rmin ^ 0.25                                           'adjust h value; 0.9 is a safety factor
    Else
        h = 0.9 * h * Rmin ^ 0.2                                            'Otherwise, we march on
    End If
    m = m + 1
Wend

SolveSixODE = Y4

End Function

Public Function AllODES(x As Double, Y() As Double, EqNumber As Integer, order As Integer, k() As Double, h As Double) As Double

Dim conc(7) As Double, i As Integer, j As Integer

If order = 1 Then
    x = x - h
    For i = 1 To 6                                              'Movin the data so I can use it
        conc(i) = Y(i)                                          'also adjusting the x and y values for RK4 (Cash Karp values)
    Next i

ElseIf order = 2 Then
    x = x - h + h * 0.2
    For i = 1 To 6
        conc(i) = Y(i) + h * k(1, i) * 0.2
    Next i

ElseIf order = 3 Then
    x = x - h + 0.3 * h
    For i = 1 To 6
        conc(i) = Y(i) + h * (0.075 * k(1, i) + 0.225 * k(2, i))
    Next i

ElseIf order = 4 Then
    x = x - h + 0.6 * h
    For i = 1 To 6
        conc(i) = Y(i) + h * (0.3 * k(1, i) - 0.9 * k(2, i) + 1.2 * k(3, i))
    Next i

ElseIf order = 5 Then
    x = x - h + h
    For i = 1 To 6
        conc(i) = Y(i) + h * ((-11 / 54) * k(1, i) + 2.5 * k(2, i) - (70 / 27) * k(3, i) + (35 / 27) * k(4, i))
    Next i

ElseIf order = 6 Then
    x = x - h + 0.875 * h
    For i = 1 To 6
        conc(i) = Y(i) + h * ((1631 / 55296) * k(1, i) + (175 / 512) * k(2, i) + (575 / 13824) * k(3, i) + (44275 / (110592) * k(4, i) + (253 / 4096) * k(5, i)))
    Next i
Else
    MsgBox ("error")
End If


If EqNumber = 1 Then                                            'These are the actual equations
    AllODES = x + Y(1)

ElseIf EqNumber = 2 Then
    AllODES = x

ElseIf EqNumber = 3 Then
    AllODES = Y(3)

ElseIf EqNumber = 4 Then
    AllODES = 2 * x

ElseIf EqNumber = 5 Then
    AllODES = 2 * Y(2)

ElseIf EqNumber = 6 Then
    AllODES = 3 * x

Else
    MsgBox ("You entered an Eq Number that was dumb")
End If

End Function

It's possible that it is something really trivial that I missed but this seems to contradict my knowledge of how variables work. So if you understand how the function is able to manipulate a variable from another function in this case, I would appreciate any advice and/or explanation!

Thanks in advance!

Upvotes: 0

Views: 31

Answers (1)

A.S.H
A.S.H

Reputation: 29352

the x value in the main function gets modified. I don't understand how this can be possible, seeing as it is not a global variable

This is normal because you are passing x by reference to the function AllODES and you do change it there. When the keyword ByVal is not explicitly specified in the function/sub prototype, the default passing mechanism is ByRef, that is, by reference.

Public Function AllODES(x As Double, ...

means

Public Function AllODES(ByRef x As Double, ....

We observe that x is manipulated in this function, so the change will appear in the caller. If you want that the change of x does not report back in the caller's scope, pass x by value:

Public Function AllODES(ByVal x As Double, ....
'                       ^^^^^

Only in this case the x of the caller and the x of the callee will be two different variables.

Upvotes: 3

Related Questions