Celsius converter on VB running into Strict Option errors - vb.net

I'm hoping someone can clarify what I'm doing wrong here. I am trying to make a form with 2 labels - Celsius and Fahrenheit with 2 respective textbooks for the Value and 1 button - Convert to display the conversion of Celsius into Fahrenheit. The following Code I use keeps running me into Strict Options errors, 2 for Option Strict On disallows implicit conversions from 'Object' to 'String' and 2 for Option Strict On disallows implicit conversion from 'String' to 'Double'. I can't seem to find a way to please the strict options.
Private Sub btnConvert_Click(sender As Object, e As EventArgs) Handles btnConvert.Click
Dim celsius As String
Dim answer As String
Dim fahrenheit As String
celsius = txtCelsius.Text
fahrenheit = txtFahrenheit.Text
If String.IsNullOrEmpty(txtFahrenheit.Text) Then
answer = celsius * 9 / 5 + 32
txtFahrenheit.Text = Int(answer)
End If
If String.IsNullOrEmpty(txtCelsius.Text) Then
answer = (fahrenheit - 32) * 5 / 9
txtCelsius.Text = Int(answer)

With Option Strict On
You need to do conversion yourself
I have edited your code, Try this
Dim celsius As String
Dim answer As String
Dim fahrenheit As String
celsius = txtCelsius.Text
fahrenheit = txtFahrenheit.Text
If String.IsNullOrEmpty(txtFahrenheit.Text) Then
answer = CStr(CDbl(celsius) * 9 / 5 + 32)
txtFahrenheit.Text = answer
End If
If String.IsNullOrEmpty(txtCelsius.Text) Then
answer = CStr((CDbl(fahrenheit) - 32) * 5 / 9)
txtCelsius.Text = answer
End If

You have many implicit conversions that can be fixed/made explicit:
You have implicit conversion in the celsius * 9 / 5 + 32and (fahrenheit - 32) * 5 / 9.
celcius and farhenheit are strings, but you're using it as a numbers.
You also have when you put the result into answer:
answer = celsius * 9 / 5 + 32
answer is a string but you're assigning the result of a calculation. It properly should be a double or similar datatype and not a string.
And then when you put Int(answer) into a textfield.
first answer is still a string, but Int() takes a number (double) if I remember right. Then you take that result and put automatically into a string:
txtCelsius.Text = Int(answer)

Related

TextBox to TextBox Calculations

Maybe a simple question but I still need some help with a formula clarification:
Could somebody help me with this:
TempCalc = CInt(TextBox3.Value) * (16*POWER(SQRT(CInt(TextBox1.Value)*(1-CInt(Textbox1.Value)))/(CInt(TextBox1.Value)*CInt(TextBox2.Value);2))
what is wrong, is the syntax totally off?
Thanks in advance
The function POWER and SQRT do not exist in VBA.
Power(x, y) can be replaced with x ^ y
sqrt is sqr in VBA
So the following should work:
TempCalc = CLng(TextBox3.Value) * (16 * ((Sqr(CLng(TextBox1.Value) * 1 - CLng(TextBox1.Value))) / (CLng(TextBox1.Value) * CLng(TextBox2.Value))) ^ 2)
And I recommend to convert the integers to Long using CLng as there is no benefit in using Integer.
So to make it easier to debug I recommend to split the calculation:
Dim SqrtVal As Double
SqrtVal = Sqr(CLng(TextBox1.Value) * 1 - CLng(TextBox1.Value))
Dim DivVal As Double
DivVal = (CLng(TextBox1.Value) * CLng(TextBox2.Value))
Dim PowerVal As Double
PowerVal = (SqrtVal / DivVal) ^ 2
Dim TempCalc As Double
TempCalc = CLng(TextBox3.Value) * 16 * PowerVal

Is there a way to avoid the error statement "Arithmetic operation resulted in an overflow."?

I've done some research and the general advice is changing the datatype of the variable holding the expression to Long or Ulong but in either case, I'm still getting the same error. I also tried enclosing the expression with CInt() (or CLong()) to force it to cut out it's decimal portion to reduce the length of the output of the expression but neither is working. It's all pretty confusing. Any help will be deeply appreciated. The code block triggering the error is as follows;
Vsf(i) = CInt((((0.91544 - 0.00166 * Angle(i) - 0.000002 * W - 0.054248 *
Superelevation(i) - Sidefrictionfactor) / 0.013939) * Radius(i)) ^ 0.5)
Vro(i) = CInt((((1.04136 - 0.004528 * Angle(i) - 0.000004 * W - 0.338711 * Superelevation(i) - rolloverthreshold) / 0.014578) * Radius(i)) ^ 0.5)
Vmin(i) = CInt(Math.Min(Vsf(i), Vro(i)))
I declared VSf(), Vro() and Vmin() all as integer arrays. I even enclosed the computation expression in a CInt() in hopes that it would convert the result of Vro (which was triggering the arithmetic overflow error) to an integer and hence not have to deal with decimals which would lead to more digits. Yet when I hover over Vro(i), I see a 4 digit integer with decimals. Not sure why that's happening.
I broke the formula down to try and see where the problem was occurring. Everything buzzed along until the very end. If the value to be raised to .5 is a negative number, the square root does not produce a number. I would perform the steps of the formula without the ^.5 and then check for a negative number.
Private Sub OPCode()
Dim Angle = 90.2
Dim Radius = 100.2
Dim Superelevation = 37.8
Dim Sidefrictionfactor = 0.003
Dim W = 0.00325
Dim Vsf As Double
Dim AngleMultiplication = 0.00166 * Angle
Dim WMultiplication = 0.000002 * W
Dim SuperelavationMultiplication = 0.054248 * Superelevation
Dim SubtractResult = 0.91544 - AngleMultiplication - WMultiplication - SuperelavationMultiplication - Sidefrictionfactor
Dim DivisionResult = SubtractResult / 0.013939
Dim MultiplyByRadius = DivisionResult * Radius
Debug.Print(MultiplyByRadius.ToString) 'With my made up values I get a negative number
Vsf = MultiplyByRadius ^ 0.5 'You cannot get the square root of a negative number
Debug.Print(Vsf.ToString) 'NaN
Dim intVsf = CInt(Vsf) 'The Arithematic overflow error occurs here
End Sub

VB.Net Double comparison after some additions

I've faced a weird case with a double variable after adding some values to it.
The problem occurs when adding (0.2) to a double variable more than one time -I think it only happens with (0.2)- for example: consider this code:
Dim i As Double = 2
i = i + 0.2
MsgBox(i) '2.2
MsgBox(i > 2.2) 'False >> No problem
But if I add (0.2) more than one time:
Dim i As Double = 2
i = i + 0.2
i = i + 0.2
MsgBox(i) '2.4
Msgbox(i > 2.4) 'True >> !!!!
Also
Dim i As Double = 2
For x As Integer = 1 to 5
i = i + 0.2
Next
MsgBox(i) '3
Msgbox(i > 3) 'True >> !!!!
I tried the same code with other values, I don't get this issue:
Dim i As Double = 2
i = i + 0.5
i = i + 0.5
MsgBox(i) '3
Msgbox(i > 3) 'False >> No problem
Anyone has an explanation for this??
Thank you
If you take the example 3 you would see that the result is actually 3.0000000000000009.
The problem is in the rounding of a double.
If you change the data type decimal the problem is fixed:
Sub Main()
Dim i As Decimal = 2
For x As Integer = 1 To 5
i = i + 0.2
Next
MsgBox(i) '3
MsgBox(i > 3) 'False >> No problem
End Sub
This is about C# but, I guess, it the same thing for vb.net.
This issue known as "Accuracy Problems (Wikipedia Link)"
The fact that floating-point numbers cannot precisely represent all
real numbers, and that floating-point operations can not precisely
represent true arithmetic operations, leads to many surprising
situations. This is related to the finite precision with which
computers generally represent numbers.

Fractional Number.

how to fix this error. . when user input whole number and multipy it there's no problem in this part of my code
but when user input a fractional number(negative or positive) like "1/2,-2/3 ETC" there is an error
the error is pointing in: new1 = CDbl(txta1.Text) * CDbl(txtb2.Text) * CDbl(txtc3.Text)
Error Message: Conversion from string "1/2" to type 'Double' is not valid.
view plaincopy to clipboardprint?
Dim new1, new2, new3, new4, new5, new6, add1, add2, minus1 As Double
new1 = CDbl(txta1.Text) * CDbl(txtb2.Text) * CDbl(txtc3.Text)
new2 = CDbl(txta2.Text) * CDbl(txtb3.Text) * CDbl(txtc1.Text)
new3 = CDbl(txta3.Text) * CDbl(txtb1.Text) * CDbl(txtc2.Text)
new4 = CDbl(txtc1.Text) * CDbl(txtb2.Text) * CDbl(txta3.Text)
new5 = CDbl(txtc2.Text) * CDbl(txtb3.Text) * CDbl(txta1.Text)
new6 = CDbl(txtc3.Text) * CDbl(txtb1.Text) * CDbl(txta2.Text)
Please activate Option strict ON, which will help you to prevent rookie mistakes like trying to use a textfield like txta1.text as a number:
http://support.microsoft.com/kb/311329
You have to try to parse a value from text to a number like so:
Dim number1 As Double
If Double.TryParse(txta1.Text, number1) Then
// do something
Else
Console.WriteLine("{0} is outside the range of a Double.", _
value)
// report error
End If
Otherwise it is very hard to debug your code.
As to fractions: I would be very hard to parse a fraction reliably by hand. I would somethink prebuild, like a mathematic expression library. Take a look: https://ncalc.codeplex.com/
"1/2" is a string and must be parsed and converted into a numeric by your code.
Here is an example.
For use with simple fractions (as shown in your example), decimals and negative numbers.
Note: You should add error checking. For brevity, I did not include any error checking.
Dim strInput As String = "-1/2"
Dim dblValue As Double = Nothing
If strInput.Contains("/") Then ' A fraction
Dim strArray() As String = strInput.Split(CChar("/"))
dblValue = CDbl(strArray(0)) / CDbl(strArray(1))
Else
dblValue = CDbl(strInput)
End If
Console.WriteLine(dblValue)

Mod with Doubles

Am I doing something wrong or does the VBA Mod operator actually not work with floating point values like Doubles?
So I've always sort of assumed that the VBA Mod operator would work with Doubles based on the VB documentation, but in trying to figure out why my rounding function doesn't work, I found some unexpected Mod behavior.
Here is my code:
Public Function RoundUp(num As Double, Optional nearest As Double = 1)
RoundUp = ((num \ nearest) - ((num Mod nearest) > 0)) * nearest
End Function
RoundUp(12.34) returns 12 instead of 13 so I dug a little deeper and found that:
12.5 Mod 1 returns 0 with the return type of Long, whereas I had expected 0.5 with a type of Double.
Conclusion
As #ckuhn203 points out in his answer, according to the VBA specification,
The modulus, or remainder, operator divides number1 by number2
(rounding floating-point numbers to integers) and returns only the
remainder as result.
And
Usually, the data type of result is a Byte, Byte variant, Integer,
Integer variant, Long, or Variant containing a Long, regardless of
whether or not result is a whole number. Any fractional portion is
truncated.
For my purposes, I need a floating point modulo and so I have decided to use the following:
Public Function FMod(a As Double, b As Double) As Double
FMod = a - Fix(a / b) * b
'http://en.wikipedia.org/wiki/Machine_epsilon
'Unfortunately, this function can only be accurate when `a / b` is outside [-2.22E-16,+2.22E-16]
'Without this correction, FMod(.66, .06) = 5.55111512312578E-17 when it should be 0
If FMod >= -2 ^ -52 And FMod <= 2 ^ -52 Then '+/- 2.22E-16
FMod = 0
End If
End Function
Here are some examples:
FMod(12.5, 1) = 0.5
FMod(5.3, 2) = 1.3
FMod(18.5, 4.2) = 1.7
Using this in my rounding function solves my particular issue.
According to the VB6/VBA documentation
The modulus, or remainder, operator divides number1 by number2
(rounding floating-point numbers to integers) and returns only the
remainder as result. For example, in the following expression, A
(result) equals 5. A = 19 Mod 6.7 Usually, the data type of result is
a Byte, Byte variant, Integer, Integer variant, Long, or Variant
containing a Long, regardless of whether or not result is a whole
number. Any fractional portion is truncated. However, if any
expression is Null, result is Null. Any expression that is Empty is
treated as 0.
Remember, mod returns the remainder of the division. Any integer mod 1 = 0.
debug.print 12 mod 1
'12/1 = 12 r 0
The real culprit here though is that vba truncates (rounds down) the double to an integer before performing the modulo.
?13 mod 10
'==>3
?12.5 mod 10
'==>2
debug.print 12.5 mod 1
'vba truncates 12.5 to 12
debug.print 12 mod 1
'==> 0
I believe that the Mod operator calculates with long type only. The link that you provided is for VB.Net, which is not the same as the VBA you use in MSAccess.
The operator in VBA appears to accept a double type, but simply converts it to a long internally.
This test yielded a result of 1.
9 Mod 4.5
This test yielded a result of 0.
8 Mod 4.5
As a work around your can do some simple math on the values. To get two decimal of precision just multiply the input values by 100 and then divide the result by 100.
result = (123.45*100 Mod 1*100)/100
result = (12345 Mod 100)/100
result = 0.45
I'm late to the party, but just incase this answer is still helpful to someone.
Try This in VBS:
Option Explicit
Call Main()
Sub Main()
WScript.Echo CStr(Is_Rest_Of_Divide_Equal_To_Zero(506.25, 1.5625))
End Sub
Function Is_Rest_Of_Divide_Equal_To_Zero(Divident, Divisor)
Dim Result
Dim DivideResult
If Divident > Divisor Then
DivideResult = Round(Divident/Divisor, 0)
If (DivideResult * Divisor) > Divident Then
Result = False
ElseIf (DivideResult * Divisor) = Divident Then
Result = True
ElseIf (DivideResult * Divisor) < Divident Then
Result = False
End If
ElseIf Divident = Divisor Then
Result = True
ElseIf Divident < Divisor Then
Result = False
End If
Is_Rest_Of_Divide_Equal_To_Zero = Result
End Function
Public Function Modi(d as double) as double
Modi = d - Int(d)
End Function
Dim myDoule as Double
myDoule = 1.99999
Debug.Print Modi(myDoule)
0.99999