IN THE SPOTLIGHT: MDE to MDB Conversion Service
(also supports: ACCDE to ACCDB, ADE to ADP, etc)
IN THE SPOTLIGHT: vbWatchdog
VBA error handling just got easier...
" vbWatchdog is off the chart. It solves a long standing problem of how to consolidate error handling into one global location and avoid repetitious code within applications. "
- Joe Anderson,
Microsoft Access MVP
Meet Shady, the vbWatchdog mascot watching over your VBA code →
(courtesy of Crystal Long, Microsoft Access MVP)
IN THE SPOTLIGHT: vbMAPI
An Outlook / MAPI code library for VBA, .NET and C# projects
Get emails out to your customers reliably, and without hassle, every single time.
Use vbMAPI alongside Microsoft Outlook to add professional emailing capabilities to your projects.
Provided by Allen Browne. Created: December 2007. Updated August 2008.
To round numbers, Access 2000 and later has a Round() function built in.
For earlier versions, get this custom rounding function by Ken Getz.
Use the Round() function in the Control Source of a text box, or in a calculated query field.
Say you have this expression in the Field row in query design:
Tax: [Amount] * [TaxRate]
To round to the nearest cent, use:
Tax: Round([Amount] * [TaxRate], 2)
To round all fractional values down to the lower number, use Int():
All these numbers would then be rounded down to 2: 2.1, 2.5, 2.8, and 2.99.
To round down to the lower cent (e.g. $10.2199 becomes $10.21), multiply by 100, round, and then divide by 100:
Int(100 * [MyField]) / 100
Be aware of what happens when negative values are rounded down: Int(-2.1) yields -3, since that is the integer below. To round towards zero, use Fix() instead of Int():
Fix(100 * [MyField]) / 100
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
To round to the nearest 5 cents, multiply the number by 20, round it, and divide by 20:
Round(20 * [MyField], 0) / 20
Similarly, to round to the nearest quarter, multiply by 4, round, and divide by 4:
Round(4 * [MyField], 0) / 4
The Round() function in Excel accepts negative numbers for the number of decimal places, e.g. Round(123456, -3) rounds to the nearest 1000. Unfortunately, the Access function does not support this.
To round to the nearest $1000, divide by 1000, round, and multiply by 1000. Example:
1000 * Round([Amount] / 1000, 0)
To round down to the lower $1000, divide by 1000, get the integer value, and multiply by 1000. Example:
1000 * Int([Amount] / 1000)
To round up to the higher $1000, divide by 1000, negate before you get the integer value. Example:
-1000 * Int( [Amount] / -1000)
To round towards zero, use Fix() instead of Int().
Alternatively, Ken Getz' custom rounding function behaves like the Excel function.
There is a Decimal Places property for fields in a table/query and for text boxes on a form/report. This property only affects the way the field is displayed, not the way it is stored. The number will appear to be rounded, but when you sum these numbers (e.g. at the foot of a report), the total may not add up correctly.
Round the field when you do the calculation, and the field will sum correctly.
This applies to currency fields as well. Access displays currency fields rounded to the nearest cent, but it stores the value to the hundredth of a cent (4 decimal places.)
The Round() function in Access uses a bankers rounding. When the last significant digit is a 5, it rounds to the nearest even number. So, 0.125 rounds to 0.12 (2 is even), whereas 0.135 rounds to 0.14 (4 is even.)
The core idea here is fairness: 1,2,3, and 4 get rounded down. 6,7,8, and 9 get rounded up. 0 does not need rounding. So if the 5 were always rounded up, you would get biased results - 4 digits being rounded down, and 5 being rounded up. To avoid this, the odd one out (the 5) is rounded according to the previous digit, which evens things up.
If you do not wish to use bankers rounding, get Ken Getz' custom function (linked above.)
Fractional values in a computer are typically handled as floating point numbers. Access fields of type Double or Single are this type. The Double gives about 15 digits of precision, and the Single gives around 8 digits (similar to a hand-held calculator.)
But these numbers are approximations. Just as 1/3 requires an infinite number of places in the decimal system, most floating point numbers cannot be represented precisely in the binary system. Wikipedia explains the accuracy problems you face when computing floating point numbers.
The upshot is that marginal numbers may not round the way you expect, due to the fact that the actual values and the display values are not the same. This is especially noticeable when testing bankers rounding.
One way to avoid these issues is to use a fixed point or scalar number instead. The Currency data type in Access is fixed point: it always stores 4 decimal places.
For example, open the Immediate Window (Ctrl+G), and enter:
? Round(CCur(.545),2), Round(CDbl(.545),2)
The Currency type (first one) yields 0.54, whereas the Double yields 0.55. The Currency rounds correctly (towards the even 4); the floating point type (Double) is inaccurate. Similarly, if you try 8.995, the Currency correctly rounds up (towards the even 0), while the Double rounds it down (wrong.)
Currency copes with only 4 decimal places. Use the scalar type Decimal if you need more places after the decimal point.
Note that the Date/Time data type in Access is a special kind of floating point type, where the fractional part represents the time of day. Consequently, Date/Time fields that have a time component are subject to floating point errors as well.
The function below rounds a date/time value to the specified number of seconds. For example, to round to the nearest half hour (30 * 60 seconds), use:
Public Function RoundTime(varTime As Variant, Optional ByVal lngSeconds As Long = 900&) As Variant 'Purpose: Round a date/time value to the nearest number of seconds 'Arguments: varTime = the date/time value ' lngSeconds = number of seconds to round to. ' e.g. 60 for nearest minute, ' 600 for nearest 10 minutes, ' 3600 for nearest hour, ' 86400 for nearest day. 'Return: Rounded date/time value, or Null if no date/time passed in. 'Note: lngSeconds must be between 1 and 86400. ' Default rounds is nearest 15 minutes. Dim lngSecondsOffset As Long RoundTime = Null 'Initialize to return Null. If Not IsError(varTime) Then If IsDate(varTime) Then If (lngSeconds < 1&) Or (lngSeconds > 86400) Then lngSeconds = 1& End If lngSecondsOffset = lngSeconds * CLng(DateDiff("s", #12:00:00 AM#, TimeValue(varTime)) / lngSeconds) RoundTime = DateAdd("s", lngSecondsOffset, DateValue(varTime)) End If End If End Function
For a more technical explanation of rounding theory in general, see Clive Maxfield's article, An introduction to different rounding algorithms.
|Home||Index of tips||Top|
This is a cached tutorial, reproduced with permission.
Have your say - comment on this article.
What did you think of 'Rounding in Access'?
No comments yet.
Why not be the first to comment on this article?!
Have your say...