Microsoft Access: Советы для случайных пользователей

Автор Allen Browne, декабрь 2007.  Обновлено: август 2008.

Оригинал Rounding in Access

Перевел с английского Александр Артамонов


Округление в Аксессе

Для округления чисел в Access 2000 и более поздних версих есть встроенная функция Round().
Для более ранних версий используйте вот эту пользовательскую функцию округления Кена Гетца.

Встроенная функция

Используйте функцию Round() в источнике данных текстового поля или в вычисляемом поле запроса.

Скажем, у вас есть такое выражение в строке "Поле" в конструкторе запросов:
    Налог: [Стоимость] * [СтавкаНалога]
Чтобы округлить до ближайшей копейки, используйте:
    Налог: Round([Стоимость] * [СтавкаНалога], 2)

Округление вниз

Чтобы округлить все дробные цифры до ближайшего целого вниз, используйте Int():
    Int([МоеПоле])

Все эти числа будут округлены вниз до 2: 2,1, 2,5, 2,8, and 2,99.

Чтобы округлить вниз до ближайшей копейки (напр. 10,2199 руб становятся 10,21 руб), умножьте на 100, округлите, и затем разделите на 100:
    Int(100 * [МоеПоле]) / 100

Заметьте, что получается при округлении вниз отрицательных величин: Int(-2.1) дает -3, так как это и есть целое число снизу. Чтобы округлять по направлению к нулю, используйте Fix() вместо Int():
    Fix(100 * [МоеПоле]) / 100

Округление вверх

Чтобы округлить вверх к ближайшему большему целому, воспользуйтесь способом, которым Int() округляет отрицательные числа:
    - Int( - [МоеПоле])

Как показано выше, Int(-2.1) округляет вниз до -3. Поэтому такое выражение округляет 2,1 до to 3.

Чтобы округлить вверх до ближайшей копейки, умножьте на -100, округлите, и разделите на -100:
    Int(-100 * [МоеПоле]) / -100

Округлить до ближайших 5 копеек

Чтобы округлить до ближайших 5 копеек, умножьте число на 20, округлите его, и разделите на 20:
    Round(20 * [МоеПоле], 0) / 20

Подобным образом, чтобы округлить до ближайшего четвертака, умножьте на 4, округлите, и разделите на 4:
    Round(4 * [МоеПоле], 0) / 4

Округлить до 1000 руб.

Функция Round() в Excel принимает отрицательные числа в качестве количества мест от запятой, напр. Round(123456, -3) округляет до 1000. К сожалению, аксессовская функция этого не поддерживает.

Чтобы округлить до ближайших 1000 руб., разделите на 1000, округлите, и умножьте на 1000. Пример:
    1000 * Round([Стоимость] / 1000, 0)

Чтобы округлить до 1000 руб. вниз, разделите на 1000, получите целое число и умножьте на 1000. Пример:
    1000 * Int([Стоимость] / 1000)

Чтобы округлить до верхней 1000 руб., разделите на 1000 и умножьте на -1 перед получением целой величины. Пример:
    -1000 * Int( [Стоимость] / -1000)

Чтобы округлить в сторону нуля, используйте Fix() вместо Int().

Альтернативно, пользовательская функция Кена Гетца ведет себя в точности как упомнутая экселевская функция.

Зачем округлять?

Существует свойство Число десятичнызх знаков для полей в таблице/запросе и для текстбоксов в форме/отчете. Это свойство влияет только на то, как поле отображается, а не на то, как оно хранится. Число выглядит округленным, но при сложении ряда чисел (напр. в примечании отчета), итог может "не биться".

Округляйте такое поле, когда вы производите вычисление и итоговая сумма сойдется.

Это также относится и к денежным полям. Аксесс отображает денежные поля округленными до ближайшей копейки, но хранит их значение до сотой доли копейки (4 знака после запятой.)

Банковское округление

Функция Round() в Аксессе использует "банковское округление". Когда последней значащей цифрой оказывается 5, она округляет до ближайшего четной цифры. Так, 0,125 округляется до 0,12 (2 четно), в то время как 0,135 округляется до 0,14 (4 четно.)

Главный смысл здесь - равенство: 1,2,3, и 4 округляются вниз. 6,7,8, и 9 - вверх. 0 не требует округления. Так, если 5 все время округлять вверх, вы получите "сдвинутые" результаты - 4 цифры округляются вниз, и 5 вверх. Чтобы избежать этого, "третий лишний" (5) округляется в соответствии с предыдущей цифрой, что сглаживает неравенство.

Если вы не хотите использовать банковское округление, возьмите функцию Кена Гетца (ссылка вверху.)

Ошибки плавающей запятой

Дробные величины компьютер обычно трактует как числа с плавающей точкой. Аксессовские поля типов Двойной точности (Double) или Одинарной точности (Single) относятся к такому типу. Тип "Двойной точности" дает около 15 знаков точности, сингл - 8 знаков (подобно ручному калькулятору).

Но эти числа являются приблизительными. Точно так же, как 1/3 требует бесконечного количества знаков в десятичной системе, большинство чисел с плавающей запятой не могут быть представлены точно в двоичной системе. Википедия объясняет проблему точности, с которой вы сталкиваетесь, оперируя числами с плавающей запятой.

Резюме заключается в том, что крайние цифры могут не округлиться ожидаемым вами образом,благодаря тому факту, что действительные значения и отображаемые не совпадают. Это становится особенно заметно при проверке банковского округления.

Один из способов избежать подобных проблем - использовать числа с фиксированной запятой или мастшабированные числа.Тип данных "Денежный" в Аксессе является типом с фиксированной запятой: он всегда хранит 4 десятичных знака.

Например, откройте окно Immediate Window (Ctrl+G) и введите:
    ? Round(CCur(.545),2), Round(CDbl(.545),2)
Денежный тип (первый) возвращает 0,54, тогда как Двойной точности - 0,55. Денежный округляет корректно (к четной цифре 4); тип с плавающей запятой (Двойной точности) некорректно. Подобным образом, если вы попробуете 8,995, Денежный корректно округлит вверх (к четной цифре 0), в то время как тип Двойной точности округлит вниз (неверно.)

Денежный тип справляется только с 4 десятичными знаками. Используйте масштабируемый тип Действительный (Decimal), если вам нужно больше знаков после запятой.

Округление дат и времени

Обратите внимание, что тип Дата/Время в Аксессе является особым видом типа с плавающей запятой, в котором дробная часть обозначает время дня. Следовательно, поля типа Дата/Время с компонентой времени также подвержены ошибкам округления.

Функция ниже округляет дату/время до указанного количества секунд. Например, чтобы округлить до ближайшего получаса (30 * 60 seconds), используйте:
    =RoundTime([МоеПолеДатаВремя], 1800)

Public Function RoundTime(varTime As Variant, Optional ByVal lngSeconds As Long = 900&) As Variant
'Цель: Округлить величину дата/время до ближайшего количества указанных секунд
'Аргументы: varTime = величина дата/время
' lngSeconds = количество секунд, до которых требуется округлить.
' напр. 60 для ближайшей минуты,
' 600 для ближайших 10 минут,
' 3600 для ближайшего часа,
' 86400 до следующего дня.
'Возвращает: Округленное значение дата/время либо Null, если не было входного аргумента дата/время.
'Примечание: lngSeconds должно быть между 1 и 86400.
' Округляет по умолчанию до ближайших 15 minutes.

Dim lngSecondsOffset As Long
RoundTime = Null 'Инициализируем возвращаемый 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

 

Заключение

Для более детального технического объяснения теории округления в целом, см. статью Клайва Максфилда (Clive Maxfield) An introduction to different rounding algorithms.

Конструктор сайтов - uCoz