The following code raises a System.OverflowException
Dim b1 As Byte = 13
Dim b2 As Byte = 26
Dim b3 As Byte = 125
Dim b4 As Byte = 225
Dim i As Integer = (b1 + b2 + b3 + b4) \ 2
Why does this happen?
The value(s) doesn't get converted into an Integer until you assign it to the variable. This means that up until, and including, the \ 2 part everything is still of type Byte.
To make this work you've got to convert at least the first variable into an Integer, so that additional numbers can be added to it and go beyond 255.
Dim i As Integer = (CType(b1, Integer) + b2 + b3 + b4) \ 2
Online test: https://dotnetfiddle.net/Lxmx2S
Be aware that since this respects the order of mathematical operations, you must convert all the instances of too small types that are calculated before the others. For instance if you changed your operation to this:
Dim i As Integer = (CType(b1, Integer) + b2 * b3 + b4) \ 2
It would also throw an error because b2 * b3 is calculated before b1 + b2, and thus you would have to change it to:
Dim i As Integer = (CType(b1, Integer) + CType(b2, Integer) * b3 + b4) \ 2
Related
I just start it to make a program in vb.net in combination with SQL.
I have 5 textboxes with 5 values with 2 decimals, which are 10,50, 7,50, 8,50, 5,75, and 8,25. When I make a sum of this and put this in an other text box then it shows me the value 38,00 instead of 40,50.
My code is as follows:
Public Sub plussen()
Dim i1 As Integer
Dim i2 As Integer
Dim i3 As Integer
Dim i4 As Integer
Dim i5 As Integer
Dim i6 As Integer
For i1 = 5 To 20
i2 = i1 + 396
i3 = i1 + 496
i4 = i1 + 596
i5 = i1 + 696
i6 = i1 + 896
Me.Controls.Find("TextBox" + CStr(i1), True)(0).Text = (Val(Me.Controls.Find("TextBox" + CStr(i2), True)(0).Text) + Val(Me.Controls.Find("TextBox" + CStr(i3), True)(0).Text) + Val(Me.Controls.Find("TextBox" + CStr(i4), True)(0).Text) + Val(Me.Controls.Find("TextBox" + CStr(i5), True)(0).Text) + Val(Me.Controls.Find("TextBox" + CStr(i6), True)(0).Text)).ToString("F2")
Next
End Sub
I have put this in a loop because I have 20 x 5 boxes to calculate. This is working but as I said with this code it does not sums up the decimals.
Does someone have an idea about my issue?
This is super lame but from the documentation:
The Val function recognizes only the period (.) as a valid decimal
separator. When other decimal separators are used, as in international
applications, use CDbl or CInt instead to convert a string to a
number. To convert the string representation of a number in a
particular culture to a numeric value, use the numeric type's
Parse(String, IFormatProvider) method. For example, use Double.Parse
when converting a string to a Double.
So basically you need to use '.' instead of ',' in your textboxes or better yet switch from Val() to Double.Parse().
Ref: https://msdn.microsoft.com/en-us/library/9da280t0(v=vs.110).aspx
Change your val() to Convert.ToDecimal() and use CultureInfo("fr-FR") to specify the decimal format.
e.g.
Convert.ToDecimal("10,5", new CultureInfo("fr-FR"))
I'm running the following program, and get an overflow error at the first iteration once the program gets to a. From my understanding this shouldn't happen because I'm using Doubles which have a ridiculous amount of capacity, and a Long, but because it's only going up to 100 currently it shouldn't matter, and the code fails long before then. Here is my original inputs:
h0 = 1000, v0 = 0, a0 = g = -9.80665, dt = .01, m = 752.2528, b = .287875
and here's the code:
Sub drag()
Dim h0 As Double
Dim v0 As Double
Dim a0 As Double
Dim dt As Double
Dim m As Double
Dim b As Double
Dim g As Double
Dim i As Long
Dim h As Double
Dim v As Double
Dim a As Double
h0 = Worksheets("Drag").Cells(2, 8).Value
v0 = Worksheets("Drag").Cells(2, 9).Value
a0 = Worksheets("Drag").Cells(2, 10).Value
g = Worksheets("Drag").Cells(2, 10).Value
dt = Worksheets("Drag").Cells(2, 7).Value
m = Worksheets("Drag").Cells(2, 4).Value
b = Worksheets("Drag").Cells(2, 5).Value
Debug.Print h0 & v0 & a0 & dt & m & b
For i = 1 To 100
v = v0 + a0 * dt
h = 0.5 * a0 * (dt ^ 2) + v0 * dt + h0
a = m * g - b * (v ^ 2) 'Line where overflow occurs
v0 = v
h0 = h
a0 = a
Cells(i + 2, 8) = h0
Cells(i + 2, 9) = v0
Cells(i + 2, 10) = a0
Next i
Debug.Print h0 & v0 & a0 & dt & m & b
End Sub
Hope this is an easy fix.
Your overflow happens when i=14 (14th pass through the loop) and when v = -1.689 x 10^209. I don't know what you are trying to do, but v is blowing up. It would help if you describe what you are trying to do. – John Coleman 17 mins ago
#John Coleman I see the problem now, I'm doing the drag equation and I forgot to divide the a term by m, thanks. – Anthrochange 9 mins ago
You have already identified what needs to be done.
Now for the explanation on why the overflow on m * g - b * (v ^ 2). I added a watch as shown below
Consider the before and after screenshot
Before v = v0 + a0 * dt is calculated
After v = v0 + a0 * dt is calculated
What you see here is a very peculiar behaviour. A Type Double changing to an Integer
This is not normal and has been experienced before. Unfortunately this problem exists in Excel for a long time and unfortunately is also present in Excel 2016. It occurs only when you are using very large numbers. These kind of bugs are very rare, but yes, they do exist.
One can have a similar kind of experience when using MOD as mentioned in the below link
The MOD Function
The variable in question that is getting an overflow is v. You defined it as a double, which means you can only put numbers in the range of 1.79769313486232 * 10^308 to 4.94065645841247 * 10^–324. VBA uses 8 bytes to hold the double data. Any number outside of this huge range causes an overflow. (see here for more information about DBA data types)
How big of a number are you expecting? A rough estimate fo the number of atoms in the universe is 1 * 10^82, and the double value range goes to almost 2 *10^308. If you need to work with numbers that large, you're going to have to use a different method because it simply won't fit in the standard VBA data types.
Purpose: Take two fractions inputted on another platform and by user and evaluate them with IsNothing. If they aren't integers or strings that can be converted, run through Frac2Num (attached, I know this works, not the focus. Code created by Jeff Arms of Arecon Data).
It then checks to see if value A2 is greater than one. If so, then performs the math function (A2/2) - (A1/2) and then returns that value. Else, it returns 0.
So far I have only been able to return 0, so something with how it is reading the values or how its returning the value after the equation is messing it up, I think.
Main function:
Public Function MyFunction(ByVal A1 As String, ByVal A2 As String) As Integer
MyFunction= 0
Try
Dim B1 As Double
Dim B2 As Double
If IsNothing(A1) Then Return 0 'If the user provides no values, return 0.
If IsNothing(A2) Then Return 0 'If the user provides no values, return 0.
If IsNumeric(A1) = True Then
B1 = CDbl(A1)
Else
B1 = Frac2Num(A1)
End If 'If the value is an integer or convertible string, convert value to double. If not, run through Frac2Num function.
If IsNumeric(A2) = True Then
B2 = CDbl(A2)
Else
B2 = Frac2Num(A2)
End If
If A2 > 1 Then
MyFunction= (A2 / 2) - (A1 / 2)
Return MyFunction
Else MyFunction= 0
End If 'If A2 is greater than one, then MyFunction = value created by equation.
Catch ex As Exception
End Try
Frac2Num function:
Function Frac2Num(ByVal X As String) As Double
Dim P As Integer, N As Double, Num As Double, Den As Double
X = Trim$(X)
P = InStr(X, "/")
If P = 0 Then
N = Val(X)
Else
Den = Val(Mid$(X, P + 1))
If Den = 0 Then Error 11 ' Divide by zero
X = Trim$(Left$(X, P - 1))
P = InStr(X, " ")
If P = 0 Then
Num = Val(X)
Else
Num = Val(Mid$(X, P + 1))
N = Val(Left$(X, P - 1))
End If
End If
If Den <> 0 Then
N = N + Num / Den
End If
Frac2Num = N
End Function
Returning:
Sub Main()
Dim result As Integer
result = MyFunction("8 1/2", "8 5/8") 'Function called with example values.
Console.WriteLine(result)
Console.ReadLine()
End Sub
First of all, in the end of your code you are trying to convert a fraction string directly to a number, witch is causing your code to generate an exception and go to the Catch block
change it to
'You are using A1 and A2, change it to B1 and B#
If B2 > 1 Then
MyFunction = (B2 * 1.0 / 2) - (B1 * 1.0 / 2)
Return MyFunction
Else : MyFunction = 0
End If
also, you are returning an integer and assigning the result to an integer. Even if the result was computed properly in your example case it will not be evaluated correctly. Changing it to Double should solve it.
Public Function MyFunction(ByVal A1 As String, ByVal A2 As String) As Double
and
Dim result As Double
result = MyFunction("8 1/2", "8 5/8")
Private Function lang_array(ByVal temp As Double) As Double
'This program call the subroutine langmuir to calculate langmuir constants
'of each molecule for the small cage and for the large cage
Dim molenum As Integer = 1 ' Number of molecular species
Dim sigma(10) As Double ' value of sigma for each species
sigma(0) = 0.00000000030197
Dim radius(10) As Double ' value of core radius for each species
radius(0) = 0.000000000072
Dim edep_div_k(10) As Double ' value of energy depth/k for each species
edep_div_k(0) = 171.3
Dim z_small As Double = 20 ' coordination number for small cage
Dim z_large As Double = 24 'coordination number for large cage
Dim r_small As Double = 0.000000000391 ' radius of small cage
Dim r_large As Double = 0.000000000433 ' radius of large cage
Dim n_small As Double = 1.0 / 23.0 'number of small cage per one water molecule
Dim n_large As Double = 3.0 / 23.0 'number of large cage per one water molecule
'In langmuir constant array c[k][i], suffix k changes with molecular species
' and suffix i changes with cavity type
'In suffix i, 0 indicates small cavity and 1 indicates large cavity.
Dim c1, c2, c3, c4, c5 As Double
Dim c(2, 2) As Double
Dim k As Integer
For k = 0 To molenum
c1 = z_small
c2 = r_small
c3 = sigma(k)
c4 = radius(k)
c5 = edep_div_k(k)
c(k, 0) = langmuir(temp, c1, c2, c3, c4, c5)
Next
' Calculate langmuir constant for large cavity
For k = 0 To molenum
c1 = z_large
c2 = r_large
c3 = sigma(k)
c4 = radius(k)
c5 = edep_div_k(k)
c(k, 1) = langmuir(temp, c1, c2, c3, c4, c5)
Next
**Return (c)**
End Function
' All I am trying to return the value of array (c(k,0) & c(k,1)) but I unable to do that. Can you help please
change the signature to:
Private Function lang_array(ByVal temp As Double) As Double(,)
should work then
This function goes through all integers and picks out binary values with only five ones and writes them to the spreadsheet.
To run this For x = 1 To 134217728 would take 2.5 days!!!! Help!
How could I speed this up?
Function D2B(ByVal n As Long) As String
n = Abs(n)
D2B = ""
Do While n > 0
If n = (n \ 2) * 2 Then
D2B = "0" & D2B
Else
D2B = "1" & D2B
n = n - 1
End If
n = n / 2
Loop
End Function
Sub mixtures()
Dim x As Long
Dim y As Integer
Dim fill As String
Dim mask As String
Dim RowOffset As Integer
Dim t As Date
t = Now
fill = ""
For x = 1 To 134217728
mask = Right(fill & CStr(D2B(x)), Len(fill & CStr(D2B(x))))
Debug.Print mask
If x > 100000 Then Exit For
If Len(mask) - Len(WorksheetFunction.Substitute(mask, "1", "")) = 5 Then _
RowOffset = RowOffset + 1
For y = 1 To Len(mask)
If Len(mask) - Len(WorksheetFunction.Substitute(mask, "1", "")) = 5 Then _
Range("mix").Offset(RowOffset).Cells(y) = Mid(mask, y, 1)
Next
Next
Debug.Print DateDiff("s", Now, t)
End Sub
By first sight guess, I think the problem lies in the fact that you do that cell by cell, which causes many read and write accesses.
You should do it range by range, like
vArr = Range("A1:C1000").Value
' it is array now, do something here effeciently
Range("A1:C1000").Value = vArr
You want find all 28bit numbers with 5 1s
There are 28*27*26*25*24/5/4/3/2=98280 such numbers
The following code took ~10 seconds on my PC:
lineno = 1
For b1 = 0 To 27
For b2 = b1 + 1 To 27
For b3 = b2 + 1 To 27
For b4 = b3 + 1 To 27
For b5 = b4 + 1 To 27
Cells(lineno, 1) = 2 ^ b1 + 2 ^ b2 + 2 ^ b3 + 2 ^ b4 + 2 ^ b5
lineno = lineno + 1
Next
Next
Next
Next
Next
mask = Right(fill & CStr(D2B(x)), Len(fill & CStr(D2B(x))))
The above line of code does the same thing (CStr(D2B(x))) twice.
Store the result of CStr(D2B(x)) in a variable & use that variable in the above line of code.
I've got 2 suggestions:
Get rid of the substitution command by counting the ones/zeroes in D2B and return an empty string if the count does not equal 5
Write these pre-filtered bitstrings to an array first and copy the array directly to the cells when finished.
Something like
ws.Range(ws.cells(1, 1), ws.cells(UBound(dstArr, 1) + 1, UBound(dstArr, 2) + 1)) = dstArr
The array-copy-trick greatly improves performance!