Subtraction between members of a list of double - vb.net

I'm creating a public function for 1D linear interpolation. I was asking if it could be possible to work with List of Double, instead of Double() because there arrays don't have fixed lenght, but it is parametric, depending on the number of rows inserted in a datagridview. I've tried to declare double() as list of double() but I'm receiving an error about subtraction between members - that seems to be not allowed. Here is the code:
Public Shared Function Interp1(ByVal xnative As Double(), ByVal ynative As Double(), ByVal xinterpol As Double()) As Double()
Dim yinterpol As Double()
For i = 1 To ynative.Length - 1
For j = 0 To xnative.Length - 1
If xinterpol(j) > xnative(i - 1) And xinterpol(j) < xnative(i) Then
yinterpol(j) = (ynative(i - 1) * (xinterpol(j) - xnative(i + 1)) / (xnative(i - 1) - xnative(i + 1))) - (ynative(i + 1) * (xinterpol(j) - xnative(i - 1)) / (xnative(i - 1) - xnative(i + 1)))
Else i += 1
End If
Next
If xinterpol(xinterpol.Length) > xnative(xnative.Length) Then
Exit For
End If
Next
End Function
Where am I doing wrong? I can't understand where the mistake can be. Other thing I was asking is, if with the provided code, yinterpol is the result of my function, because that is what I need to have as result. Thanks in advance
Edit: Here is the version of my code using List of Double():
Public Shared Function Interp1(ByVal xnative As List(Of Double)(), ByVal ynative As List(Of Double)(), ByVal xinterpol As List(Of Double)()) As List(Of Double)()
Dim yinterpol As New List(Of Double)()
For i = 1 To ynative.Length - 1
For j = 0 To xnative.Length - 1
If xinterpol(j) > xnative(i - 1) And xinterpol(j) < xnative(i) Then
yinterpol.add((ynative(i - 1) * (xinterpol(j) - xnative(i + 1)) / (xnative(i - 1) - xnative(i + 1))) - (ynative(i + 1) * (xinterpol(j) - xnative(i - 1)) / (xnative(i - 1) - xnative(i + 1))))
Else i += 1
End If
Next
If xinterpol(xinterpol.Length) > xnative(xnative.Length) Then
Exit For
End If
Next
End Function
I'm having back the error BC30452: operators "-", ">" and "<" are not defined for List of Double
Edit II: What I have to do with this function is to rebuild two list of double that I'm gonna type in the application through a Datagridview.
What I need to have is:
To rebuild the starting List, I have to implement a 1D linear interpolation function, in which, with the values in the column x-ending (from 0 to 106 in the example), I can obtain the y-ending. I've updated my code with your corrections but I think that my code is missing something to do what is my aim. I hope this is clearer now.

Your parameters for your function look like arrays of lists considering the trailing (). This can be used when declaring a New list to indicate you are calling the constructor, although in vb.net it is not necessary (unlike C#). You are asking calling code to provide and arrays of lists.
The error you are getting is because xinterpol(j) is the list present at index j in the array of list. Obviously you can't convert a List(Of Double) to a Double.
.Length is not available for List(Of T). You should use .Count
Your index j makes me a bit nervous. You are basing this on the .Count of xnative but applying it to xinterpol. What if xnative is longer than xinerpol? You are begging for an Index Out of Range exception.
I can't see why you want to possibly add a single item to yinterpol and then quit if the .Count of xinterpol is greater than the .Count of xnative
Public Shared Function Interp1(xnative As List(Of Double), ynative As List(Of Double), xinterpol As List(Of Double)) As List(Of Double)
Dim yinterpol As New List(Of Double)
For i = 1 To ynative.Count - 1
For j = 0 To xnative.Count - 1
If xinterpol(j) > xnative(i - 1) And xinterpol(j) < xnative(i) Then
yinterpol.Add((ynative(i - 1) * (xinterpol(j) - xnative(i + 1)) / (xnative(i - 1) - xnative(i + 1))) - (ynative(i + 1) * (xinterpol(j) - xnative(i - 1)) / (xnative(i - 1) - xnative(i + 1))))
Else i += 1
End If
Next
If xinterpol(xinterpol.Count) > xnative(xnative.Count) Then
Exit For
End If
Next
Return yinterpol
End Function

Re: The error you're receiving using arrays, you have a couple of issues here.
One is that you're not actually returning a value from the function.
Another is that you haven't initialized the yinterpol array with a size.
It's also good practice to declare the types of your indices rather than infer them (set Option Explicit on, Option Infer off and always set Option Strict on).
Try this:
Public Shared Function Interp1(ByVal xnative As Double(), ByVal ynative As Double(), ByVal xinterpol As Double()) As Double()
Dim yinterpol(9) As Double '<- Initialize array length
For i As Integer = 1 To ynative.Length - 1 '<- Declare type of i
For j As Integer = 0 To xnative.Length - 1 '<- Declare type of j
If xinterpol(j) > xnative(i - 1) AndAlso xinterpol(j) < xnative(i) Then
yinterpol(j) = (ynative(i - 1) * (xinterpol(j) - xnative(i + 1)) / (xnative(i - 1) - xnative(i + 1))) - (ynative(i + 1) * (xinterpol(j) - xnative(i - 1)) / (xnative(i - 1) - xnative(i + 1)))
Else
i += 1 '<- Don't modify outer loop index
End If
Next j
If xinterpol(xinterpol.Length) > xnative(xnative.Length) Then Exit For
Next i
Return yinterpol '<- Return a value
End Function
I prefer Lists over Arrays personally. Let me know if you want that version posted. Some sample data for the call would be helpful.
UPDATE: You shouldn't change a loop variable directly. So i += 1 within the "j" For is a bad idea. (In fact, I'm not even sure the changed value will persist in the outer "i" loop.)
List Version
You List example is using ARRAYs of List(of Double) on account of the trailing "()". Most of the other issues still apply, eg changing loop index, missing return value, etc.
Public Shared Function Interp1(ByVal xnative As List(Of Double), ByVal ynative As List(Of Double), ByVal xinterpol As List(Of Double)) As List(Of Double)
Dim yinterpol As New List(Of Double)
For i As Integer = 1 To ynative.Count - 1
For j As Integer = 0 To xnative.Count - 1
If xinterpol(j) > xnative(i - 1) AndAlso xinterpol(j) < xnative(i) Then
yinterpol.Add((ynative(i - 1) * (xinterpol(j) - xnative(i + 1)) / (xnative(i - 1) - xnative(i + 1))) - (ynative(i + 1) * (xinterpol(j) - xnative(i - 1)) / (xnative(i - 1) - xnative(i + 1))))
Else
i += 1
End If
Next j
If xinterpol(xinterpol.Count) > xnative(xnative.Count) Then Exit For
Next i
Return yinterpol
End Function

Related

Min function not working properly in VBA

I'm working on a macro right now and it's producing weird results. The part that is specifically not working is a Min function.
a1RowTemp1 = a1Row
For i = 0 To diff1
intercept = Application.WorksheetFunction.intercept(a(),c())
LinReg1 = (slope * Cells(a1RowTemp1, 1)) + intercept
difference1 = Worksheets("GF9").Cells(a1RowTemp1, 2) - LinReg1
e(i) = difference1
a1RowTemp1 = a1RowTemp1 + 1
Next i
a2RowTemp2 = a2Row
For i = 0 To diff2
intercept2 = Application.WorksheetFunction.intercept(b(), d())
LinReg2 = (slope2 * Cells(a2RowTemp2, 1)) + intercept2
difference2 = Worksheets("GF9").Cells(a2RowTemp2, 2) - LinReg2
f(i) = difference2
a2RowTemp2 = a2RowTemp2 + 1
Next i
Worksheets("Chart").Cells(currentRow, 12) = Application.Max(e())
Worksheets("Chart").Cells(currentRow, 13) = Application.Min(e())
Worksheets("Chart").Cells(currentRow, 25) = Application.Max(f())
Worksheets("Chart").Cells(currentRow, 26) = Application.Min(f())
In the bottom of the code it stores the difference1 and difference2 values in arrays e() and f(). When I use the functions max/min the macro only outputs the correct values for the max functions. I suspect this has something to do with my incorrectly using the arrays.
If e is one dimensional array you should be able to write
Application.WorksheetFunction.Min(e)
Example:
Option Explicit
Public Sub TEST()
Dim e()
e = Array(3, 4, 2, 5)
MsgBox Application.WorksheetFunction.Min(e)
End Sub
If you are still getting the wrong values you need to step though with F8 and check the values being assigned to e in the loop are the expected ones.
You've omitted the declaration and dimensioning of the e and f array. This was an important factor in your problem.
When you declared your e and f as long or double arrays, they were instantiated with zero values.
Dim v() As Double, i As Long
ReDim v(5) '<~~ all zero values
For i = LBound(v) To UBound(v) - 1 '<~~fill all but the last one
v(i) = i + 10
Next i
Debug.Print Application.Min(v) 'zero as v(5) is zero
If you want to ignore array elements that you have not assigned values to, declare the arrays as a variant type.
Dim v() As Variant, i As Long
ReDim v(5) '<~~ all empty values
For i = LBound(v) To UBound(v) - 1 '<~~fill all but the last one
v(i) = i + 10
Next i
Debug.Print Application.Min(v) '10 as v(5) is empty and not considered in Min
An unassigned variant array element is considered empty and is not used in the Min calculation.
Alternately, use one of two methods to remove unused array elements.
'...
'redimension before the loop to the known ubound
redim e(diff1)
For i = 0 To diff1
intercept = Application.WorksheetFunction.intercept(a(),c())
LinReg1 = (slope * Cells(a1RowTemp1, 1)) + intercept
difference1 = Worksheets("GF9").Cells(a1RowTemp1, 2) - LinReg1
e(i) = difference1
a1RowTemp1 = a1RowTemp1 + 1
Next i
'...
'or redimension after the loop with Preserve
For i = 0 To diff2
intercept2 = Application.WorksheetFunction.intercept(b(), d())
LinReg2 = (slope2 * Cells(a2RowTemp2, 1)) + intercept2
difference2 = Worksheets("GF9").Cells(a2RowTemp2, 2) - LinReg2
f(i) = difference2
a2RowTemp2 = a2RowTemp2 + 1
Next i
'i exits with a value 1 greater than diff2
redim preserve f(i-1)
'...

use of ByVal in VBA

During an interpolation scheme I had to write, I needed a minimum and maximum function so I quickly wrote functions Min and Max that are called from within my interpolation function. It looked like this:
Function interpolateVol(Strike As Double, Maturity As Double, coupon As Variant)
Dim i, k, j As Long
Dim timeIndex, strikeIndex As Long
Dim vol_minus1, vol_zero, volmin, volmax, vol As Double
Dim w1, w2 As Double
If coupon = "1M" Then
j = 3
ElseIf coupon = "3M" Then
j = 4
ElseIf coupon = "6M" Then
j = 5
End If
' we set i = 1 as the maturities do not matter for
' picking up the time index
If Maturity <= volatilityCube(1, 1, 2) Then
timeIndex = 1
ElseIf Maturity > volatilityCube(noMaturities, 1, 2) Then
timeIndex = noMaturities
Else
i = 1
While volatilityCube(i, 1, 2) < Maturity
i = i + 1
Wend
timeIndex = i ' volatilityCube(timeIndex-1,2) < Maturity <= volatilityCube(timeIndex,2)
End If
' we set k = 1 as the strikes do not matter for
' picking up the strike index
If Strike <= volatilityCube(1, 1, 1) Then
strikeIndex = 1
ElseIf Strike > volatilityCube(1, noStrikes, 1) Then
strikeIndex = noStrikes
Else
k = 1
While volatilityCube(1, k, 1) < Strike
k = k + 1
Wend
strikeIndex = k ' volatilityCube(strikeIndex-1,1) < Strike <= volatilityCube(strikeIndex,1)
End If
' first we interpolate on the tenors
' as a result we will have two interpolated values:
' one for timeIndex, another for timeIndex + 1
w1 = (Maturity - volatilityCube(timeIndex - 1, 1, 2)) / _
(volatilityCube(timeIndex, 1, 2) - volatilityCube(timeIndex - 1, 1, 2))
w2 = (volatilityCube(timeIndex, 1, 2) - Maturity) / _
(volatilityCube(timeIndex, 1, 2) - volatilityCube(timeIndex - 1, 1, 2))
vol_minus1 = w1 * volatilityCube(timeIndex - 1, strikeIndex - 1, j) + _
w2 * volatilityCube(timeIndex, strikeIndex - 1, j)
vol_zero = w1 * volatilityCube(timeIndex - 1, strikeIndex, j) + _
w2 * volatilityCube(timeIndex, strikeIndex, j)
' Now we have two vols interpolated in time, each for another strike.
' These two vols need to be interpolated in strikes:
volmin = Min(vol_minus1, vol_zero)
volmax = Max(vol_minus1, vol_zero)
w1 = (Strike - volatilityCube(1, strikeIndex - 1, 1)) / _
(volatilityCube(1, strikeIndex, 1) - volatilityCube(1, strikeIndex - 1, 1))
w2 = (volatilityCube(1, strikeIndex, 1) - Strike) / _
(volatilityCube(1, strikeIndex, 1) - volatilityCube(1, strikeIndex - 1, 1))
vol = w1 * volmin + w2 * volmax
interpolateVol = vol
End Function
Function Min(number1 As Double, number2 As Double) As Double
Dim var As Double
If (number1 < number2) Then
var = number1
Else
var = number2
End If
Min = var
End Function
Function Max(number1 As Double, number2 As Double) As Double
Max = number1 + number2 - Min(number1, number2)
End Function
However, running the code prompted the `byref argument type mismatch' error. As it turns out, I had to make explicit that I pass values and not references by adding ByVal to the function arguments:
Function Min(ByVal number1 As Double, ByVal number2 As Double) As Double
Dim var As Double
If (number1 < number2) Then
var = number1
Else
var = number2
End If
Min = var
End Function
Function Max(ByVal number1 As Double, ByVal number2 As Double) As Double
Max = number1 + number2 - Min(number1, number2)
End Function
Now I have two questions about this:
I find it surprising to discover that I need to make passing by value explicit. In C++, function variables pass by value by default. Should I conclude that VBA passes variables by references as default?
Why does it help to add Byval to the function arguments? I do not see the relation between types (as the error supposedly is about) and passing by value and/or reference ....
Many thanks in advance.
Try changing this part of interpolateVol:
Dim vol_minus1, vol_zero, volmin, volmax, vol As Double
To this:
Dim vol_minus1 As Double, vol_zero As Double, volmin As Double, volmax As Double, vol As Double
The issue is that in the original version, only vol is declared as Double because it is right next to the word Double. The other four declarations do not have that Double applied to them, so they get declared as the Excel VBA default type, which is Variant. This can be confusing because VBA is not like other languages you might be used to, e.g. C where you can say things like double vol_minus1, vol_zero, volmin, volmax, vol;
That error has nothing to do with ByRef or ByVal; it's simply stating that the type of either a, b, or both is incorrect. For example, if you do this:
Public Sub interpolate()
Dim a As String
Dim b As String
a = 1
b = 2
x = Min(a, b)
End Sub
You'll get that error, but if you do this, you won't:
Public Sub interpolate()
Dim a As Double
Dim b As Double
a = 1
b = 2
x = Min(a, b)
End Sub
The difference between the two is that, in the second one, a and b are have types that the Min function expects.
The reason that it even uses the term ByRef in that error is that it's just trying to be more specific to help you figure out which argument it's referring to. It's like saying "look at the BLACK dog" instead of just "look at the dog."

My MInverse function will not work in VBA

EDIT: I fixed it, the ReDim and all starts at 0 and not 1 so I had a cell that was empty which wasn't supposed to be there!
It now works, thanks for the help!
I'm trying to take a matrix and invert it, but for some reason I get this error:
Unable to get the MInverse property of the WorksheetFunction class.
My (relevant) code is as following:
Dim covar() As Variant
ReDim covar(UBound(assetNames), UBound(assetNames))
Dim corr() As Double
ReDim corr(UBound(assetNames), UBound(assetNames))
Dim covarTmp As Double
For i = 0 To UBound(assetNames) - 1
For j = 0 To UBound(assetNames) - 1
covarTmp = 0
For t = 1 To wantedT
covarTmp = covarTmp + (Log((prices(histAmount + 1 - t, i + 1)) / (prices(histAmount - t, i + 1))) - mu(i) * dt) * (Log((prices(histAmount + 1 - t, j + 1)) / (prices(histAmount - t, j + 1))) - mu(j) * dt)
Next t
covar(i, j) = covarTmp * (1 / ((wantedT - 1) * dt))
corr(i, j) = covar(i, j) / (sigma(i) * sigma(j))
Next j
Next i
Dim covarInv() As Variant
ReDim covarInv(UBound(assetNames), UBound(assetNames))
'ReDim covar(1 To UBound(assetNames), 1 To UBound(assetNames))
covarInv = Application.WorksheetFunction.MInverse(covar)
This last row is where the error occurs.
I've tried many things, having covar and covarInv dim as double, variant etc. Different ReDims on covar and covarInv.
You don't say what version of Excel you are using, but with Excel 2010 there seems to be a Minverse maximum limit of 200 * 200 (for Excel 2003 its probably around 80 * 80): How many asset names do you have?

Performance difference between two implementations of the same algorithm

I'm working on an application that will require the Levenshtein algorithm to calculate the similarity of two strings.
Along time ago I adapted a C# version (which can be easily found floating around in the internet) to VB.NET and it looks like this:
Public Function Levenshtein1(s1 As String, s2 As String) As Double
Dim n As Integer = s1.Length
Dim m As Integer = s2.Length
Dim d(n, m) As Integer
Dim cost As Integer
Dim s1c As Char
For i = 1 To n
d(i, 0) = i
Next
For j = 1 To m
d(0, j) = j
Next
For i = 1 To n
s1c = s1(i - 1)
For j = 1 To m
If s1c = s2(j - 1) Then
cost = 0
Else
cost = 1
End If
d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1), d(i - 1, j - 1) + cost)
Next
Next
Return (1.0 - (d(n, m) / Math.Max(n, m))) * 100
End Function
Then, trying to tweak it and improve its performance, I ended with version:
Public Function Levenshtein2(s1 As String, s2 As String) As Double
Dim n As Integer = s1.Length
Dim m As Integer = s2.Length
Dim d(n, m) As Integer
Dim s1c As Char
Dim cost As Integer
For i = 1 To n
d(i, 0) = i
s1c = s1(i - 1)
For j = 1 To m
d(0, j) = j
If s1c = s2(j - 1) Then
cost = 0
Else
cost = 1
End If
d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1), d(i - 1, j - 1) + cost)
Next
Next
Return (1.0 - (d(n, m) / Math.Max(n, m))) * 100
End Function
Basically, I thought that the array of distances d(,) could be initialized inside of the main for cycles, instead of requiring two initial (and additional) cycles. I really thought this would be a huge improvement... unfortunately, not only does not improve over the original, it actually runs slower!
I have already tried to analyze both versions by looking at the generated IL code but I just can't understand it.
So, I was hoping that someone could shed some light on this issue and explain why the second version (even when it has fewer for cycles) runs slower than the original?
NOTE: The time difference is about 0.15 nano seconds. This don't look like much but when you have to check thousands of millions of strings... the difference becomes quite notable.
It's because of this:
For i = 1 To n
d(i, 0) = i
s1c = s1(i - 1)
For j = 1 To m
d(0, j) = j 'THIS LINE HERE
You were just initializing this array at the beginning, but now you are initializing it n times. There is a cost involved with accessing memory in an array like this, and you are doing it an extra n times now. You could change the line to say: If i = 1 Then d(0, j) = j. However, in my tests, you still basically end up with a slightly slower version than the original. And that again makes sense. You're performing this if statement n*m times. Again there is some cost. Moving it out like it is in the original version is a lot cheaper It ends up being O(n). Since the overall algorithm is O(n*m), any step you can move out into an O(n) step is going to be a win.
You can split the following line:
d(i, j) = Math.Min(Math.Min(d(i - 1, j) + 1, d(i, j - 1) + 1), d(i - 1, j - 1) + cost)
as follows:
tmp = Math.Min(d(i - 1, j), d(i, j - 1)) + 1
d(i, j) = Math.Min(tmp, d(i - 1, j - 1) + cost)
It this way you avoid one summation
Further more you can place the last "min" comparison inside the if part and avoid assigning cost:
tmp = Math.Min(d(i - 1, j), d(i, j - 1)) + 1
If s1c = s2(j - 1) Then
d(i, j) = Math.Min(tmp, d(i - 1, j - 1))
Else
d(i, j) = Math.Min(tmp, d(i - 1, j - 1)+1)
End If
So you save a summation when s1c = s2(j - 1)
Not the direct answer to your question, but for faster performance you should consider either using a jagged array (array of arrays) instead of a multidimensional array. What are the differences between a multidimensional array and an array of arrays in C#? and Why are multi-dimensional arrays in .NET slower than normal arrays?
You will see that the jagged array has a code size of 7 as opposed to 10 with multidimensional arrays.
The code below is uses a jagged array, single dimensional array
Public Function Levenshtein3(s1 As String, s2 As String) As Double
Dim n As Integer = s1.Length
Dim m As Integer = s2.Length
Dim d()() As Integer = New Integer(n)() {}
Dim cost As Integer
Dim s1c As Char
For i = 0 To n
d(i) = New Integer(m) {}
Next
For j = 1 To m
d(0)(j) = j
Next
For i = 1 To n
d(i)(0) = i
s1c = s1(i - 1)
For j = 1 To m
If s1c = s2(j - 1) Then
cost = 0
Else
cost = 1
End If
d(i)(j) = Math.Min(Math.Min(d(i - 1)(j) + 1, d(i)(j - 1) + 1), d(i - 1)(j - 1) + cost)
Next
Next
Return (1.0 - (d(n)(m) / Math.Max(n, m))) * 100
End Function

How can I make this VB.NET code more efficient and faster?

I've been trying to make this code faster and more efficient for a few days now, but it still doesn't seem as efficient as it could be.
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim l As New List(Of ULong)(CType(My.Application.CommandLineArgs.Item(0), ULong))
For i As ULong = 1 To l.Capacity
' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
If l.Capacity And 1 <> 0 Then
If i And 1 = 0 Then
l.Add((i * i) - 1)
Else
l.Add((i * i) + 1)
End If
Else
If i And 1 = 0 Then
l.Add((i * i) + 1)
Else
l.Add((i * i) - 1)
End If
End If
Next i
Console.WriteLine(String.Join(","c, l.ToArray))
watch.Stop()
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub
It currently runs 100 iterations of i in 4.3 milliseconds.
I feel like the nested if statements are the main bottleneck here, but I'm not sure of any way I can change them.
So, can this code be made more efficient?
Thanks... :)
First off, pull the If l.Capacity And 1 <> 0 out of the loop, since it’s always going to be the same.
Then, drop the bit operations in favour of more readable i Mod 2 = 0 tests: you seem to think that this is more efficient, but in reality such trivial optimisations are best left to the compiler and runtime, they have no place in your code and I seriously doubt that they have any measurable impact.
If this is still to inefficient, don’t use an initial capacity and Add. Instead, use Resize and indexed access to the elements. Then you can also get rid of the other If statements by using two loops: one for the even elements and one for the odd elements.
That said, the Join operation is probably by far the slowest step here (apart from the actual printing to the console, maybe) and there’s nothing you can do to optimise that.
Finally, I find the CType horribly unreadable: what you’re doing here isn’t a cast – it’s a parsing operation. Why not write it as one? ULong.Parse(…). Also, why are you using the unwieldy My.Application.CommandLineArgs.Item instead of accepting the command line arguments as a parameter to Main?
Once I only correct your errors, as I think you intended, I get this output when using Ctrl+F5 with Visual Studio 2010 with a Release build:
0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408,9605,9800,10001
33.9106
That's with this code:
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim l As New List(Of ULong)(CInt(My.Application.CommandLineArgs(0)))
For i As ULong = 1 To CULng(l.Capacity)
' ONE LINE IF STMT: If l.Capacity And 1 <> 0 Then If i And 1 = 0 Then l.Add((i * i) - 1) Else l.Add((i * i) + 1) Else If i And 1 = 0 Then l.Add((i * i) + 1) Else l.Add((i * i) - 1)
If (l.Capacity And 1) <> 0 Then
If (i And 1UL) = 0UL Then
l.Add((i * i) - 1UL)
Else
l.Add((i * i) + 1UL)
End If
Else
If (i And 1UL) = 0UL Then
l.Add((i * i) + 1UL)
Else
l.Add((i * i) - 1UL)
End If
End If
Next i
Console.WriteLine(String.Join(","c, l.ToArray))
watch.Stop()
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub
Using LINQ:
0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408,9605,9800,10001
13.0721
That's with:
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim arg = CInt(My.Application.CommandLineArgs(0))
Console.WriteLine(String.Join(","c, Enumerable.Range(1, arg).Select(
Function(i) ((i * i +
If((arg And 1) <> 0,
If((i And 1) = 0, -1, 1),
If((i And 1) = 0, 1, -1))).ToString()))))
watch.Stop()
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub
Now optimised:
0,5,8,17,24,37,48,65,80,101,120,145,168,197,224,257,288,325,360,401,440,485,528,577,624,677,728,785,840,901,960,1025,1088,1157,1224,1297,1368,1445,1520,1601,1680,1765,1848,1937,2024,2117,2208,2305,2400,2501,2600,2705,2808,2917,3024,3137,3248,3365,3480,3601,3720,3845,3968,4097,4224,4357,4488,4625,4760,4901,5040,5185,5328,5477,5624,5777,5928,6085,6240,6401,6560,6725,6888,7057,7224,7397,7568,7745,7920,8101,8280,8465,8648,8837,9024,9217,9408,9605,9800,10001
12.5956
And at this point I thought I clearly hit the Console.WriteLine variance being within the timing, but even with the code below I still get 12 to 15 milliseconds...
Sub Main()
Dim watch As Stopwatch = Stopwatch.StartNew()
Dim arg = CInt(My.Application.CommandLineArgs(0))
Dim fn As Func(Of Integer, String) = If((arg And 1) <> 0,
Function(i As Integer) ((i * i + If((i And 1) = 0, -1, 1)).ToString()),
Function(i As Integer) ((i * i + If((i And 1) = 0, 1, -1)).ToString()))
Dim s = String.Join(","c, Enumerable.Range(1, arg).Select(fn))
watch.Stop()
Console.WriteLine(s)
Console.WriteLine(watch.Elapsed.TotalMilliseconds)
Console.ReadLine()
End Sub