Тест самоперевірки · Python · тема 04

Числа й арифметика

Обери відповідь — і одразу побачиш пояснення. Помилитись тут корисніше, ніж на іспиті.

← до лекції
Відповіді0 / 8   правильних: 0
Питання 1 / 8

Скільки буде -7 // 2 у Python і чому саме так?

Чому так. Оператор // округлює вниз, до мінус нескінченності: −3.5 йде до −4, а не до −3. Це не примха: тільки так виконується рівність b*(a//b) + a%b == a з остачею, що має знак дільника, тому -7 % 2 дає 1. Варіант «−3» — це поведінка C і Java, де остача виходить відʼємною (−1).
Питання 2 / 8

0.1 + 0.2 дає 0.30000000000000004. Що саме там сталося?

Чому так. Округлень тут три: 0.1 і 0.2 зберігаються трохи більшими за справжні, їхню точну суму процесор округлює до найближчого представного числа, а літерал 0.3 округлився в інший бік — трохи вниз. Саме додавання виконується точно; і JavaScript, і C, і Java дадуть той самий результат — це властивість формату IEEE 754, а не мови.
Питання 3 / 8

Обчислена величина має бути нулем, але math.isclose(x, 0.0) завжди повертає False. У чому причина?

Чому так. math.isclose за замовчуванням дає відносний допуск: різниця порівнюється з rel_tol × max(|a|,|b|). Якщо одне з чисел — нуль, а друге крихітне, то й поріг виходить крихітним, і будь-яка різниця його перевищує. Правильно так: math.isclose(x, 0.0, abs_tol=1e-9). Зменшення rel_tol тільки погіршить ситуацію.
Питання 4 / 8

round(2.675, 2) дає 2.67, а не 2.68. Чому?

Чому так. Це навіть не половинний випадок: найближчий до 2.675 двійковий дріб дорівнює 2.67499999999999982236…, тобто трохи менший. Тому найближчі два знаки — це 2.67, і round() спрацював абсолютно правильно над тим числом, яке йому дали. Банківське округлення тут ні до чого — воно вмикається лише на точних половинках, як у round(2.5).
Питання 5 / 8

2 ** 1000 обчислюється миттєво, а 2.0 ** 1024 кидає OverflowError. Чому такий контраст?

Чому так. У 64-бітному float під поле порядку відведено рівно 11 бітів, тому найбільший степінь двійки трохи менший за 21024 — далі лише inf. int у CPython — це масив «цифр» по 30 бітів: щоб зберегти більше число, додається ще одна цифра. Тому 2 ** 1024 — звичайне ціле на 309 десяткових цифр і 152 байти памʼяті.
Питання 6 / 8

math.fsum([0.1] * 3) — чи дорівнює це рівно 0.3?

Чому так. math.fsum підсумовує точно й округлює один раз у кінці — але підсумовує він ті числа, які йому дали. А кожне збережене 0.1 уже трохи більше за одну десяту, тому їхня точна сума більша за 0.3, і результат — 0.30000000000000004. Жоден алгоритм підсумовування не може виправити похибку, яка сидить у самих доданках; тут рятує лише Decimal.
Питання 7 / 8

Ти рахуєш гроші й пишеш Decimal(0.1) + Decimal(0.2). Що вийде?

Чому так. Decimal(0.1) чесно копіює точне значення переданого float — усі 55 цифр 0.1000000000000000055511…. Decimal рятує тільки тоді, коли створений із рядка: Decimal(ʼ0.1ʼ) + Decimal(ʼ0.2ʼ) дає рівно Decimal(ʼ0.3ʼ). Тому правило просте: у гроші число потрапляє з рядка, ніколи через float.
Питання 8 / 8

int(-3.9) дає -3, а -3.9 // 1 дає -4.0. Чому на тому самому числі різні відповіді?

Чому так. int() завжди рухається до нуля: −3.9 → −3, 3.9 → 3. // завжди рухається вниз, до мінус нескінченності: −3.9 → −4. На додатних числах ці напрямки збігаються, тому різницю видно лише на відʼємних. Якщо потрібне саме округлення до найближчого — бери round().