How do I debug this crash - vb.net

My code:
Imports System
Module Program
Sub Main(args As String())
Dim Price As Integer
Dim Qty As Integer
Dim Total As Integer
Console.Write("Enter the product unit price. ")
Price = Console.ReadLine()
Console.Write("Enter the product quantity. ")
Qty = Console.ReadLine()
Total = Price * Qty
If (Qty > 99) And (Qty < 150) Then
Console.WriteLine("You did not qualify for a discount. Your total is: " + Total.ToString)
End If
If (100 < Qty > 149) Then
Console.WriteLine("You qualified for a 10% discount! Your total is: " + (Total * 1.1).ToString)
End If
If (Qty > 149) And (Qty < 200) Then
Console.WriteLine("You qualified for a 15% discount! Your total is: " + (Total * 1.15).ToString)
End If
If (Qty > 199) Then
Console.WriteLine("You qualified for a 20% discount! Your total is: " + (Total * 1.2).ToString)
End If
End Sub
End Module
I can run it to input the values but crash when the math component is executed. Any ideas on how to fix this silly little program?

This isn't a thing:
If (100 < Qty > 149) Then
If needs to look more like this:
If 100 <= Qty AndAlso Qty < 150 Then
The first condition should also just be If Qty < 100 Then
Worse, Qty is a STRING. For cultural/internationalization reasons, converting between strings and numbers is one of the slowest and most error-prone operations you can do within a single computer. It's something to minimize. Therefore you should parse the Qty and Price variables into actual Integer and Decimal variables once right after you read them from the user. Failure to do so makes the code seem amateurish.
Finally, rather than a bunch of If/Else conditions I'd put the data in an ordered map and take the first match:
Imports System
Imports System.Linq
Imports System.ValueTuple ' No longer needed on recent versions of VS
Module Program
Sub Main(args As String())
Console.Write("Enter the product unit price. ")
Dim Price As Decimal = Decimal.Parse(Console.ReadLine())
Console.Write("Enter the product quantity. ")
Dim Qty As Integer = Integer.Parse(Console.ReadLine())
Dim Total As Decimal = Price * Qty
Dim discount As Decimal = GetDiscount(Qty)
Dim discountMessage As String = "You did not qualify for a discount."
If discount > 0.0D Then
discountMessage = $"You qualified for a {discount:P0} discount!"
Total *= (1.0D - discount)
End If
Console.WriteLine($"{discountMessage} Your total is: {Total:C2}")
End Sub
Public Function GetDiscount(Qty As Integer) As Decimal
Dim discountMap() As (Integer, Decimal) = {
(200, 0.20D),
(150, 0.15D),
(100, 0.10D),
(Integer.MinValue, 0.00D)
}
Return discountMap.First(Function(m) m.Item1 <= Qty).Item2
End Function
End Module
If some of this code looks strange to you, it relies on Tuples, a lambda expression, and string interpolation; all three techniques are good tricks to add to your programming repertoire.

Related

Showing the name of the most expensive product in vb

i'm pretty new to programming and i got stuck trying to write a program where you type in the name and prices of products and you get back the total, the name+ prices and the most expensive product. Everything works fine except showing the name of the most expensive product.
Here's what i've done
""
Public Class Mrj
Shared Sub main()
Dim i, n As Integer
Console.WriteLine("Enter the number of products")
n = Console.ReadLine()
Dim Products_name(n) As String
Dim Products_price(n), HT, TTC, TVA, max As Decimal
For i = 1 To n
Console.WriteLine("Enter the name of the product " & i)
Products_name(i - 1) = Console.ReadLine()
Console.WriteLine("Enter the price of the product " & i)
Products_price(i - 1) = Console.ReadLine()
HT = HT + Products_price(i - 1)
Next
For i = 1 To n
Console.WriteLine(Products_name(i - 1) & " " & Products_price(i - 1))
Next
TVA = 0.2 * HT
TTC = HT + TVA
Console.WriteLine("Total to pay " & TTC)
max = Products_price(0)
For i = 1 To n - 1
If max > Products_price(i) Then
Else
max = Products_price(i)
End If
Next
Console.WriteLine("The product the most expensive is" & max & Products_name(i))
End Sub
End Class
""
I think the problem is that you are using i to get the name of the most expensive product, but that index i is always i = n since you don't save the index of the maximum value.
You should add a new variable where you store the index everytime you get a new maximum value, and use it in the last line.
Your for loop should be something like this:
Dim max_index As Integer
For i = 1 To n - 1
If max > Products_price(i) Then
Else
max = Products_price(i)
max_index = i
End If
Next
Console.WriteLine("The product the most expensive is" & max & Products_name(max_index))
Try this out and check if it works.
Turn on Option Strict now and forever. Project Properties -> Compile tab. Also for future projects Tools -> Options -> Projects and Solutions -> VB Defaults
You cannot assume that a user will actually enter a number. Test with TryParse.
Arrays in vb.net are declared Products_name(upper bound). In this case that would be Products_name(n-1)
Instead of doing i - 1 for the indexes in the For loop, start our with For i = 0 to n-1
I decided to not use the parallel arrays. Instead I made a tiny class and declared a List(Of Product). I filled the list with the user input setting the Properties of the Product.
I used Linq instead of loops for sums and max. Not necessarily faster but can be accomplished in a single line of code.
I use interpolated strings to display results. When your string is preceded by a $, you can insert variables directly in the text surrounded by braces. The colon following Price indicates a formatting character. Here, I used a C for currency.
Public Class Product
Public Property Name As String
Public Property Price As Decimal
End Class
Sub main()
Dim ProductList As New List(Of Product)
Dim n As Integer
Console.WriteLine("Enter the number of products")
Integer.TryParse(Console.ReadLine, n)
For i = 1 To n
Dim p As New Product
Dim pr As Decimal
Console.WriteLine("Enter the name of the product " & i)
p.Name = Console.ReadLine()
Console.WriteLine("Enter the price of the product " & i)
Decimal.TryParse(Console.ReadLine, pr)
p.Price = pr
ProductList.Add(p)
Next
For Each p In ProductList
Console.WriteLine($"{p.Name} {p.Price:C}")
Next
Dim SubTotal As Decimal = ProductList.Sum(Function(item) item.Price)
Dim Tax As Decimal = 0.2D * SubTotal
Dim Total = SubTotal + Tax
Console.WriteLine($"Total to pay {Total:C}")
Dim Prod = ProductList.OrderByDescending(Function(p) p.Price).FirstOrDefault()
Console.WriteLine($"The product the most expensive is {Prod.Name} at {Prod.Price:C}")
Console.ReadKey()
End Sub

VB.NET book exercise that outputs monthly balances from a fixed amount deposit

I'm going through practice exercises from a book and am stuck on a particular example. Full disclosure, this is not an assignment or test but merely me practicing through chapters of a book called Introduction to Visual Basic so off the bat, I apologize to those who feel it is a stupid question to ask. The question goes like this,
Suppose a fixed amount of
money is deposited at the beginning of each month into an
investment paying 6% interest compounded monthly. After each
deposit is made,
new balance] = 1.005 * [previous balance one month ago] +
[fixed amount].
Write a program that requests the fixed amount of
the deposits as input and displays the balance after each of the
first four deposits.
Here is an attached image of the output
I am not sure how to approach this question really.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim amount As Decimal
amount = CDec(txtAmount.Text)
lstResults.Items.Add(MonthlyInvestment(amount)).ToString("C")
End Sub
Function MonthlyInvestment(amount As Decimal) As Decimal
Dim balance As Decimal = amount
Dim newBalance As Decimal
Dim interestRate As Decimal = 0.06
newBalance = 1.005 * balance + amount
Return newBalance
End Function
End Class
Here's an example you can refer to.
Private count As Decimal
Private monthCount As Integer = 1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If count = 0 Then
count = CDec(txtAmount.Text)
lstResults.Items.Add($"Month {monthCount}: " + count.ToString("C"))
monthCount += 1
Else
lstResults.Items.Add($"Month {monthCount}: " + MonthlyInvestment(count).ToString("C"))
monthCount += 1
End If
End Sub
Function MonthlyInvestment(balance As Decimal) As Decimal
count = 1.005 * balance + CDec(txtAmount.Text)
Return count
End Function
Result of my test.
You are using a TextBox control which is not the best option for accepting numeric values. My first suggestion would be to swap that out in favor of a NumericUpDown control. You can find the documentation here: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.numericupdown
After that what you should do is setup a For/Next loop to loop from month 2 (since month 1 is the initial deposit) to month n. Outside of your loop you should declare a variable to hold the current total and inside of your loop, you should do your calculation based on the current total.
Take a look at this example using a NumericUpDown:
Dim total = NumericUpDown1.Value
lstResults.Items.Add($"Month 1: {total:c}")
For month = 2 To 4
total = 1.005 * total + NumericUpDown1.Value
lstResults.Items.Add($"Month {month}: {total:c}")
Next
Fiddle: https://dotnetfiddle.net/2CK432
Also, quick side-note, 1.005 is not 6 percent. Not sure if that's a typo in your code.
Hi all thank you for your help. I went back and looked at my previous work and indeed as one said, breaking down these problems I was able to see a pattern. This is what I did
Public Class Form1
Dim balance As Double = 0 'global variable, We need to access it everywhere in the project
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim originalDeposit As Double = CDbl(txtAmount.Text)
'clears the listbox and asaaign 0 to balance when the new blance is being entered
lstResults.Items.Clear()
balance = 0
' Option 1 displays results
'lstOutput.Items.Add("Month 1: " & newBalance(originalDeposit).ToString("C"))
'lstOutput.Items.Add("Month 2: " & newBalance(originalDeposit).ToString("C"))
'lstOutput.Items.Add("Month 3: " & newBalance(originalDeposit).ToString("C"))
'lstOutput.Items.Add("Month 4: " & newBalance(originalDeposit).ToString("C"))
' Option 2 - displays results
For i As Integer = 1 To 4
lstResults.Items.Add("Month " & i & ": " & newBalance(originalDeposit).ToString("C"))
Next
End Sub
'calculates new balance. This function is called 4 times. It increase the balance
'and returns its new value
Function newBalance(originalDeposit As Double) As Double
balance = 1.005 * (balance) + originalDeposit
Return balance
End Function
End Class

vb.net calculations for multiple condition

I need to calculate and get a total amount for a unit with multiple calculation conditions. If I enter an amount in a textbox and press enter the second textbox should display a total amount for the below conditions.
(if unit = 450)
0-100 = 3.00 // 101-200 = 5.00 // 201-300 = 7.00 // over 300 = 10.00
if i press enter after entering the unit as 450 second textbox should display total as 2000.00. I am new to vb.net can anyone help me to do this
(for first 100 => 300.00 / second 100 => 500.00 / third 100 => 700.00 / fourth 100 => 500.00 altogether totally 2000.00)
Here is a simple console application to illustrate the process. The idea is to go from the highest range to the lowest and always check if we have to take items from the current range.
Class AmountLimit
Public Property AmountLowerBound As Integer
Public Property Value As Double
Public Sub New(amountLowerBound As Integer, value As Double)
Me.AmountLowerBound = amountLowerBound
Me.Value = value
End Sub
End Class
Sub Main()
'Specify the values for each range. The first number is the lower bound for the range
Dim amountLimits As New List(Of AmountLimit)
amountLimits.Add(New AmountLimit(0, 3))
amountLimits.Add(New AmountLimit(100, 5))
amountLimits.Add(New AmountLimit(200, 7))
amountLimits.Add(New AmountLimit(300, 10))
Console.Write("Enter the total amount: ")
Dim totalAmount = Integer.Parse(Console.ReadLine())
Dim finalValue As Double = 0
For i As Integer = amountLimits.Count - 1 To 0 Step -1
'Check if our total amount is greater than the current lower bound
Dim currentRange = amountLimits(i)
If (totalAmount > currentRange.AmountLowerBound) Then
finalValue += (totalAmount - currentRange.AmountLowerBound) * currentRange.Value
totalAmount = currentRange.AmountLowerBound
End If
Next
Console.WriteLine(finalValue)
End Sub

Conversion from string "" to type 'Double' is not valid In .NET Fiddle's VB

I am writing a project in school (on .NET Fiddle's VB Console) and am encountering an error.
In this task, we have to:
Enter 10 test results with the name of the student.
Validate all data as it is entered and refuse poor data
We need to print out the Mean (arithmetic average), Highest Mark and who got it (assume 1 max per test), Lowest Mark and who got it (assume 1 min per test)
My Personal Code Follows:
Imports System
Public Module Module1
Public Sub Main()
Dim sStudentName As String
Dim iStudentMark As Double
Dim iHighMark As Integer
Dim iLowMark As Integer
Dim iAve As Integer
For List = 1 to 10
Console.WriteLine("Input A Students Name")
sStudentName = Console.ReadLine()
Console.WriteLine("This student's Mark is")
iStudentMark = Console.ReadLine()
Do Until 25<= iStudent Or iStudentMark <= 100
Console.WriteLine("Error. Invalid Percentage. Re-input.")
iStudentMark = Console.ReadLine()
Loop
iAve = iAve + iStudentMark
If iStudentMark > iHighMark Then
iHighMark = iStudentMark
Console.Write("The Highest Percentage has changed. The top score is now " + iStudentMark + " Percent from " + sStudentName)
End If
If iStudentMark < iLowMark Then
iHighMark = iStudentMark
Console.Write("The Highest Percentage has changed. The top score is now " + iStudentMark + " Percent from " + sStudentName)
End If
Next
iAve = iAve/10
Console.WriteLine(iAve)
End Sub
End Module
The Error Message(s) I get is/are:
Run-time exception (line -1): Conversion from string "The Highest
Percentage has chang" to type 'Double' is not valid.
Stack Trace:
[System.FormatException: Input string was not in a correct format.]
[System.InvalidCastException: Conversion from string "The Highest
Percentage has chang" to type 'Double' is not valid.]
I have never been the best at coding, so many thanks to those who try and solve it.
Console.ReadLine() method will return a string you cannot assign it directly to double. you need to cast them as double.
Console.WriteLine("This student's Mark is")
If Not Integer.TryParse(Console.ReadLine(), iStudentMark) Then
Console.WriteLine("Invalid input..! failed to convert")
End If
'you can proceed with iStudentMark

Can someone tell me what I am doing wring

The output I am getting is is not what I am suppose to be getting when you type in 50 dollars i should get 58 bars and 2 coupons but when i run it i am getting 57 with 7 coupons left. Thank you.
Module Module1
Sub Main()
' declare variable
Dim amountDollar As Integer
Dim totalCoupons As Integer
Dim leftOverCoupons As Integer
Dim numberofChocolate As Integer
Dim freeChocolate As Integer
Dim totalchocolate As Integer
Console.WriteLine("Please enter your amount here")
amountDollar = CInt(Console.ReadLine())
numberofChocolate = amountDollar
freeChocolate = CInt(numberofChocolate / 7)
totalchocolate = numberofChocolate + freeChocolate
Console.WriteLine("Total number of chocolate: " & totalchocolate)
leftOverCoupons = freeChocolate Mod numberofChocolate
Console.WriteLine("Leftover Coupons: " & leftOverCoupons)
End Sub
End Module
ok this is the new one but i can do it will the mod and the divison why is that
Sub Main()
' This program will calculate the number of chocolate bars you can buy or redeem by coupons for an input number
' of dollars. Each bar costs one dollar and there is one coupon in each bar. It takes 7 coupons to receive one
' additional chocolate bar.
Dim dollars, numberOfBars, couponCount As Integer
' Prompt user to enter amount of money they have to spend
Console.WriteLine("Would you like to buy candy bars")
Console.WriteLine("Yes")
Console.WriteLine("No")
Console.WriteLine("Please enter your amount here")
dollars = Convert.ToInt32(Console.ReadLine())
' Set value of numberOfBars and couponCount
numberOfBars = dollars
couponCount = numberOfBars
' Begin loop. Loop will determine total bars and remaining coupons
Do While couponCount >= 7
couponCount = couponCount - 7
numberOfBars = numberOfBars + 1
couponCount = couponCount + 1
Loop
' Output values for ending number of chocolate bars and remaining coupons
Console.WriteLine("The total number of chocolate bars you receive is: " & numberOfBars)
Console.WriteLine("The number of coupons you have left is: " & couponCount)
End Sub
Okey I have figure it out just how do i stop the program if someone enters No?
For the 58 compared to 57, I think 57 is actually what you are looking for - 50 bars plus (50/7) = 7.14 round down to 7 = 57
In the case where someone only buys 1 bar, you wouldn't want them to get a free bar, would you?
If you do want 58, then you need to use Double's for your maths and you need to use Math.Ceiling to get the next number up.
For the number of coupons left, I think you need to change:
leftOverCoupons = freeChocolate Mod numberofChocolate
to
leftOverCoupons = freeChocolate Mod 7
to improve the readability of your code a little, you should probably also define a local constant for this "magic number" of 7