Using Recursive Functions in VB.net - vb.net

I found this piece of code in MSDN documentation as an example of recursive functions: The link is provided below:
https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/procedures/recursive-procedures
Function Factorial(n As Integer) As Integer ......'statement 1
If n <= 1 Then
Return 1
End If
**Return Factorial(n - 1) * n** 'Statement II: Not understanding how this helps calculating the factorial
End Function
Although I do understand how recursive functions work, I do not understand how statement II is calculating the factorial. For example say we enter n =5, in the first step. Then as per my understanding the first part of the statement II Return **Factorial(n - 1)** shall call the Factorial function in statement I and send the parameter n-1 = 4. And this is where my first question is: When we are calling Factorial function in statement I from statement II and passing the parameter (n-1) which equals 4 we are also multiplying it by n....what exactly are we returning in statement II...? In other words can someone explain in a step by step manner how the factorial value is getting calculated?
Also i tried using this piece of code to write a full program but unfortunately i could not make it work. To make it work I had to introduce a second parameter in the Factorial function - a parameter that would actually store the calculated value. I have provided the code below. My second question is: Is it possible to simplify the code I have written...the idea is not to use the second parameter "fact"...Is that possible?
The code that I wrote is as follows:
Module Module1
Sub Main()
Dim number As Integer
Dim fact As Integer = 1
Console.Write("Please enter number: ")
number = Console.ReadLine()
Factorial(number, fact)
Console.ReadLine()
End Sub
Function Factorial(ByVal n As Integer, ByVal fact As Integer) As Integer
If n > 0 Then
Console.WriteLine("Current Value of n = {0}", n)
End If
If n < 1 Then
Console.WriteLine("Factorial = {0}", fact)
Return 1
End If
fact = fact * n
Return Factorial(n - 1, fact)
End Function
End Module

Given the recursive function:
Function Factorial(n As Integer) As Integer
If n <= 1 Then
Return 1
End If
Return Factorial(n - 1) * n
End Function
And a initial call with value of 5:
Dim result As Integer = Factorial(5)
You'd get this sequence:
Call What gets returned
---- -----------------------
F(5) Return Factorial(4) * 5
F(4) Return Factorial(3) * 4
F(3) Return Factorial(2) * 3
F(2) Return Factorial(1) * 2
F(1) Return 1
When we get to F(1), we return a 1, then we "unwind" and move backwards up the call chain, substituting the return value into the previous line where the recursive call was. At each point during the unwind, a new integer value will be calculated (and returned) until we end up with the final answer that gets returned by the original recursive call and assigned to the "result" variable:
Return 1
Return 2 ' 1 * 2
Return 6 ' 2 * 3
Return 24 ' 6 * 4
Return 120 ' 24 * 5

If you're just interested in learning how recursion works then Idle_Mind's answer is good. However, if you just want to computer the factorial of a number, this is much simpler:
Dim Factorial As Integer = 1
For i As Integer = 1 To N
Factorial *= i
Next
where N is the number for which the factorial is desired.

Related

Why does the "Double" data type mess up my Fibonacci sequence?

I am trying to write a program which gives me the index of the first 1000-digit number in the Fibonacci sequence. I have set the data type as "Double" because I need to store the long numbers, however the output I get isn't right?
I have tried setting the "num" data type as "integer", "long" and even "int64", but all these just give me an overflow error after about 2 seconds.
Dim num, prev, temp, index As Double
Sub Main()
num = 1
prev = 1
temp = 1
index = 1
While Len(num) < 1000
Console.WriteLine(num)
temp = num
num += prev
prev = temp
index += 1
End While
Console.WriteLine(index)
Console.ReadLine()
End Sub
I would expect the program to output the Fibonacci sequence until it finds the first 1000-digit number, and then it will output the index of it. However, I just get an output of loads of decimal numbers (to about 20 decimal points) and then it outputs 8. Forever.
I am truly stumped. Any ideas?
The precision of a double data type does not allow you to store so many digits.
If you use BigInteger you can store as many digits as you can, as the data type grows its storage according to your needs.
Additionally, as suggested by the comments, a quick and dirty way to stop after 1000 digits is to have the number converted to string and check its length. This way you are not using mathematical operations which would result in an overflow.
Your code should look like the following:
Dim num, prev, temp, index As BigInteger
Sub Main()
num = 1
prev = 1
temp = 1
index = 1
While BigInteger.Log10(num) <= 999
Console.WriteLine(num)
temp = num
num += prev
prev = temp
index += 1
End While
Console.WriteLine(index)
Console.ReadLine()
End Sub
It all comes down to no data types in vb being able to hold a 1000 digit number. If I were you I would have an array with 1000 items and have each item be a digit.

VBA optimization - function with multiple args

Hi I am trying to create a function that takes as input a few parameters (irrelevant to the variables optimized) and a variable over which I want to optimize. For example for foo_function(a,b,c,x) I want to pass a,b,c as fixed parameters to foo_function, and finding the minimum of foo_function by changing x. If I was able to work in Matlab or Python this should be relatively easy as a function can return a handle to another function, but that's not possible in VBA. Im trying to use the code in http://www.quantcode.com/modules/mydownloads/singlefile.php?lid=424
Does anybody have any idea how to proceed?
You can declare foo_function to take a parameter array, treat it as a function of 1 variable if only 1 parameter is passed, and if more than 1 is passed, you can store the parameters in static variables. This allows your calling code to set the parameters of foo_function before passing its name to optimization code which will treat it as a function of 1 variable.
As a proof of concept, the following function represents a quadratic function:
Function quad(ParamArray args()) As Double
Dim x As Double
Static a As Double
Static b As Double
Static c As Double
If UBound(args) = 0 Then
x = args(0)
Else 'assumes that at least 3 parameters passed
a = args(0)
b = args(1)
c = args(2)
If UBound(args) = 3 Then
x = args(3)
Else
Exit Function 'function call just initializes statics
End If
End If
quad = a * x ^ 2 + b * x + c
End Function
When just 1 is passed, quad(x) just evaluates ax^2 + bx + c with its current values for those coefficients. If 4 is passed then it is interpreted as a call to quad(a,b,c,x), with the obvious meaning. If just 3 parameters are passed, it is called like a sub:
quad a,b,c
and doesn't return anything but sets the static parameters to the passed values.
To test it, I wrote a crude numerical differentiation function:
Function Derivative(f As String, x As Double, h As Double) As Double
Derivative = (Application.Run(f, x + h) - Application.Run(f, x)) / h
End Function
This approximates the derivative of f at the given x value using the given step size.
The following test sub shows how quad can be set before passing it the the derivative function:
Sub test()
quad 1, 2, -3 'initializes quad to be x^2 + 2x - 3
Debug.Print Derivative("quad", 2, 0.0001) 'should be approximately 6
quad 3, 2, 1
Debug.Print Derivative("quad", 2, 0.0001) 'now around 14
End Sub
Output:
6.00010000001205
14.0003000000277
Another, in some ways simpler, approach is to use public variables instead of actual parameters for the parameters to foo_function that are irrelevant to the variables being optimized. Then the calling code could assign to these public variables before optimizing. This approach would eliminate the need for parameter arrays but has the drawback of using global-type variables which tend to make programs not sufficiently modular.

Linq statement vs For loop in VB.NET for Project Euler P1: why the result is different?

I am just trying to experience myself the use of For Loop vs. Linq statement in VB.NET. However, I've found a difference in a result of which I found interesting, but had no clue why it 's happening. (I am trying to find the sum of all the multiples of 3 or 5 below 1000.) Below are my two ways of doing that:
method 1: For loop
Dim sum1 As Integer = 0
For i As Integer = 0 To 999
If i Mod 3 = 0 Or i Mod 5 = 0 Then
sum1 += i
End If
Next
Method 2: Linq statement
Dim sum2 As Integer = Enumerable.Range(0, 999).Where(Function(x As Integer) x Mod 3 = 0 Or x Mod 5 = 0).Sum
Obviously method 2 is shorter and of more functional style. But interestingly, I found that Sum1 = 233168 and Sum2 = 232169 which is different by 1001. Can anyone please tell me why it's happening? Thank you.
For loop is inclusive, so you get 1000 numbers (0 to 999). Enumerable.Range will give you 999 numbers, because that's what you asked it for passing 999 as second parameter (0 to 998).
999 is the one that makes the difference.
Ok I've found it, my very simple mistake: Enumerable.Range(start,count) which I thought as if it were Enumerable.Range(firstNumber, lastNumber).

Overflow exception?

I have the following code for finding factorials:
Private Shared Function Factorial(ByVal Number As Long) As Long
If Number = 0 Then
Return 1
Else
Return Number * Factorial(Number - 1)
End If
End Function
It usually results in an overflow. It only works if I start with something small like 4.
I have to work with starting numbers such as 30-60.
Any ideas? I thought changing the value type to LONG would prevent this problem.
This is VB.net just for reference.
Factorials get very large, very quickly. The largest number that will fit in a Long is about 9×10^18. Factorial(30) is about 2.7×10^32.
If you're using .Net 4 there is a built-in BigInteger class that you can use which will hold arbitrarily large numbers.
If you're not using .Net 4, you'll need to find and download a BigInteger library, for example intx.
You get the overflow exception only with integer and long types. To avoid that, you can use System.Double or System.Numerics.BigInteger (or BigDecimal I think).
For example,
if you run 3 different versions of the factorial: 1 with long, 1 with double and 1 with biginteger as follow with a range of values of 5 to 50 by 5:
'Long Factorial
Public Function FactorialInt64(ByVal n As Integer) As Int64
If n = 1 Then
Return 1
Else
Return n * FactorialInt64(n - 1)
End If
End Function
' Double Factorial
Public Function FactorialDouble(ByVal n As Integer) As Double
If n = 1 Then
Return 1
Else
Return n * FactorialDouble(n - 1)
End If
End Function
' BigInteger Factorial
Public Function FactorialBigInteger(ByVal n As Integer) As BigInteger
If n = 1 Then
Return 1
Else
Return n * FactorialBigInteger(n - 1)
End If
End Function
You will get a result like this:
You can find the complete source code in my blog post: Factorial and Fibonacci in VB.NET
There is a big int Library for .NET that will solve your problem. It can manipulate very large number (limited only by your system memory).
Here is the link: http://www.emilstefanov.net/Projects/GnuMpDotNet/

Rounding a number to the nearest 5 or 10 or X

Given numbers like 499, 73433, 2348 what VBA can I use to round to the nearest 5 or 10? or an arbitrary number?
By 5:
499 -> 500
2348 -> 2350
7343 -> 7345
By 10:
499 -> 500
2348 -> 2350
7343 -> 7340
etc.
It's simple math. Given a number X and a rounding factor N, the formula would be:
round(X / N)*N
Integrated Answer
X = 1234 'number to round
N = 5 'rounding factor
round(X/N)*N 'result is 1235
For floating point to integer, 1234.564 to 1235, (this is VB specific, most other languages simply truncate) do:
int(1234.564) 'result is 1235
Beware: VB uses Bankers Rounding, to the nearest even number, which can be surprising if you're not aware of it:
msgbox round(1.5) 'result to 2
msgbox round(2.5) 'yes, result to 2 too
Thank you everyone.
To round to the nearest X (without being VBA specific)
N = X * int(N / X + 0.5)
Where int(...) returns the next lowest whole number.
If your available rounding function already rounds to the nearest whole number then omit the addition of 0.5
In VB, math.round has additional arguments to specify number of decimal places and rounding method. Math.Round(10.665, 2, MidpointRounding.AwayFromZero) will return 10.67 . If the number is a decimal or single data type, math.round returns a decimal data type. If it is double, it returns double data type. That might be important if option strict is on.
The result of (10.665).ToString("n2") rounds away from zero to give "10.67". without additional arguments math.round returns 10.66, which could lead to unwanted discrepancies.
'Example: Round 499 to nearest 5. You would use the ROUND() FUNCTION.
a = inputbox("number to be rounded")
b = inputbox("Round to nearest _______ ")
strc = Round(A/B)
strd = strc*B
msgbox( a & ", Rounded to the nearest " & b & ", is" & vbnewline & strd)
For a strict Visual Basic approach, you can convert the floating-point value to an integer to round to said integer. VB is one of the rare languages that rounds on type conversion (most others simply truncate.)
Multiples of 5 or x can be done simply by dividing before and multiplying after the round.
If you want to round and keep decimal places, Math.round(n, d) would work.
Here is our solution:
Public Enum RoundingDirection
Nearest
Up
Down
End Enum
Public Shared Function GetRoundedNumber(ByVal number As Decimal, ByVal multiplier As Decimal, ByVal direction As RoundingDirection) As Decimal
Dim nearestValue As Decimal = (CInt(number / multiplier) * multiplier)
Select Case direction
Case RoundingDirection.Nearest
Return nearestValue
Case RoundingDirection.Up
If nearestValue >= number Then
Return nearestValue
Else
Return nearestValue + multiplier
End If
Case RoundingDirection.Down
If nearestValue <= number Then
Return nearestValue
Else
Return nearestValue - multiplier
End If
End Select
End Function
Usage:
dim decTotal as Decimal = GetRoundedNumber(CDec(499), CDec(0.05), RoundingDirection.Up)
Simply ROUND(x/5)*5 should do the job.
I cannot add comment so I will use this
in a vbs run that and have fun figuring out why the 2 give a result of 2
you can't trust round
msgbox round(1.5) 'result to 2
msgbox round(2.5) 'yes, result to 2 too
something like that?
'nearest
n = 5
'n = 10
'value
v = 496
'v = 499
'v = 2348
'v = 7343
'mod
m = (v \ n) * n
'diff between mod and the val
i = v-m
if i >= (n/2) then
msgbox m+n
else
msgbox m
end if
Try this function
--------------start----------------
Function Round_Up(ByVal d As Double) As Integer
Dim result As Integer
result = Math.Round(d)
If result >= d Then
Round_Up = result
Else
Round_Up = result + 1
End If
End Function
-------------end ------------
I slightly updated the function provided by the "community wiki" (the best answer), just to round to the nearest 5 (or anything you like), with this exception : the rounded number will NEVER be superior to the original number.
This is useful in cases when it is needed to say that "a company is alive for 47 years" : I want the web page to display "is alive for more than 45 years", while avoiding lying in stating "is alive for more than 50 years".
So when you feed this function with 47, it will not return 50, but will return 45 instead.
'Rounds a number to the nearest unit, never exceeding the actual value
function RoundToNearestOrBelow(num, r)
'#param num Long/Integer/Double The number to be rounded
'#param r Long The rounding value
'#return OUT Long The rounded value
'Example usage :
' Round 47 to the nearest 5 : it will return 45
' Response.Write RoundToNearestBelow(47, 5)
Dim OUT : OUT = num
Dim rounded : rounded = Round((((num)) / r), 0) * r
if (rounded =< num) then
OUT = rounded
else
OUT = rounded - r
end if
'Return
RoundToNearestOrBelow = OUT
end function 'RoundToNearestOrBelow
To mimic in Visual Basic the way the round function works in Excel, you just have to use:
WorksheetFunction.Round(number, decimals)
This way the banking or accounting rounding don't do the rounding.