Rounding a variable to an integer - vba

I have a calculation like this: 3 * 12300 / 160. The result is: 230.625. But I just want the integer part, 230.
In C, this can be done using something like this: int MyVar = (int)3*12300/160;
Is there a way in VBA (With MS-Access) for force the result to be an integer?

You can round down using the Int or Fix functions.
Since you know the result you want is a whole number, you should store the result in a variable of type Long (or Integer if you're absolutely certain it will always be smaller than 32768).
Dim l As Long
l = Int(3 / 160 * 12300) ' <~~~~ Yes, I switched the numbers around on purpose!*
MsgBox "l = " & l
* Why did I switch the numbers around? Because the expression 3 * 12300 / 160 will throw an error in VBA. Read here why: Overflow when multiplying Integers and assigning to Long

Related

VBA: difference between Variant/Double and Double

I am using Excel 2013. In the following code fragment, VBA calculates 40 for damage:
Dim attack As Variant, defense As Variant, damage As Long
attack = 152 * 0.784637
defense = 133 * 0.784637
damage = Int(0.5 * attack / defense * 70)
If the data types are changed to Double, VBA calculates 39 for damage:
Dim attack As Double, defense As Double, damage As Long
attack = 152 * 0.784637
defense = 133 * 0.784637
damage = Int(0.5 * attack / defense * 70)
In the debugger, the Variant/Double and Double values appear the same. However, the Variant/Double seems to have more precision.
Can anyone explain this behavior?
tldr; If you need more precision than a Double, don't use a Double.
The answer lies in the timing of when the result is coerced into a Double from a Variant. A Double is an IEEE 754 floating-point number, and per the IEEE specification reversibility is guaranteed to 15 significant digits. Your value flirts with that limit:
0.5 * (152 * .784637) / (133 * .784637) * 70 = 39.99999999999997 (16 sig. digits)
VBA will round anything beyond 15 significant digits when it is coerced into a double:
Debug.Print CDbl("39.99999999999997") '<--Prints 40
In fact, you can watch this behavior in the VBE. Type or copy the following code:
Dim x As Double
x = 39.99999999999997
The VBE "auto-corrects" the literal value by casting it to a Double, which gives you:
Dim x As Double
x = 40#
OK, so by now you're probably asking what that has to do with the difference between the 2 expressions. VBA evaluates mathematical expressions using the "highest order" variable type that it can.
In your second Sub where you have all of the variable declared as Double on the right hand side, the operation is evaluated with the high order of Double, then the result is implicitly cast to a Variant before being passed as the parameter for Int().
In your first Sub where you have Variant declarations, the implicit cast to Variant isn't performed before passing to Int - the highest order in the mathematical expression is Variant, so no implicit cast is performed before passing the result to Int() - the Variant still contains the raw IEEE 754 float.
Per the documentation of Int:
Both Int and Fix remove the fractional part of number and return the
resulting integer value.
No rounding is performed. The top code calls Int(39.99999999999997). The bottom code calls Int(40). The "answer" depends on what level of floating point error you want to round at. If 15 works, then 40 is the "correct" answer. If you want to floor anything up to 16 or more significant digits, then 39 is the "correct" answer. The solution is to use Round and specify the level of precision you're looking for explicitly. For example, if you care about the full 15 digits:
Int(Round((0.5 * attack / defense * 70), 15))
Keep in mind that the highest precision you use anywhere in the inputs is 6 digits, so that would be a logical rounding cut-off:
Int(Round((0.5 * attack / defense * 70), 6))
If you get rid of the Int() function on both lines where damage is calculated both end up being the same. You shouldn't be using Int as this is producing the errant behavour, you should be using CLng as you are converting to a Long variable or if damage were an Int you should use CInt.
Int and CInt behave differently. Int always rounds down to the next lower whole number - whereas CInt will round up or down using Banker's Rounding. You'll typically see this behaviour for numbers that have a mantissa of 0.5.
As for the variant and double differences, if you do a TypeName to a MsgBox for the 1st code block you'll find that both attack and defense after having been assigned values have been converted to a double despite having been declared as variant.

Why am I getting this error in Visual Basic 2010? What does it mean?

I don't know why it does this but here is the code linked to it not show in the picture.
In the My.Settings the type is string
Dim cursorValue as BigInteger
Dim cursorPrice as BigInteger
Dim xCursor as Decimal
My.Settings.cursorValue = cursorValue.ToString
My.Settings.cursorPrice = cursorPrice.ToString
My.Settings.xCursor = xCursor
Error:
To Update Values Displayed:
cursorUpgrade.Text = "Cursors: " & cursorValue.ToString("N0") & Environment.NewLine & "Upgrade: " & cursorPrice.ToString("N0")
You can't mix BigInteger and decimal values in arithmetic directly in VB.
One way to handle this would be to scale your decimal value up by a power of 10 and make it a BigInteger and perform your aritmetic in the BigInteger domain. So, if you need to multiply your BigInteger by an arbitrary decimal number, and you know what precision you're willing to accept, you could do (assuming you want to maintain 4 decimal places of precision when multiply your decimal number):
cursorValue *= (BigInteger)(xCursor * 10000)
cursorValue /= 10000
In the case of adding 1, just add 1 instead of attempting to add xCursor:
cursorValue += 1
Or, if you know you want to add xCursor as an integer:
cursorValue += (BigInteger)xCursor
The problem you are having seems to to in the code in your linked picture
cursorValue += xCursor
Won't work if cursorValue is BigInteger and xCursor is Dewcimal for the reasons given in the error message. Instead you could use
cursorValue += New BigInteger(xCursor)

Vb.net number truncate. How to do this?

I wanna round "2.765467..." number to "2.70".
How can i do that?
İ tried Math.round or math.floor but not working:(
Anyone can send a code for vb.net?
It sounds like what you want to do is truncate, not round. Try this:
Dim decTemp = (10 ^ NumberOfPlaces)
Return CDec(Fix(ToTruncate * decTemp) / decTemp)
Where ToTruncate is the number you'd like to truncate, and NumberOfPlaces is the number of decimal places you want to truncate to. In your case:
Dim ToTruncate As Decimal = 2.765467D
Dim NumberofPlaces as Integer = 1
Dim decTemp = (10 ^ NumberOfPlaces)
Return CDec(Fix(ToTruncate * decTemp) / decTemp)

VBA Ultimate rounding

I've read much about rounding in Excel. I found out that VBA's Round() function uses "Bankers rounding" while Application.WorksheetFunction.Round() uses more or less "normal" rounding. But it didn't help me to understand this:
? Round(6.03499,2)
6.03
Why? I want to see 6.04, not 6.03! The trick is that
? Round(Round(6.03499,3),2)
6.04
I thought a bit and developed a subroutine like this:
Option Explicit
Function DoRound(ByVal value As Double, Optional ByVal numdigits As Integer = 0) As Double
Dim i As Integer
Dim res As Double
res = value
For i = 10 To numdigits Step -1
res = Application.Round(res, i)
Next i
DoRound = res
End Function
It works fine.
? DoRound(6.03499,2)
6.04
But it is not cool. Is there any built-in normal rounding in Excel?
If you round 6.03499 to 3 digits it will be 6.035 - which is correct.
If you round 6.03499 to 2 digits it will be 6.03 - which is correct
However - the example where you first round to 3 digits, then to 2 is also correct, by the following statement:
Round(6.03499, 3) gives 6.035
Round(6.035, 2) gives 6.04
If you want Round(6.03499, 2) to give 6.04 you have to use Application.WorksheetFunction.RoundUp
Rounding 6.0349 to two decimals is just not 6.04 hence, no, there is no such function.
Round up will round anything up. Hence, 6.0000000001 will also become 7 if you round to 0 decimals.

Rounding a number to the nearest 5 or 10 or X

Given numbers like 499, 73433, 2348 what VBA can I use to round to the nearest 5 or 10? or an arbitrary number?
By 5:
499 -> 500
2348 -> 2350
7343 -> 7345
By 10:
499 -> 500
2348 -> 2350
7343 -> 7340
etc.
It's simple math. Given a number X and a rounding factor N, the formula would be:
round(X / N)*N
Integrated Answer
X = 1234 'number to round
N = 5 'rounding factor
round(X/N)*N 'result is 1235
For floating point to integer, 1234.564 to 1235, (this is VB specific, most other languages simply truncate) do:
int(1234.564) 'result is 1235
Beware: VB uses Bankers Rounding, to the nearest even number, which can be surprising if you're not aware of it:
msgbox round(1.5) 'result to 2
msgbox round(2.5) 'yes, result to 2 too
Thank you everyone.
To round to the nearest X (without being VBA specific)
N = X * int(N / X + 0.5)
Where int(...) returns the next lowest whole number.
If your available rounding function already rounds to the nearest whole number then omit the addition of 0.5
In VB, math.round has additional arguments to specify number of decimal places and rounding method. Math.Round(10.665, 2, MidpointRounding.AwayFromZero) will return 10.67 . If the number is a decimal or single data type, math.round returns a decimal data type. If it is double, it returns double data type. That might be important if option strict is on.
The result of (10.665).ToString("n2") rounds away from zero to give "10.67". without additional arguments math.round returns 10.66, which could lead to unwanted discrepancies.
'Example: Round 499 to nearest 5. You would use the ROUND() FUNCTION.
a = inputbox("number to be rounded")
b = inputbox("Round to nearest _______ ")
strc = Round(A/B)
strd = strc*B
msgbox( a & ", Rounded to the nearest " & b & ", is" & vbnewline & strd)
For a strict Visual Basic approach, you can convert the floating-point value to an integer to round to said integer. VB is one of the rare languages that rounds on type conversion (most others simply truncate.)
Multiples of 5 or x can be done simply by dividing before and multiplying after the round.
If you want to round and keep decimal places, Math.round(n, d) would work.
Here is our solution:
Public Enum RoundingDirection
Nearest
Up
Down
End Enum
Public Shared Function GetRoundedNumber(ByVal number As Decimal, ByVal multiplier As Decimal, ByVal direction As RoundingDirection) As Decimal
Dim nearestValue As Decimal = (CInt(number / multiplier) * multiplier)
Select Case direction
Case RoundingDirection.Nearest
Return nearestValue
Case RoundingDirection.Up
If nearestValue >= number Then
Return nearestValue
Else
Return nearestValue + multiplier
End If
Case RoundingDirection.Down
If nearestValue <= number Then
Return nearestValue
Else
Return nearestValue - multiplier
End If
End Select
End Function
Usage:
dim decTotal as Decimal = GetRoundedNumber(CDec(499), CDec(0.05), RoundingDirection.Up)
Simply ROUND(x/5)*5 should do the job.
I cannot add comment so I will use this
in a vbs run that and have fun figuring out why the 2 give a result of 2
you can't trust round
msgbox round(1.5) 'result to 2
msgbox round(2.5) 'yes, result to 2 too
something like that?
'nearest
n = 5
'n = 10
'value
v = 496
'v = 499
'v = 2348
'v = 7343
'mod
m = (v \ n) * n
'diff between mod and the val
i = v-m
if i >= (n/2) then
msgbox m+n
else
msgbox m
end if
Try this function
--------------start----------------
Function Round_Up(ByVal d As Double) As Integer
Dim result As Integer
result = Math.Round(d)
If result >= d Then
Round_Up = result
Else
Round_Up = result + 1
End If
End Function
-------------end ------------
I slightly updated the function provided by the "community wiki" (the best answer), just to round to the nearest 5 (or anything you like), with this exception : the rounded number will NEVER be superior to the original number.
This is useful in cases when it is needed to say that "a company is alive for 47 years" : I want the web page to display "is alive for more than 45 years", while avoiding lying in stating "is alive for more than 50 years".
So when you feed this function with 47, it will not return 50, but will return 45 instead.
'Rounds a number to the nearest unit, never exceeding the actual value
function RoundToNearestOrBelow(num, r)
'#param num Long/Integer/Double The number to be rounded
'#param r Long The rounding value
'#return OUT Long The rounded value
'Example usage :
' Round 47 to the nearest 5 : it will return 45
' Response.Write RoundToNearestBelow(47, 5)
Dim OUT : OUT = num
Dim rounded : rounded = Round((((num)) / r), 0) * r
if (rounded =< num) then
OUT = rounded
else
OUT = rounded - r
end if
'Return
RoundToNearestOrBelow = OUT
end function 'RoundToNearestOrBelow
To mimic in Visual Basic the way the round function works in Excel, you just have to use:
WorksheetFunction.Round(number, decimals)
This way the banking or accounting rounding don't do the rounding.