I found a ROUNDUP equivalent from this link: http://allenbrowne.com/round.html#RoundUp
To round upwards towards the next highest number, take advantage of the way Int() rounds negative numbers downwards, like this: - Int( - [MyField])
As shown above, Int(-2.1) rounds down to -3. Therefore this expression rounds 2.1 up to 3.
To round up to the higher cent, multiply by -100, round, and divide by -100: Int(-100 * [MyField]) / -100
The syntax is counter-intuitive, but it works exactly as I intended.
Answer from alextansc on Stack OverflowroundUp Function | Access World Forums
sql - How to ROUNDUP a number in Access 2013? - Stack Overflow
ms access - How can I always round up decimal values to the nearest integer value? - Stack Overflow
excel - Rounding in MS Access - Stack Overflow
Videos
I found a ROUNDUP equivalent from this link: http://allenbrowne.com/round.html#RoundUp
To round upwards towards the next highest number, take advantage of the way Int() rounds negative numbers downwards, like this: - Int( - [MyField])
As shown above, Int(-2.1) rounds down to -3. Therefore this expression rounds 2.1 up to 3.
To round up to the higher cent, multiply by -100, round, and divide by -100: Int(-100 * [MyField]) / -100
The syntax is counter-intuitive, but it works exactly as I intended.
I have found the easiest way to round up a number in access is to use the round function like this:
Round([MyField]+0.4,0)
The number 10.1, for example then becomes 10.5. When the round function is applied, it rounds up to 11. If the number is 10.9, adding 0.4 becomes 11.3, which rounds to 11.
This is an old Access trick I learned a very long time ago, and it makes use of the way Access handles fractional, negative numbers. Try this:
-Int(-[DecimalValue])
It's odd, but it will always round your numbers up to the nearest whole number.
Test this: Round(yournumber + 0.5, 0)
Be careful, the VBA Round function uses Banker's rounding, where it rounds .5 to an even number, like so:
Round (12.55, 1) would return 12.6 (rounds up)
Round (12.65, 1) would return 12.6 (rounds down)
Round (12.75, 1) would return 12.8 (rounds up)
Whereas the Excel Worksheet Function Round, always rounds .5 up.
I've done some tests and it looks like .5 up rounding (symmetric rounding) is also used by cell formatting, and also for Column Width rounding (when using the General Number format). The 'Precision as displayed' flag doesn't appear to do any rounding itself, it just uses the rounded result of the cell format.
I tried to implement the SymArith function from Microsoft in VBA for my rounding, but found that Fix has an error when you try to give it a number like 58.55; the function giving a result of 58.5 instead of 58.6. I then finally discovered that you can use the Excel Worksheet Round function, like so:
Application.Round(58.55, 1)
This will allow you to do normal rounding in VBA, though it may not be as quick as some custom function. I realize that this has come full circle from the question, but wanted to include it for completeness.
To expand a little on the accepted answer:
"The Round function performs round to even, which is different from round to larger."
--Microsoft
Format always rounds up.
Debug.Print Round(19.955, 2)
'Answer: 19.95
Debug.Print Format(19.955, "#.00")
'Answer: 19.96
ACC2000: Rounding Errors When You Use Floating-Point Numbers: http://support.microsoft.com/kb/210423
ACC2000: How to Round a Number Up or Down by a Desired Increment: http://support.microsoft.com/kb/209996
Round Function: http://msdn2.microsoft.com/en-us/library/se6f2zfx.aspx
How To Implement Custom Rounding Procedures: http://support.microsoft.com/kb/196652
You can use the RoundUp and RoundDown functions found here at Experts Exchange and here at GitHub.
Your usage would be:
Value = 27.605
Value1 = RoundUp(Value, 2) ' 27.61
Value2 = RoundDown(Value, 2) ' 27.6
These are the functions:
' Rounds Value up with count of decimals as specified with parameter NumDigitsAfterDecimals.
'
' Rounds to integer if NumDigitsAfterDecimals is zero.
'
' Optionally, rounds negative values away from zero.
'
' Uses CDec() for correcting bit errors of reals.
'
' Execution time is about 0.5µs for rounding to integer
' else about 1µs.
'
Public Function RoundUp( _
ByVal Value As Variant, _
Optional ByVal NumDigitsAfterDecimals As Long, _
Optional ByVal RoundingAwayFromZero As Boolean) _
As Variant
Dim Scaling As Variant
Dim ScaledValue As Variant
Dim ReturnValue As Variant
' Only round if Value is numeric and ReturnValue can be different from zero.
If Not IsNumeric(Value) Then
' Nothing to do.
ReturnValue = Null
ElseIf Value = 0 Then
' Nothing to round.
' Return Value as is.
ReturnValue = Value
Else
If NumDigitsAfterDecimals <> 0 Then
Scaling = CDec(Base10 ^ NumDigitsAfterDecimals)
Else
Scaling = 1
End If
If Scaling = 0 Then
' A very large value for Digits has minimized scaling.
' Return Value as is.
ReturnValue = Value
ElseIf RoundingAwayFromZero = False Or Value > 0 Then
' Round numeric value up.
If Scaling = 1 Then
' Integer rounding.
ReturnValue = -Int(-Value)
Else
' First try with conversion to Decimal to avoid bit errors for some reals like 32.675.
On Error Resume Next
ScaledValue = -Int(CDec(-Value) * Scaling)
ReturnValue = ScaledValue / Scaling
If Err.Number <> 0 Then
' Decimal overflow.
' Round Value without conversion to Decimal.
ScaledValue = -Int(-Value * Scaling)
ReturnValue = ScaledValue / Scaling
End If
End If
Else
' Round absolute value up.
If Scaling = 1 Then
' Integer rounding.
ReturnValue = Int(Value)
Else
' First try with conversion to Decimal to avoid bit errors for some reals like 32.675.
On Error Resume Next
ScaledValue = Int(CDec(Value) * Scaling)
ReturnValue = ScaledValue / Scaling
If Err.Number <> 0 Then
' Decimal overflow.
' Round Value without conversion to Decimal.
ScaledValue = Int(Value * Scaling)
ReturnValue = ScaledValue / Scaling
End If
End If
End If
If Err.Number <> 0 Then
' Rounding failed because values are near one of the boundaries of type Double.
' Return value as is.
ReturnValue = Value
End If
End If
RoundUp = ReturnValue
End Function
And:
' Rounds Value down with count of decimals as specified with parameter NumDigitsAfterDecimals.
'
' Rounds to integer if NumDigitsAfterDecimals is zero.
'
' Optionally, rounds negative values towards zero.
'
' Uses CDec() for correcting bit errors of reals.
'
' Execution time is about 0.5µs for rounding to integer
' else about 1µs.
'
Public Function RoundDown( _
ByVal Value As Variant, _
Optional ByVal NumDigitsAfterDecimals As Long, _
Optional ByVal RoundingToZero As Boolean) _
As Variant
Dim Scaling As Variant
Dim ScaledValue As Variant
Dim ReturnValue As Variant
' Only round if Value is numeric and ReturnValue can be different from zero.
If Not IsNumeric(Value) Then
' Nothing to do.
ReturnValue = Null
ElseIf Value = 0 Then
' Nothing to round.
' Return Value as is.
ReturnValue = Value
Else
If NumDigitsAfterDecimals <> 0 Then
Scaling = CDec(Base10 ^ NumDigitsAfterDecimals)
Else
Scaling = 1
End If
If Scaling = 0 Then
' A very large value for Digits has minimized scaling.
' Return Value as is.
ReturnValue = Value
ElseIf RoundingToZero = False Then
' Round numeric value down.
If Scaling = 1 Then
' Integer rounding.
ReturnValue = Int(Value)
Else
' First try with conversion to Decimal to avoid bit errors for some reals like 32.675.
' Very large values for NumDigitsAfterDecimals can cause an out-of-range error when dividing.
On Error Resume Next
ScaledValue = Int(CDec(Value) * Scaling)
ReturnValue = ScaledValue / Scaling
If Err.Number <> 0 Then
' Decimal overflow.
' Round Value without conversion to Decimal.
ScaledValue = Int(Value * Scaling)
ReturnValue = ScaledValue / Scaling
End If
End If
Else
' Round absolute value down.
If Scaling = 1 Then
' Integer rounding.
ReturnValue = Fix(Value)
Else
' First try with conversion to Decimal to avoid bit errors for some reals like 32.675.
' Very large values for NumDigitsAfterDecimals can cause an out-of-range error when dividing.
On Error Resume Next
ScaledValue = Fix(CDec(Value) * Scaling)
ReturnValue = ScaledValue / Scaling
If Err.Number <> 0 Then
' Decimal overflow.
' Round Value with no conversion.
ScaledValue = Fix(Value * Scaling)
ReturnValue = ScaledValue / Scaling
End If
End If
End If
If Err.Number <> 0 Then
' Rounding failed because values are near one of the boundaries of type Double.
' Return value as is.
ReturnValue = Value
End If
End If
RoundDown = ReturnValue
End Function
Note please, that the native Round of VBA is quite buggy. See the test module of the download.
You won't get a better answer than Gustav's for proper rounding functions, and in the case of only two constituent values, then the complimentary RoundDown and RoundUp functions are sufficient. (FYI, similar functions are often named Floor and Ceiling in other languages and programming libraries.)
However, when it is critical to have constituent values sum to an original/expected value, it is best to calculate the last of the constituent values by a difference of the expected total and the sum of all other rounded values. This will guarantee the correct sum even if there are unexpected results from rounding. Even if using the buggy VBA Round() function, this technique would have avoided the 1 cent errors to start with.
surcharge1 = SomeRoundFunction(Total_Surcharge / 2.0)
surcharge2 = Total_Surcharge - surcharge1
This is especially important with more than two constituent values, since there is no set of rounding functions that will properly round 3 or more values to guarantee they add up to some value. As an example, I recently had to split out total transaction amounts by (re)calculating discounts and taxes. Although I knew the percentages for both, I needed to figure each part rounded to the penny. Penny errors were acceptable in both discount and tax, but they still needed to add up to the total after any rounding. The only guarantee to ensure that the final transaction value remained unchanged was to first calculate and round the tax, next calculate and round the discount, then finally correct for penny errors by subtracting the sum of parts from the expected total.