Sum variables in VBA - vba

I have found myself into an issue that looked so simple and stupid at the beginning but keeps me struggling to solve it for over 24 hours now.
I have a string (bunch of numbers delimited by |) that I want to be converted into array and then sum some of the array keys depending on the case.
The first issue I have found was the Integer length limitation, I couldn't believe when VBA was unable to return a number higher than 32767 (Then I found longs...). After "solving" that I found that when trying to SUM some 0 values it actually increase my grand total and I can't find any explanation for this.
Below you can see what I have now:
Public Function calcTime(TimeType As String)
Dim jsSting As String
Dim strSplit As Variant
Dim tempTime as Double
jsSting = "100|0|10080|400|0|4320|70|0|1440|30|0|2280|10|0|7400|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|300|0|15855|90|0|1721"
'Split the string by delimiter
strSplit = Split(jsSting, "|")
Select Case UCase(TimeType)
Case "TOTAL"
tempTime = WorksheetFunction.Sum(strSplit(2), strSplit(5), strSplit(8), strSplit(11), strSplit(14), strSplit(17), strSplit(20), strSplit(23), strSplit(26), strSplit(29), strSplit(32), strSplit(35), strSplit(38))
Case "GROUP1" ' Team 1 + Team2
tempTime = WorksheetFunction.Sum(strSplit(2), strSplit(5), strSplit(8), strSplit(11), strSplit(14))
Case "GROUP2" ' Team 1 + Team2 + Team3
tempTime = WorksheetFunction.Sum(strSplit(2), strSplit(5), strSplit(8), strSplit(11), strSplit(14), strSplit(38))
Case "GROUP3" ' Team 5
tempTime = WorksheetFunction.Sum(strSplit(17), strSplit(20), strSplit(23), strSplit(26))
Case "GROUP4" ' Team 2
tempTime = strSplit(14)
Case "GROUP5" ' Team 6
tempTime = WorksheetFunction.Sum(strSplit(29), strSplit(32), strSplit(35))
End Select
Return tempTime
End Function
In this example I have tried to use Excel's SUM function in order to get the desired result but It wasn't a success.
Sticking to the TOTAL case. It sums the following keys - values:
jsString(2) - 10080
jsString(5) - 4320
jsString(8) - 1440
jsString(11) - 2280
jsString(14) - 7400
jsString(17) - 0
jsString(20) - 0
jsString(23) - 0
jsString(26) - 0
jsString(29) - 0
jsString(32) - 0
jsString(35) - 15855
jsString(38) - 0
This gives a total of 41375, however, when I do the sum in VBA I get 43096 and I can't understand why. If I remove from the SUM the values with 0 it returns the correct 41k value.
Hope this makes sense and the answer is simple (I am seriously thinking that I've missed something when assigning the data type).
Thank you in advance for your help !

Did you maybe mean ... ?
Select Case UCase(TimeType)
Case "TOTAL"
tempTime = WorksheetFunction.Sum(strSplit(2), strSplit(5), strSplit(8), strSplit(11), strSplit(14), strSplit(17), strSplit(20), strSplit(23), strSplit(26), strSplit(29), strSplit(32), strSplit(35), strSplit(38)
Anyway, the problem is that you're summing also strSplit(38) which is 1721 even if you wrote in your sample which is equal to 0, exactly the difference between Excel and VBA ;)
Check with a MsgBox strSplit(38) in your code.

strsplit(38) = 1721, which is the difference of 43096 and 41375

Related

Formatting a double variable using String Format to add up to 3 zero from the right

I got a price decimal which sometimes can be either 0.00002001 or 0.00002.
I want to display always 3 zeros from the right if the number is like 0.00002 so I'm looking it to be 0.00002000. If the number is 0.00002001 do not add anything.
I came accross some examples and other examplesin msdn and tried with
price.ToString.Format("{0:F4}", price)
but It doesn't actually change anything in the number.
And in the case number is like 123456789 I want it to display 123.456.789 which I've half solved using ToString("N2") but it's displaying also a .00 decimals which I don't want.
Some special cases here between the fractional and whole numbers, so they need to be handled differently.
Private Function formatWithTrailingZeros(number As Double) As String
If number Mod 1 > 0 Then ' has a fractional component
Return $"{number:0.00000000}"
Else
Dim formattedString = $"{number:N2}"
Return formattedString.Substring(0, formattedString.Length - 3)
End If
End Function
Dim price = 0.00002001
Console.WriteLine(formatWithTrailingZeros(price))
price = 0.00002
Console.WriteLine(formatWithTrailingZeros(price))
price = 123456789
Console.WriteLine(formatWithTrailingZeros(price))
price = 123456789.012345
Console.WriteLine(formatWithTrailingZeros(price))
0.00002001
0.00002000
123,456,789
123456789.01234500
If your second case with 123.456.789 is not based on your current culture, then you may need to replace , with . such as
Return formattedString.Substring(0, formattedString.Length - 3).Replace(",", ".")
Since you are using . both as a decimal separator and a thousands separator, I'm not sure how my example of 123456789.012345000 should look, but since you didn't ask, I'm not going to guess.

Lookupset with duplicate records SUM not working SSRS 2008

I have the below data in a dataset called Questions and all IDs in another dataset called Dataset1
ID Answer
1 Yes
2 Yes
2 No
2 Yes
3 No
My expected output should be as below
ID Yes No
1 1 0
2 2 1
3 0 1
I am trying to match the ids from Dataset1 and get the Answer from Questions dataset.
If I just use Lookup, it is just checking the first match and ignoring the second record. For eg, in the above data, for ID-2, it is checking the first record with id 2 and counting 'Yes' and ignoring the other 'No' and 'Yes'
=Sum(iif(Lookup(Fields!ID.Value, Fields!ID.Value, Fields!answer.Value, "Questions") = "Yes", 1, 0))
I want to count all Yes and No like shown in the expected output above
I have tried using Lookupset but I couldn't get it working. Is there any easier way without using custom code. If custom code is necessary, could you please advise on how to achieve this.
Thank you in advance.
Why do you need a second dataset?
Have a matrix on the questions dataset, row grouped by ID then use a sum in each column as follows:
=SUM(IIF(Fields!answer.Value="Yes",1,0))
=SUM(IIF(Fields!answer.Value="No",1,0))
You can count the output from a lookupset by using the following custom code:
Function CountAnswers(ByVal AnswerArray As Object(), Answer As string) As Object
If AnswerArray Is Nothing Then Return cint(0)
If Answer Is Nothing Then Return "Nothing"
Dim TotalCount As Decimal = New Decimal()
Dim AnswerPosition As Decimal = New Decimal()
TotalCount = 0
For AnswerPosition = 0 to AnswerArray.GetUpperBound(0)
TotalCount = Switch(IsNothing(AnswerArray(AnswerPosition)),TotalCount, cstr(AnswerArray(AnswerPosition))=Answer,TotalCount + 1, TRUE,TotalCount)
Next
return TotalCount
End Function
Then enter the following under "Yes" and "No" on a matrix on Dataset1:
Code.CountAnswers(Lookupset(Fields!ID.Value, Fields!ID.Value, Fields!answer.Value,"Questions"),"Yes")
Code.CountAnswers(Lookupset(Fields!ID.Value, Fields!ID.Value, Fields!answer.Value,"Questions"),"No")

How to convert string to byte in Visual Basic

I'm trying to simulate an algoritham in cryptography and I need to convert a string of 0s and 1s back into a word. Example:
I have: 01011110010101101000001101100001101
I have split it into an array of strings:
0101111, 0010101, ...
each member has 7 characters. I want to get a letter that 0101111 represents in UTF8? How do I do this?
I try CType("0010101", Byte), but it fails. I can pass max 111 this way.
Help :/
UTF-8 is 8 bit, those are only 7 bits. Do you mean 7 bit ASCII?
In that case here you go:
Function BinToStr(binStr As String) As String
Dim i As Long
For i = 0 To (Len(binStr) / 7) - 1
[A1] = CLng(Mid(binStr, i * 7 + 1, 7))
BinToStr = BinToStr & Chr([BIN2DEC(A1)])
Next
End Function
If that's not what you're looking for, let me know.

Looping through variables in spss

Im looking for a way to loop through variables (eg week01 to week52) and count the number of times the value changes across the them. For example
week01 to week18 may be coded as 1
week19 to week40 may be coded as 4
and week 41 to 52 may be coded as 3
That would be 2 transistions within the data.
How could i go about writing a code that can find me this information? I'm rather new to this and some help to get me in the right direction would be very appreciated.
You can use the DO REPEAT command to loop through variable lists. Below is an example of using this command to create a before date and after date to compare, and increment a count variable whenever these two variables are different.
data list fixed / observation (A1).
begin data
1
2
3
4
5
end data.
*making random data.
vector week(52).
do repeat week = week1 to week52.
compute week = RND(RV.UNIFORM(0.5,4.4)).
end repeat.
execute.
*initialize count to zero.
compute count = 0.
do repeat week_after = week2 to week52 / week_before = week1 to week51.
if week_after <> week_before count = count + 1.
end repeat.
execute.

What function does .NET NPV() use? Doesn't match manual calculations

I am using the NPV() function in VB.NET to get NPV for a set of cash flows.
However, the result of NPV() is not consistent with my results performing the calculation manually (nor the Investopedia NPV calc... which matches my manual results)
My correct manual results and the NPV() results are close, within 5%.. but not the same...
Manually, using the NPV formula:
NPV = C0 + C1/(1+r)^1 + C2/(1+r)^2 + C3/(1+r)^3 + .... + Cn/(1+r)^n
The manual result is stored in RunningTotal
With rate r = 0.04
and period n = 10
Here is my relevant code:
EDIT: Do I have OBOB somewhere?
YearCashOutFlow = CDbl(TxtAnnualCashOut.Text)
YearCashInFlow = CDbl(TxtTotalCostSave.Text)
YearCount = 1
PAmount = -1 * (CDbl(TxtPartsCost.Text) + CDbl(TxtInstallCost.Text))
RunningTotal = PAmount
YearNPValue = PAmount
AnnualRateIncrease = CDbl(TxtUtilRateInc.Text)
While AnnualRateIncrease > 1
AnnualRateIncrease = AnnualRateIncrease / 100
End While
AnnualRateIncrease = 1 + AnnualRateIncrease
' ZERO YEAR ENTRIES
ListBoxNPV.Items.Add(Format(PAmount, "currency"))
ListBoxCostSave.Items.Add("$0.00")
ListBoxIRR.Items.Add("-100")
ListBoxNPVCum.Items.Add(Format(PAmount, "currency"))
CashFlows(0) = PAmount
''''
Do While YearCount <= CInt(TxtLifeOfProject.Text)
ReDim Preserve CashFlows(YearCount)
CashFlows(YearCount) = Math.Round(YearCashInFlow - YearCashOutFlow, 2)
If CashFlows(YearCount) > 0 Then OnePos = True
YearNPValue = CashFlows(YearCount) / (1 + DiscountRate) ^ YearCount
RunningTotal = RunningTotal + YearNPValue
ListBoxNPVCum.Items.Add(Format(Math.Round(RunningTotal, 2), "currency"))
ListBoxCostSave.Items.Add(Format(YearCashInFlow, "currency"))
If OnePos Then
ListBoxIRR.Items.Add((IRR(CashFlows, 0.1)).ToString)
ListBoxNPV.Items.Add(Format(NPV(DiscountRate, CashFlows), "currency"))
Else
ListBoxIRR.Items.Add("-100")
ListBoxNPV.Items.Add(Format(RunningTotal, "currency"))
End If
YearCount = YearCount + 1
YearCashInFlow = AnnualRateIncrease * YearCashInFlow
Loop
EDIT: Using the following values:
Discount Rate = 4%
Life of Project = 10 years
Cash Flow 0 = -78110.00
Cash Flow 1 = 28963.23
Cash Flow 2 = 30701.06
Cash Flow 3 = 32543.12
Cash Flow 4 = 34495.71
Cash Flow 5 = 36565.45
Cash Flow 6 = 38759.38
Cash Flow 7 = 41084.94
Cash Flow 8 = 43550.03
Cash Flow 9 = 46163.04
Cash Flow 10 = 48932.82
Using the calculator at http://www.investopedia.com/calculator/NetPresentValue.aspx
And following the manual "textbook" formula I arrive at the same result:
Net Present Value: $225,761.70
I cannot seem to get NPV() to replicate this result... it spits out $217,078.59
I iterate it manually using the example same value... so they must be using a different function than I am...
The MSDN page example clearly states that the initial expense should be included in the cash flows list.
Normally you wouldn't include the first cashflow in the Visual Basic NPV() function (or at least we don't in the leasing world). You would discount all but the first cash flow, then add that first cash flow amount onto your Net Present Value. Here's an example of what I've done before in a calculation engine (minus error checking to simplify the example):
Dim leaseRentalsDiscounted As Double = 0.0
Dim rebatedCashFlows As IEnumerable(Of LeasePayment) = GetLeaseRentalsPaymentStream()
Dim firstFlow As LeasePayment = rebatedCashFlows(0)
Dim doubleStream As Double() = PaymentToDoubleArray(rebatedCashFlows.Skip(1))
If doubleStream.Length > 0 Then
Dim rate As Decimal = New Decimal(Me.Lease.DiscountRate / 100.0 / 12.0)
leaseRentalsDiscounted = NPV(rate, doubleStream)
End If
leaseRentalsDiscounted += firstFlow.Amount
Return leaseRentalsDiscounted
That could account for your 5% -- I know I've run into an issue like this before. To me, in the manual NPV formula you posted, C0 doesn't need to be in the stream that is discounted, so that's why I don't include it in the NPV() function.
The MSDN page notes that if your cash outflow begins at the beginning of the first period (instead of the end) the first value must be added to the NPV value and not included in the cash flows array.
Your manual calculation shows that your cash outflow (C0) occurs at time zero (present value), which indicates you should follow the MSDN page's suggestion.
Cory Larson is right, in part... but the MSDN documentation seems in error to me.
The problem is that the NPV() function is discounting the very first (n=0) element of the array when it should not; it is beginning at n=1
Even though the MSDN documentation specifics that the first element of the array should be the initial expense this is not the case with their function.
In the NPV() function, the first element of the array (as Cory Larson implied) should be the first real cash flow. Then, after the function returns a result, the result should have the initial expense subtracted.
This is because the NPV() function begins with n=1
using the NPV formula: NPV = C0 + C1/(1+r)^1 + C2/(1+r)^2 + C3/(1+r)^3 + .... + Cn/(1+r)^n
In the manual formula, Cn/(1+r)^n, for n=0 you use your initial expense... then the denominator is 1 (because n=0)
In my opinion, the MSDN example at http://msdn.microsoft.com/en-us/library/microsoft.visualbasic.financial.npv.aspx should be amended to the following:
Exclude the initial -70000 value from the array, shift all element down one in index, and decrease the array size by 1.
Then add the initial expense (-70000) to the variable NetPVal to arrive at the actual result.
Somebody should like MS know about their OBOB :D
(But it's actually a feature, right?)
EDIT: And the section which says " The array must contain at least one negative value (a payment) and one positive value (a receipt)."
In not accurate.
As Cory Larson pointed out: a negative value is not required in the array (and, in fact, should be left out!)