Converting File sizes from bytes to Kb or Mb - vba

I have got a large amount of rows with different values in it, from 1000s to 1,000,000s.
This is data that has come across to me in bytes and i need to convert it to Kb or Mb respectively.
I could divide all the values by 1M and get all the data en Mb but i want to have the data in kb and Mb.
I tried using the MOD function but that wont do the trick as all the numbers are going to be divisible by 1K and 1M so i am a bit stuck!
here is a sample of the data that i get:
16000000
220000
2048000
2048000
230000
16000000
230000
16000000
220000
230000
so what i need is that if the cell contains 6 zeros then divide by 1M or if the cell contains 3 zeros devide by 1000.
I will add concatenation to each individual result in order to get the data differentiated.

This is the function you are looking for :
Public Function SizeInStr(ByVal Size_Bytes As Double) As String
Dim TS()
ReDim TS(4)
TS(0) = "b"
TS(1) = "kb"
TS(2) = "Mb"
TS(3) = "Gb"
TS(4) = "Tb"
Dim Size_Counter As Integer
Size_Counter = 0
If Size_Bytes <= 1 Then
Size_Counter = 1
Else
While Size_Bytes > 1
Size_Bytes = Size_Bytes / 1000
''Or
'Size_Bytes = Size_Bytes / 1024
Size_Counter = Size_Counter + 1
Wend
End If
SizeInStr = Format(Size_Bytes * 1000, "##0.0#") & " " & TS(Size_Counter - 1)
''Or
'SizeInStr = Format(Size_Bytes * 1024, "##0.0#") & " " & TS(Size_Counter - 1)
End Function
Use it simply like this :
Private Sub Test_SizeInStr()
MsgBox SizeInStr(1000000)
End Sub

If you are looking for some VBA code you might use this Function:
Public Function yourFunction(ByVal number)
If number > 1000000 Then
'number as MB
yourFunction = number / 1000000
'or use the following to add MB
'yourFunction = (number / 1000000) & " Mb"
Else
'number in kB
yourFunction = number / 1000
'or use the following to add kB
'yourFunction = (number / 1000) & " Kb"
End if
End Function
If you are looking for an Excel-Formula you might use this Function (original value in A1), put this formula in another column (for example column B)
=IF(A1>1000000,A1/1000000,A1/1000)
or with concatenation:
=IF(A1>1000000,CONCATENATE(A1/1000000," Mb"),CONCATENATE(A1/1000," Kb"))

I would avoid changing the numbers themselves, and use a number format instead. If you use a function or macro to modify the number, then you will no longer be able to eg. sum them up.
This number format does exactly what you need, but leaves the actual numbers untouched, in bytes, so you can still use them in formulas:
[>1000000]0,,"Mb";[>1000]0,"kb";0"b"
Note that this can be environment language dependent. For me with Hungarian regional settings, spaces must be used instead of commas:
[>1000000]0 "Mb";[>1000]0 "kb";0"b"
What space/comma does is each of them "hides" three digits from the end.

For any number n, apply this
If n Mod 1000 = 0 Then
n = n / 1000
End If
twice. On the first run it will convert millions to thousands, and thousands to units. On the second run it will converts any thousands to units.

Related

Why are the variables are not taking the desired values

I have to check how many hundreds are there in a number and translate that number to letters. For example the number 700. I have done the following code:
DATA(lv_dmbtr) = ZDS_FG-DMBTR. //Declared local variable of type DMBTR, thus DMBTR=700.
lv_dmbtr = ZDS_FG-DMBTR MOD 100. //Finding how many times 700 is in 100 via MOD and putting the value in lv_dmbtr.
IF lv_dmbtr LE 9. //The value is less or equal than 9(if larger means that the DMBTR is larger than hundreds,
e.g. 8000)
lv_hundred = lv_dmbtr / 100. // Divide the 700 with 100, taking the number 7.
lv_hundred_check = lv_hundred MOD 1. // Then taking the value of 7 into the new variable, done in case the
lv_hundred is a decimal value, e.g. 7.32.
IF lv_hundred_check > 0.
CALL FUNCTION 'SPELL_AMOUNT'
EXPORTING
amount = lv_hundred_check
* CURRENCY = ' '
* FILLER = ' '
LANGUAGE = SY-LANGU
IMPORTING
in_words = lv_hundred_string // the value is put in the new string
EXCEPTIONS
not_found = 1
too_large = 2
OTHERS = 3.
ENDIF.
Now when I debugg the code, all the variables have the value 0. Thus, lv_dmbtr, lv_hundred, lv_hundred_check all have the value 0.
May anyone of you know where the problem may be?
Thank you in advance!
Sorry for writing a lot in the code, just wanted to clarify as much as I could what I had done.
yes so I want to display the value of a specific number 700-> seven, 1400-> four.
So the basic formula to get the hundred in a number is the following: Find out how many times 100 fits completely into your number with integer division.
99 / 100 = 0
700 / 100 = 7
701 / 100 = 7
1400 / 100 = 14
1401 / 100 = 14
Now you can simply take this number MOD 10 to get the the individual hundreds.
0 MOD 10 = 0
7 MOD 10 = 7
14 MOD 10 = 4
Keep in mind that ABAP, in contrast to many other programming languages, rounds automatically. So in code this would be:
CONSTANTS lc_hundred TYPE f VALUE '100.0'.
DATA(lv_number) = 1403.
DATA(lv_hundred_count) = CONV i( floor( ( abs( lv_number ) / lc_hundred ) ) MOD 10 ).

Calculating a total cost based on how many stripes someone wants on their clothes

I'm trying to make it so that if someone wants 3 or less stripes on their shorts it costs 50 cent per stripe on top of the 5.50 base cost for a pair of shorts and then every stripe after the third costs 2 euro each. It works if they chose 3 or less but once I enter any stripe amount above 3 it just displays the base 5.50 cost for the shorts. Not sure what to do any help is appreciated.
I have declared all my variables correctly, I assume the problem is with the code below
'calculate cost of Shorts
If mskShortStripes.Text <= 3 Then
dblTotalShorts += CDbl(mskShorts.Text * 5.5) + (mskShortStripes.Text * 0.5)
ElseIf mskShortStripes.Text > 3 Then
dblTotalShorts += CDbl(mskShorts.Text * 5.5) + (mskShortStripes.Text <= 3 * 0.5) + (mskShortStripes.Text > 3 * 2)
End If
You're asking for trouble working with the .Text property directly as if it were a number. It is not. Fun things happen when the value in your control is not actually a number.
Use Integer.TryParse to convert that string to a number:
Dim numberOfStripes As Integer
If Integer.TryParse(mskShortStripes.Text, numberOfStripes) Then
If numberOfStripes >= 0 Then
' ... now do some math in here with the "numberOfStripes" variable ...
Else
MessageBox.Show("Number of Stripes can't be negative!")
End If
Else
MessageBox.Show("Invalid Number of Stripes!")
End If

Order a Multiline Textboxes by Character Number

I want to order a Multiline by character, this code should do this, unfortunately it does not.
Dim strs = New String() {TxtListScanTxt.Text}
Dim sorted = strs.OrderBy(Function(x) x.Length).ThenBy(Function(x) x).ToArray()
TxtListScanTxt.Lines = sorted
Output
1,2,3,4,5
1,2,3,9
1,2,4,8
1,2,5,7
3,12
4,5,6
7,8
15
Output: Expected:
15
7,8
3,12
4,5,6
1,2,5,7
1,2,4,8
1,2,3,9
1,2,3,4,5
This would be easy if you didn't want to sort lists of numbers individually. Also, since you are sorting the individual lists (of the same count) by numeric items, you can't use a string sort. What I mean is
9,5
10,6
How do you sort that? You would compare 9 with 1, in 9 and 10, respectively, if doing an alphabetical sort, and 9 would be greater than 10. I think you should parse each individual element as an integer beforehand.
So my code here is complex, and involves grouping the lines by item count first, then ordering the lines within their groups. I suppose this could be put into one line but this is more readable (though, still not very...)
Dim lines = TxtListScanTxt.Lines.Select(Function(l) l.Split(","c).Select(Function(s) Integer.Parse(s)))
Dim groups = lines.GroupBy(Function(l) l.Count()).OrderBy(Function(g) g.Key)
Dim sortedGroups = groups.Select(Function(g) g.OrderByDescending(Function(gi) gi.Reverse().Select(Function(i, v) v * 10 ^ i).Sum())).SelectMany(Function(g) g)
Dim result = sortedGroups.Select(Function(g) String.Join(",", g))
TxtListScanTxt.Lines = result.ToArray()
Recursion could be used to do sort each sub group by their numbers, but we could also take a sum, and I'm trying to do this with LINQ. The magic in Function(i, v) v * 10 ^ i).Sum() is that we will sort by creating a number out of your list by multiplying each successive item by 10 to a higher order of magnitude then summing.
1,2,3,9 = 1000 * 1 + 100 * 2 + 10 * 3 + 9 = 1239
1,2,4,8 = 1000 * 1 + 100 * 2 + 10 * 4 + 8 = 1248
and 1248 should come before 1239 (so order by descending for these sub groups)
You could say concatenate the characters into an integer but once you get into double digits, that breaks down. This method handles that case.
You can try to split the text in multiple lines before try to order the lines:
The TextBox has a Lines property that already gives an Array containing each line of the Text.
Dim Lines() As String = TxtListScanTxt.Lines ' System.IO.File.ReadAllLines("C:\temp\myfile.txt") ' TxtListScanTxt.Text.Split({Environment.NewLine}, StringSplitOptions.None) ' You can use this if you want to split the text from a string
Dim SortedLines = Lines.OrderBy(Function(Line) Line.Length).ToArray()
TxtListScanTxt.Lines = SortedLines
Initial screen:
Result after sort:

Advice and feedback on dividing cash amounts into actual counts of various bills and coinage

So I need an idea of how to divide out an amount of money into actual counts of various bills and coinage. I know this is confusing, so let me give an example:
$16.32 - Sixteen dollars and thirty-two cents
One $10 bill
One $5 bill
One $1 bill
One Quarter ($0.25)
One Nickel ($0.05)
Two Pennies ($0.01)
So as you can see, we're just getting the number of bills and coinage that goes into a value, which will change according to user input.
Here's my current setup (Visual Basic):
If 100 Mod amount < 0 Then
If 50 Mod amount < 0 Then
' Continue this pattern until you get all the way down to the end ($0.01)
Else
While amount > 50
fiftiesAmount += 1
amount -= 50
End If
Else
While amount > 100
hundredsAmount += 1
amount -= 100
End If
Basically, each If statement determines whether or not your total amount needs an extra billing amount of that type, and then either adds to the amount of bills/coinage already created or moves on to the next amount.
Is this an efficient way of doing things, or am I missing out on an easier/faster algorithm/pattern that would make my life, and whoever is reading my code's life easier?
If you need extra details, I'll be happy to edit the question as needed.
Convert your amount to cents (it's easier). Divide by the currency value being tested, and then deduct that amount from the balance (pseudo-code)
Value = 16.32 * 100 ' Convert to cents
If Value > 10000 ' Hundreds
Hundreds = Value / 10000 ' How many?
Value = Value - (Hundreds * 10000) ' Reduce amount accordingly
End If
If Value > 5000 ' Fifties
Fifties = Value / 5000
Value = Value - (Fifties * 5000)
End If
If Value > 2000 ' Twenties
Twenties = Value / 2000
Value = Value - (Twenties * 2000)
End If
Repeat until you have less than 100, at which point you start with coins (50, 25, 10, 5)
Once you've got > 10, you've reached pennies; save them, reduce Value by that amount, and
Value is zero, so you're finished.

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!)