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