This page is hosted for free by zzz.com.ua, if you are owner of this page, you can remove this message and gain access to many additional features by upgrading your hosting to PRO or VIP for just 32.50 UAH.
Do you want to support owner of this site? Click here and donate to his account some amount, he will be able to use it to pay for any of our services, including removing this ad.

Округлення в третьому Python – заплутана математика

Друк

Округлення, як відомо, це  математична операція, яка полягає в заміні числа α наближеним числом α1 із меншою кількістю значущих цифр. Число α1 вибирають так, щоб похибка округлення була якомога меншою.

 

У різних галузях застосовують різні методи округлення.

 

На уроках математики в школі традиційно округлюють методом «Округлення до найближчого цілого» (англ. rounding) — це найбільш часто вживаний метод округлення, при якому число округлюється до цілого, модуль різниці з яким у цього числа мінімальний. У загальному випадку, коли число в десятковій системі округляють до N-ого знаку, правило може бути сформульовано таким чином:

якщо N+1 знак < 5, тоді N-ий знак зберігають, а N+1 та всі наступні обнуляють;

якщо N+1 знак ≥ 5, тоді N-ий знак збільшують на одиницю, а N+1 та всі наступні обнуляють;

Наприклад: 11,9 → 12; −0,9 → −1; −1,1 → −1; 2,5 → 3.

 

Давайте напишемо ще кілька прикладів на даний тип округлення:

Округлюємо до цілого:

1,5 → 2

2,5 → 3

3,5 → 4

4,5 → 5

5,5 → 6

6,5 → 7

 

Такий метод округлення використовує Python версії 2 і старі програмні компілятори, наприклад Turbo Pascal.

 

Але це не єдиний метод округлення. Відповідно до стандарту IEEE 754 (і 1985, і 2008 року),  основним для комп'ютерних обчислень є інший метод. Він зветься округленням до найближчого парного, банківським, статистичним, данським, Гаусовим округленням. Вважається, що банківське округлення дозволяє зменшити похибки при роботі з великими масивами даних. Подробиці можна дізнатися, завітавши на кілька років на правильну спеціальність гарного університету. Даний метод на сьогодні популярний:  наприклад, .NET Math.Round  так робить по замовчуванню,  цей метод використовує для функції стандартного округлення round() PascalABC.Net  і Python 3.

 

Синтаксично округлення в Python 3 здійснюється функцією round(number, ndigits), де number – число що округлюється, а ndigits - кількість знаків після коми. Наприклад:

 

>>>round(2.137, 2)

2.14

>>>round(1.5)

2

 

Ось результат такого округлення:

1,5 → 2

2,5 → 2

3,5 → 4

4,5 → 4

5,5 → 6

6,5 → 6

 

Саме так округлює функція round() в Python 3.

 

Але є і великі підводні камені, пов’язані з представленням в пам’яті комп’ютера дійсних чисел. Ось приклад:

 

>>>round(2.15, 1)

 

З точки зору округлення до найближчого парного, результат повинен бути 2.2

Python 3 вважає інакше:

 

>>>round(2.15, 1)

2.1

 

Це пов’язано з тим, як представлено число 2.15 в машинному поданні, давайте переглянемо, як воно виглядає для, наприклад, 30 знаків після коми:

 

>>> '%0.30f' % 2.15

'2.149999999999999911182158029987'

 

Тепер все зрозуміло, в такому випадку логіка округлення  Python 3 цілком зрозуміла.

 

Але сюрпризи при округленні дійсних чисел можуть з’являтися цілком несподівано, наприклад:

 

>>> round(2.15, 1)

2.1

>>> round(2.1500000000000001, 1)

2.1

>>> round(2.150000000000001, 1)

2.2

 

Як бачимо, камінців вистачає. Але round() – не єдина функція округлення.

 

В Python 3, в модулі math реалізовано ще декілька методів округлення:

 

math.ceil(x) – округлення до найближчого більшого числа

math.floor(x) - округлення до найближчого меншого числа

math.trunc(x) - усікає значення X до цілого.

 

Ось приклади, що ілюструють роботу даних функцій:

 

>>> import math

>>> math.ceil(1.4)

2

>>> math.floor(1.4)

1

>>> math.trunc(1.4)

1

>>> math.trunc(1.9)

1

>>> math.floor(-1.9)

-2

>>> math.trunc(-1.9)

-1

 

 

Усікти значення до цілого можна і без використання модуля math:

 

>>> int(1.1)

1

>>> int(1.9)

1

>>> int(-1.1)

-1

>>> int(-1.9)

-1

 

А для естетів, перфекціоністів, тих, хто хоче забезпечити абсолютну точність, контролювати стратегію округлення і системно керувати золотою рибкою, Python 3 має модуль decimal

 

Цей неймовірний інструмент має  аж вісім варіантів округлення:

 

ROUND_CEILING - Округлення в сторону позитивної нескінченності. Наприклад, число 2.52 буде округлено до 2.6, а число -2.58 до -2.5

 

ROUND_DOWN - Округлення в сторону нуля. Наприклад, число 2.58 буде округлено до 2.5, а число -2.58 - до -2.5

 

ROUND_FLOOR - Округлення в бік негативної нескінченності. Наприклад, число 2.52 буде округлено до 2.5, а число -2.58 до -2.6

 

ROUND_HALF_DOWN - Округлення в сторону від нуля, якщо частина, що округлюється,  більше половини останнього значущого розряду, в іншому випадку округлення буде виконано в сторону нуля. Наприклад, число 2.58 буде округлено до 2.6, число 2.55 буде округлено до 2.5, а число -2.58 до -2.6

 

ROUND_HALF_EVEN - Те ж, що і ROUND_HALF_DOWN, тільки якщо частина, що округлюється дорівнює точно половині останнього значущого розряду, результат округлюється вниз, якщо попередня цифра парна, і вгору - якщо попередня цифра непарна. Наприклад, число 2.65 буде округлено до 2.6, число 2.55 також буде округлено до 2.6

 

ROUND_HALF_UP - Те ж, що і ROUND_HALF_DOWN, тільки якщо частина, що округлюється, дорівнює точно половині останнього значущого розряду, результат округлюється в бік від нуля. Наприклад, число 2.55 буде округлено до 2.6, а число -2.55 до -2.6

 

ROUND_UP - Округлення в бік від нуля. Наприклад, число 2.52 буде округлено до 2.6, а число -2.52 - до -2.6

 

ROUND_05UP - Округлення в бік від нуля, якщо останній значущий розряд містить цифру 0 або 5, в іншому випадку округлення виконується в сторону нуля. Наприклад, число 2.54 буде округлено до 2.6, число 2.64 також буде округлено до 2.6

 

Звичайно, всі ці варіанти з’явилися в decimal не просто так  - вони мають цілком прикладний сенс. З таким інструментарієм можна реалізувати багато чого, в тому числі і популярне шкільне округлення методом «Округлення до найближчого цілого»:

 

import decimal as decimal

print(decimal.Decimal('2.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP))

print(decimal.Decimal('3.5').quantize(decimal.Decimal('1'), rounding=decimal.ROUND_HALF_UP))

 

out:

3

4

 

Ну і можна, звичайно, написати і власну функцію округлення, якщо на то є причини. В будь-якому варіанті тема округлення дійсних чисел в Python 3 має чимало непростих аспектів. І програмістам необхідно уважно враховувати дані особливості як на етапі проектування інформаційних систем, так і при розробці стратегій їх тестування.