Cannot figure out calculation - vb.net

I need to make a phone bill program that would allow the user to calculate their phone bill. They would enter their minutes, texts and data allowance as well as how much they've used.
Each extra minute is 30p, each extra text is 10p and data used over the limit is £10.00, all added to the final cost.
The problem is that I cannot get the program to calculate the cost of each minute, I guess that after finding out how the minutes are calculated I will be able to do the same for the texts and the data.
Thanks for the help, much appreciated.
This is the problem
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub btn1TotalCost_Click(sender As Object, e As EventArgs) Handles btn1TotalCost.Click
Dim MinutesAllowed As Integer
Dim MinutesUsed As Integer
Dim TextsAllowed As Integer
Dim TextsUsed As Integer
Dim DataAllowed As Integer
Dim DataUsed As Integer
Dim MinutesTotalCost As Double
Dim TextsTotalCost As Double
Dim DataTotalCost As Double
Dim MonthlyCost As Double
Dim TotalCost As Double
MinutesAllowed = Val(txtBoxMinutesAllowed.Text)
MinutesUsed = Val(txtBoxMinutesUsed.Text)
TextsAllowed = Val(txtBoxTextsAllowed.Text)
TextsUsed = Val(txtBoxTextsUsed.Text)
DataAllowed = Val(txtBoxDataAllowed.Text)
DataUsed = Val(txtBoxDataUsed.Text)
MinutesTotalCost = Val(txtBoxTotalCost.Text)
TextsTotalCost = Val(txtBoxTotalCost.Text)
DataTotalCost = Val(txtBoxTotalCost.Text)
TotalCost = Val(txtBoxTotalCost.Text)
'Minutes
MinutesAllowed = Integer.Parse(txtBoxMinutesAllowed.Text)
MinutesUsed = Integer.Parse(txtBoxMinutesUsed.Text)
MonthlyCost = Val(txtBoxMonthlyCost.Text)
If MinutesAllowed >= MinutesUsed Then
MinutesTotalCost = 0
Else
MinutesTotalCost = (MinutesUsed - MinutesAllowed) * 0.3
End If
txtBoxTotalCost.Text = CType(MinutesTotalCost + MonthlyCost, String)
'Texts
TextsAllowed = Integer.Parse(txtBoxTextsAllowed.Text)
TextsUsed = Integer.Parse(txtBoxTextsUsed.Text)
MonthlyCost = Val(txtBoxMonthlyCost.Text)
If TextsAllowed >= TextsUsed Then
TextsTotalCost = 0
Else
TextsTotalCost = (TextsUsed - TextsAllowed) * 0.15
End If
txtBoxTotalCost.Text = CType(TextsTotalCost + MonthlyCost, String)
'Data
DataAllowed = Integer.Parse(txtBoxDataAllowed.Text)
DataUsed = Integer.Parse(txtBoxDataUsed.Text)
MonthlyCost = Val(txtBoxMonthlyCost.Text)
If DataAllowed >= DataUsed Then
DataTotalCost = 0
Else
DataTotalCost = (DataUsed - DataAllowed) + 10.0
End If
txtBoxTotalCost.Text = CType(DataTotalCost + MonthlyCost, String)
End Sub
End Class

MinutesTotalCost = MinutesUsed - MinutesAllowed * 0.3
Multiplication and division operators have precedence over the addition and subtraction operators.
You need to add brackets to the calculation.
MinutesTotalCost = (MinutesUsed - MinutesAllowed) * 0.3
You also overwrite the result of the calculation here:
MinutesTotalCost = txtBoxTotalCost.Text
Edit: Working code for just the minutes
Dim MinutesAllowed As Integer
Dim MinutesUsed As Integer
Dim MinutesTotalCost As Double
Dim MonthlyCost As Double
MinutesAllowed = Integer.Parse(txtBoxMinutesAllowed.Text)
MinutesUsed = Integer.Parse(txtBoxMinutesUsed.Text)
MonthlyCost = Val(txtBoxMonthlyCost.Text)
If MinutesAllowed >= MinutesUsed Then
MinutesTotalCost = 0
Else
MinutesTotalCost = (MinutesUsed - MinutesAllowed) * 0.3
End If
txtBoxTotalCost.Text = CType(MinutesTotalCost + MonthlyCost, String)
Val() returns a double so you need to use Integer.Parse() for int.
Double needs to be converted to string for the textbox.
Edit 2:
Since MonthlyCostdoesn't change you need the line
MonthlyCost = Val(txtBoxMonthlyCost.Text)
only once at the beginning.
You are always overwriting the value of txtBoxTotalCost. Just make a single calculation with all costs i.e.
txtBoxTotalCost.Text = CType(MinutesTotalCost + TextsTotalCost + DataTotalCost + MonthlyCost, String)

Related

If I click the calculate button the program crashes?

Just for context;
I need to calculate the average of 5 numbers located in 5 textboxes.
Nummer means number
Gemiddelde means average
and
Bereken means calculate
What is causing it to crash?
Private Sub butBereken_Click(sender As Object, e As EventArgs) Handles butBereken.Click
'Variabelen'
Dim nummer1 As Decimal = txtNummer1.Text
Dim nummer2 As Decimal = txtNummer2.Text
Dim nummer3 As Decimal = txtNummer3.Text
Dim nummer4 As Decimal = txtNummer4.Text
Dim nummer5 As Decimal = txtNummer5.Text
Dim somNummers As Decimal = nummer1 + nummer2 + nummer3 + nummer4 + nummer5
Dim Gemiddelde As String = (somNummers) / 5
lblGemiddelde.Text = Gemiddelde
If Gemiddelde < 5.5 Then
lblGemiddelde.Text = Gemiddelde + " Dit is onvoldoende"
End If
If nummer1 = "" Or nummer2 = "" Or nummer3 = "" Or
nummer4 = "" Or nummer5 = "" Then
butBereken.Enabled = False
MessageBox.Show("your mom")
Else
butBereken.Enabled = True
End If
End Sub
I don't see what would crash the program but check to that the TextBoxes have values before assigning them to numeric variables. A Decimal value will never = "".
Private Sub butBereken_Click(sender As Object, e As EventArgs) Handles butBereken.Click 'Variabelen'
If Not IsNumeric(txtNummer1.Text) Or _
Not IsNumeric(txtNummer2.Text) Or _
Not IsNumeric(txtNummer3.Text) Or _
Not IsNumeric(txtNummer4.Text) Or _
Not IsNumeric(txtNummer5.Text) Then
MessageBox.Show ("your mom wants you to fill in all the number boxes")
Exit Sub
End If
Dim nummer1 As Decimal = CDec(txtNummer1.Text)
Dim nummer2 As Decimal = CDec(txtNummer2.Text)
Dim nummer3 As Decimal = CDec(txtNummer3.Text)
Dim nummer4 As Decimal = CDec(txtNummer4.Text)
Dim nummer5 As Decimal = CDec(txtNummer5.Text)
Dim somNummers As Decimal = nummer1 + nummer2 + nummer3 + nummer4 + nummer5
Dim Gemiddelde As String = (somNummers) / 5
lblGemiddelde.Text = Gemiddelde
If Gemiddelde < 5.5 Then
lblGemiddelde.Text = Gemiddelde + "Dit is onvoldoende"
End If
If nummer1 = 0 Or nummer2 = 0 Or nummer3 = 0 Or nummer4 = 0 Or nummer5 = 0 Then
butBereken.Enabled = False
MessageBox.Show ("your mom")
Else
butBereken.Enabled = True
End If
End Sub
If this doesn't work I would consider setting breakpoints in the could to determine what line is causing the crash.
If that doesn't work consider adding this line to the form's initialization:
butBereken.Caption = "Warning: Do not Click!"
Assuming the user populated all the textboxes with numeric only data, (and you have checked this) try replacing these lines in your code with this code
Dim nummer1 As Decimal = txtNummer1.Text
Dim nummer2 As Decimal = txtNummer2.Text
Dim nummer3 As Decimal = txtNummer3.Text
Dim nummer4 As Decimal = txtNummer4.Text
Dim nummer5 As Decimal = txtNummer5.Text
Dim somNummers As Decimal = nummer1 + nummer2 + nummer3 + nummer4 + nummer5
Dim Gemiddelde As Decimal = somNummers / 5
lblGemiddelde.Text = Gemiddelde.ToString("##0.0")
I'd do something more like:
Private Sub butBereken_Click(sender As Object, e As EventArgs) Handles butBereken.Click
Dim TBs() As TextBox = {txtNummer1, txtNummer2, txtNummer3, txtNummer4, txtNummer5}
Dim inputs() As String = TBs.Select(Function(x) x.Text).ToArray()
Dim values() As Decimal
Try
values = Array.ConvertAll(inputs, Function(s) Decimal.Parse(s))
Dim Gemiddelde As String = values.Average()
lblGemiddelde.Text = Gemiddelde & If(Gemiddelde < 5.5, " Dit is onvoldoende", "")
Catch ex As Exception
MessageBox.Show("your mom")
End Try
End Sub
I prefer this approach as it doesn't require repetitive lines of code, manually converting each TextBox to a Decimal. Since the TextBoxes are in an Array, we could also add another TextBox to the form and then add that name to the end of the Array. The rest of the code would not need to change at all; it would still just work as is.
From the Array of TextBox, we use a LINQ statement to extract the Text from each TextBox and add it to an Array of String called "inputs". From there, we convert every single String to a Decimal using Array.ConvertAll(), again avoiding repetitive code. If any of the input values is not a valid Decimal then an Exception will be thrown and we'll jump the the Catch block where the not so well written error message is displayed.
If there are no exceptions, then all String inputs were successfully converted to Decimals and stored in the "values" Array. Next we simply use the LINQ function Average() to get the average of all the values.
Lastly we display the computed average in the Label, adding the "Dit is onvoldoende" message if approapriate. The If() function used in this line is simply a shorthand version of a longer If...Else...End If statement.
In your original attempt, it looks like you wanted to disable the button if any of the values are blank (or maybe if they are invalid decimals?):
If nummer1 = "" Or nummer2 = "" Or nummer3 = "" Or nummer4 = "" Or nummer5 = "" Then
butBereken.Enabled = False
MessageBox.Show("your mom")
Else
butBereken.Enabled = True
End If
This makes no sense as if you disable the button, how would it get turned back on so that user could click it again?
A different approach would be to handle the TextChanged() event of all the TextBoxes and simply update your Label with the average in real-time whenever one of the TextBoxes is changed:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UpdateAverage()
End Sub
Private Sub txtAll_TextChanged(sender As Object, e As EventArgs) Handles txtNummer5.TextChanged, txtNummer4.TextChanged, txtNummer3.TextChanged, txtNummer2.TextChanged, txtNummer1.TextChanged
UpdateAverage()
End Sub
Private Sub UpdateAverage()
Dim TBs() As TextBox = {txtNummer1, txtNummer2, txtNummer3, txtNummer4, txtNummer5}
Dim inputs() As String = TBs.Select(Function(x) x.Text).ToArray()
Try
Dim values() As Decimal = Array.ConvertAll(inputs, Function(s) Decimal.Parse(s))
Dim average As Decimal = values.Average
lblGemiddelde.Text = average & If(average < 5.5, " Dit is onvoldoende", "")
Catch ex As Exception
lblGemiddelde.Text = "{ Invalid Input }"
End Try
End Sub
End Class
Sample run:

vb.net calculation doesn't give decimals

hello im trying to do this calculation : [365!/((365^x)((365-x)!))]
the problem is when i do it it doesn't give me the decimals just the integer it give me 0 or 1 because the answer is 0
Public Class Form1
Private Function fact(ByVal n As Integer) As Numerics.BigInteger
Dim Z As New Numerics.BigInteger(1)
For i As Integer = 1 To n
Z = Z * i
Next
Return Z
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim min As Integer
Dim max As Integer
Dim ranum As Integer
Dim ind() As Integer
Dim ran As New Random
Dim F365 As New Numerics.BigInteger(0)
F365 = Numerics.BigInteger.Parse("25104128675558732292929443748812027705165520269876079766872595193901106138220937419666018009000254169376172314360982328660708071123369979853445367910653872383599704355532740937678091491429440864316046925074510134847025546014098005907965541041195496105311886173373435145517193282760847755882291690213539123479186274701519396808504940722607033001246328398800550487427999876690416973437861078185344667966871511049653888130136836199010529180056125844549488648617682915826347564148990984138067809999604687488146734837340699359838791124995957584538873616661533093253551256845056046388738129702951381151861413688922986510005440943943014699244112555755279140760492764253740250410391056421979003289600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
min = Integer.Parse(Tmin.Text)
max = Integer.Parse(Tmax.Text)
ranum = Integer.Parse(TRan.Text)
ReDim ind(ranum)
For x As Integer = 1 To ranum
ind(x) = ran.Next(min, max + 1)
Answer.Items.Add(ind(x))
Next
Dim P(ranum) As Numerics.BigInteger
Dim facts(ranum) As Numerics.BigInteger
For x = 1 To ranum
P(x) = 365 ^ (ind(x))
facts(x) = fact(365 - ind(x))
Next
Dim phenB(ranum) As Numerics.BigInteger
Dim phen(ranum) As Double
For x = 1 To ranum
phenB(x) = (P(x) * facts(x))
phen(x) = F365 / phenB(x)
tx.Text = phen(x) (here is the aswer)
Next
End Sub
End Class
The BigInteger class does not have a function to give a non-integer result for division. However, it does have BigInteger.Log, so, using these logarithmic identities:
ln(a⋅b) = ln(a) + ln(b)
ln(a/b) = ln(a) - ln(b)
ln(a^b) = b⋅ln(a)
we can perform the calculation like this:
Function SomeCalc(n As Integer) As Double
Dim lnF365 = BigInteger.Log(fact(365))
Dim lnPower = n * Math.Log(365)
Dim lnOtherFact = BigInteger.Log(fact(365 - n))
Return Math.Exp(lnF365 - lnPower - lnOtherFact)
End Function
where fact() is a pre-calculated array:
Option Strict On
Option Infer On
' ... other code ...
Dim fact(365) As BigInteger
' ... other code ...
Private Sub CalcFacts()
Dim z = BigInteger.One
For i = 1 To 365
z *= i
fact(i) = z
Next
End Sub
You could even have an array of pre-calculated logs of the factorials, instead of an array of the factorials. It depends on if you're using them elsewhere, and if there is any need for it to go a tiny tiny bit faster:
Function SomeCalc(n As Integer) As Double
Dim lnF365 = lnFact(365)
Dim lnPower = n * Math.Log(365)
Dim lnOtherFact = lnFact(365 - n)
Return Math.Exp(lnF365 - lnPower - lnOtherFact)
End Function
and
Dim lnFact(365) As Double
' ...
Private Sub CalcLnFacts()
Dim z = BigInteger.One
For i As Integer = 1 To largestNum
z *= i
lnFact(i) = BigInteger.Log(z)
Next
End Sub
That number 365 should be a named variable - I had no idea what a sensible name for it would be.

Dynamic Arrays in VB

Struggling student here... I've been asked to find the min, max and mid-point value. However, I cannot figure this out; arrays/data storage is 3 chapters away. So, I'm hoping someone could help me out with this conundrum.
-I need to get the data from an individual element within an array in decimal. Any ideas? I've largely been unsuccessful with the 'array.getvalue' method & with the 'array.min' methods.
Dim numberOfInvoices As Integer
Dim totalOfInvoices As Decimal
Dim invoiceAverage As Decimal
Private Sub BtnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click
Dim subtotal As Decimal = CDec(txtEnterSubtotal.Text)
Dim discountPercent As Decimal = 0.25D
Dim discountAmount As Decimal = Math.Round(subtotal * discountPercent, 2)
Dim invoiceTotal As Decimal = subtotal - discountAmount
Dim minimum, maximum, middle, i As Decimal
Dim array(1) As Decimal
Dim midpoint As Integer
txtSubtotal.Text = FormatCurrency(subtotal)
txtDiscountPercent.Text = FormatPercent(discountPercent, 1)
txtDiscountAmount.Text = FormatCurrency(discountAmount)
txtTotal.Text = FormatCurrency(invoiceTotal)
numberOfInvoices += 1
totalOfInvoices += invoiceTotal
invoiceAverage = totalOfInvoices / numberOfInvoices
For i = 0 To numberOfInvoices - 1
array(i) = i
ReDim Preserve array(0 To numberOfInvoices - 1)
Next i
If numberOfInvoices = 1 Then
minimum = totalOfInvoices
middle = totalOfInvoices
maximum = totalOfInvoices
End If
If numberOfInvoices > 1 Then
midpoint = numberOfInvoices / 2
middle = array.GetValue(midpoint)
For Each i In array
If i < UBound(array) - 1 Then If array(i) > array(i + 1) Then maximum = array(i)
If i < UBound(array) - 1 Then If array(i) < array(i + 1) Then minimum = array(i)
Next i
End If
txtLargestInvoice.Text = maximum.ToString
txtSmallestInvoice.Text = minimum.ToString
txtMidPoint.Text = middle.ToString
txtNumberOfInvoices.Text = numberOfInvoices.ToString
txtTotalOfInvoices.Text = FormatCurrency(totalOfInvoices)
txtInvoiceAverage.Text = FormatCurrency(invoiceAverage)
txtEnterSubtotal.Text = ""
txtEnterSubtotal.Select()
End Sub
Private Sub BtnClearTotals_Click(sender As Object,
e As EventArgs) Handles btnClearTotals.Click
numberOfInvoices = 0
totalOfInvoices = 0
invoiceAverage = 0
txtNumberOfInvoices.Text = ""
txtTotalOfInvoices.Text = ""
txtInvoiceAverage.Text = ""
txtEnterSubtotal.Select()
End Sub
Private Sub BtnExit_Click(sender As Object,
e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Comments and explanations in-line
Private Sub OPCode2()
'You can declare and initialize an array in one line
Dim arr() As Double = {13.5, 18.0, 6.2, 11.8, 13.6}
'Just check intellisense for a list of methods and properties of arrays
Dim myAverage As Double = arr.Average()
Dim myMin As Double = arr.Min
Dim myMax As Double = arr.Max
Dim myMedian As Double
'The original array is lost when .Sort is applied
Array.Sort(arr)
Dim myLength As Integer = arr.Length
'If the lenght of the array is even you could also average
'the middle two values And return that number which
'may not be a value in the original array
myMedian = arr(CInt(myLength / 2)) 'returns the higher of the middle two if length is even
'or the actual middle value in the sorted array
MessageBox.Show($" The Average value is {myAverage}
The Maximum value is {myMax}
The Minimum value is {myMin}
The Median value is {myMedian}")
End Sub

Displaying Input into textbox

I am trying to display a calculation into a TextBox, but having trouble with getting it to show. I want it to show once all input fields are true.
Public Class VehicleAudit
Private Sub Calculate()
Dim validMiles As Boolean = False
Dim validPercent As Boolean = False
Dim validAvg As Boolean = False
Dim inputtedMiles As Double
Dim inputtedPercent As Double
Dim inputtedAvgCost As Double
Dim servTruck As Integer
Try
inputtedMiles = Double.Parse(txtMilesDriven.Text)
inputtedPercent = Double.Parse(txtPercent.Text)
inputtedAvgCost = Double.Parse(txtAvgCost.Text)
Catch ex As FormatException
MessageBox.Show("Please enter all values and try again")
Return
End Try
Dim cal As String = FormatCurrency(Convert.ToString(inputtedAvgCost * inputtedMiles * (1.0 + inputtedPercent))) + " dollars."
ValidateBoxes(inputtedMiles, 0, 10000, "Miles must range from 0-10000.", validMiles)
ValidateBoxes(inputtedPercent, 0.1, 0.5, "Please enter percent from .10 to .50", validPercent)
ValidateBoxes(inputtedAvgCost, 0.25, 0.75, " Please enter Average cost from .25 to .75", validAvg)
If (validAvg And validMiles And validPercent) Then
Dim totalCost As Double
If boxVehicleSelect.SelectedIndex = 9 Then
servTruck = inputtedMiles / 100 'this way we lose precision using the integer, so values below 100s are dropped.
totalCost = servTruck * 15.46
Else
totalCost = inputtedAvgCost * inputtedMiles * (1.0 + inputtedPercent)
End If
End If
End Sub
Private Sub txtTotalCost_TextChanged(ByVal Calculate As String, e As EventArgs) Handles txtTotalCost.TextChanged
End Sub
You appear to already have a block that runs when all three values are "valid". Simply output that value at the bottom of it:
If (validAvg And validMiles And validPercent) Then
Dim totalCost As Double
If boxVehicleSelect.SelectedIndex = 9 Then
servTruck = inputtedMiles / 100 'this way we lose precision using the integer, so values below 100s are dropped.
totalCost = servTruck * 15.46
Else
totalCost = inputtedAvgCost * inputtedMiles * (1.0 + inputtedPercent)
End If
' Output the computed "totalCost" some where.
' Here I'm using a Textbox called "txtTotalCost":
txtTotalCost.Text = totalCost.ToString()
End If
Edit...
Also call your Calculate() method whenever one of your textboxes changes:
Private Sub TextChanged(sender As Object, e As EventArgs) Handles txtMilesDriven.TextChanged, txtAvgCost.TextChanged, txtPercent.TextChanged
Calculate()
End Sub
Note how all three textboxes are listed after the handles keyword.

this error appears when trying to call a sub (An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll)

i have a sub that will try to get random foods in the database, get the sum of these food's calories and check if they wont exceed the required calories.
most of the time the sub worked, but sometimes this error appears.
this is my code. it is kinda long.
Private Sub lunchgenerate()
Dim grams As Integer = DSgrams.Tables("grams").Rows(0).Item("grams")
Dim grams1 As Integer = DSricegrams.Tables("ricegrams").Rows(0).Item("grams")
Dim grams2 As Integer = DSgrams2.Tables("grams").Rows(0).Item("grams")
Dim calorieval As Decimal = foodcalories * grams
Dim calorieval1 As Decimal = ricecalories * grams1
Dim calorieval2 As Decimal = foodcalories2 * grams2
Dim carbval As Decimal = foodcarb * grams
Dim carbval1 As Decimal = ricecarb * grams1
Dim carbval2 As Decimal = foodcarb2 * grams2
Dim proteinval As Decimal = foodprotein * grams
Dim proteinval1 As Decimal = riceprotein * grams1
Dim proteinval2 As Decimal = foodprotein2 * grams
Dim fatval As Decimal = foodfat * grams
Dim fatval1 As Decimal = ricefat * grams1
Dim fatval2 As Decimal = foodfat2 * grams
Dim caloriepercent As Decimal = usercalories * 0.5
Dim mincalories As Decimal = caloriepercent - 300
Dim proteinpercernt As Decimal = userprotein * 0.5
Dim minprotein As Decimal = proteinpercernt - 20
Dim counter As Integer = 0
Dim counter1 As Integer = 0
Dim foodcalorietotal As Decimal = calorieval + calorieval1 + calorieval2
Dim foodproteintotal As Decimal = proteinval + proteinval1 + proteinval2
Dim carbtotal As Decimal = carbval + carbval1 + carbval2
Dim foodfattotal As Decimal = fatval + fatval1 + fatval2
If foodcalorietotal < mincalories Or foodcalorietotal > caloriepercent Then
counter = 0
Else
counter = 1
End If
If foodproteintotal < minprotein Or foodproteintotal > proteinpercernt Then
counter1 = 0
Else
counter1 = 1
End If
If counter = 1 And counter1 = 1 Then
'output to the form
Else
**lunchgenerate()**
End If
End If
End Sub
i think the error is when the lunchgenerate() sub is called again.
but just like what i said, most of the times it worked, but sometimes it freezes and then this error appears and then highlights the first line of my code which is
Dim DAlunchcategory As New SqlDataAdapter(lunchquery, CN)
Dim DSlunchcategory As New DataSet
DAlunchcategory.Fill(DSlunchcategory, "category_id")
Stack Overflow error happens when there is no space on the stack (part of the process memory used for local variables, parameter values, function results and a few other little things).
Often the code that produces this error does it by executing infinite recursion. If the code that you showed is complete lunchgenerate function, in the case when either counter or counter1 is not 1, lunchgenerate will be called again with exactly the same outcome, and again, and again, until it completely depletes space on the stack and exception is thrown. You need to have some escape logic to avoid it.