27

Ответ на пост «Точность - вежливость королей!»

Серия Доступно об АйТи

Как программист, попробую рассказать некомпьютерному народу про парочку компьютерных глюков и их природу. Эти глюки (кроме тех, что связаны с датами) универсальны для всех языков программирования, потому что завязаны на устройстве наших процессоров.

Глюки целых чисел

Минимальная единица компьютерной информации — бит. Это одна цифра двоичной системы счисления: 0 или 1.

Процессор одним махом работает не с одним битом, а с 8-ю. Или 16-ю. Или 32-мя. Или 64-мя — так называемая разрядность процессора, или длина машинного слова. Если вы такие олдфаги, что вспоминаете 8- и 16-битные приставки — всё верно, это разрядность их процессоров.

8 битов — это байт. Позволяет записать числа от 0 до 2⁸−1, то есть от 0 до 255. Удобная цифра: позволяет записать 26·2=52 буквы английского алфавита, 33·2=66 букв русского, и на цифры со спецсимволами хватит.

При этом компьютер работает так: 254+1=255, а 255+1=0. Такой механизм сложения позволяет теми же операциями «сложить» и «вычесть» работать и с отрицательными числами в таком виде: 255=−1, 254=−2, и т.д. до 128=−128 (а также с числами во много-много машинных слов). Какое число хранится в памяти — со знаком или нет — компьютер никак не запоминает, это работа программиста и компилятора (программы, которая переводит исходный текст на языке программирования в машинный код).

Пример. В первой версии компьютерной игры Civilization у всех правителей был такой параметр, как воинственность. У всяких там Сталиных с Монтезумами она была 9 или 10, а у махатмы Ганди 1. При открытии демократии воинственность (которая записывалась однобайтовым числом без знака) падает на 2. В такой вот арифметике 1−2=255. Таким образом, в конце игры благовидный старичок начинал громить всех ядерными бомбами. «Сумасшедший Ганди» так полюбился публике, что в том или ином виде существовал во всех последующих «цивилизациях» — например, слетал с катушек, если его втянут в войну.

Пример 2. В первых версиях игры UFO: Enemy Unknown приходилось выгонять бывалых солдат, потому что… сила превышала 255, превращалась в 0, и боец становился немощным.

Запишем эти цифры и для других форматов компьютерных целых. И не говорите, что не встречали их в каких-то компьютерных глюках!

Эти цифры могли получиться тремя методами.

• В результате арифметического переполнения без проверки границ. Я уже говорил, что для одного байта 0−1=255. А если байтов четыре (что в наши дни встречается чаще всего) — получится 0−1=4,2 млрд.

• В результате арифметического переполнения с проверкой границ, если что-то страшно заглючило (или программе скормили нехорошие данные). Случай крайне редкий.

• Иногда по договорённости крайние числа означают «дыру» в данных — то есть «нет числа», «не найдено» и подобное. Разумеется, программист должен постоянно проверять такие «числа с дырами» — а если не проверит, компьютер выведет те же 4,2 миллиарда.

Глюки дат

Если даты нет, вы часто видите дату 1 января 1970 года или 30/31 декабря 1899 года. Та и другая — ноль в двух разных системах отсчёта.

Время операционной системы Unix отсчитывается в секундах, при этом нулём считается 1 января 1970 года. Добавляем к ним те самые 2,1 млрд секунд — и получим 18 января 2038 года, когда на 32-битных машинах время Unix уйдёт в минус.

В электронной таблице Lotus 1-2-3 даты считаются количеством дней, прошедших с 31 декабря 1899 года, с ошибкой, что 1900 год високосный (на самом деле нет!) Этот формат перебрался в электронную таблицу Excel и систему программирования Delphi, причём глюк 1900 года они разрешили по-разному: Excel заявил, что 1900 год у него так и будет високосным, а Delphi начал отсчёт с 30 декабря 1899 года.

Также распространён отсчёт с 31 декабря 1899 года без всяких глюков (то есть цифра на единичку меньше, чем в формате Lotus 1-2-3). Этот день — воскресенье, что упрощает работу с днями недели.

Откуда взялась проблема 2000, я толком и не знаю, и видел её лишь однажды: в том же Lotus 1-2-3 вместо 2000 года писался 19100, причём не везде, а выборочно. Смею предположить, что в каких-то очень старых машинах две цифры года записывались двоично-десятичным кодом и потому при переходе через столетие сбрасывались в 00. (Двоично-десятичный формат действительно широко используется в устройствах без микропроцессоров, чтобы упростить вывод на индикацию.)

Глюки дробных чисел

Форматы компьютерных дробных писались для удобства вычислителей (это люди, занимающиеся организацией вычислений на компьютере) и совершенно непригодны для хранения денежных сумм до копейки. (Уважающие себя бухгалтерские программы записывают денежные суммы в специальных форматах без потерь, простейший — 12 р. 34 коп. = 1234 коп.)

Из школы мы знаем, что любое число, кроме нуля, можно записать в стандартном виде: 162=1,62·10². Компьютерные дробные — это такой же стандартный вид, только в двоичной системе счисления: 5=1,01₂·2². (1,01 в двоичной — это наши 1,25.)

Кто помнит из школы, какие обыкновенные дроби представимы в виде конечной десятичной? Ответ: знаменатель должен иметь множителями только 2 и 5. А в виде двоичной дроби — знаменатель должен быть степенью двойки. Таким образом, самые простые числа вроде 0,1 представимы в виде компьютерных дробных только приблизительно.

Отсюда 0,1+0,2≠0,3. И выглядит это примерно так: 0,1≈26/256=1,1010₂·2⁻⁴, 0,2≈26/128=1,1010₂·2⁻³ — а 0,1+0,2=1,00111₂·2⁻² — округлив, получим 1,0100₂·2⁻²=20/64, в то время как 0,3≈19/64. Компьютеры, правда, поточнее будут и для 0,1 знаменатель 65 млн или даже больше — но принцип поняли.

Хорошие функции преобразования дробного в строку это учитывают и не пишут лишних цифр, но иногда проскакивает.

А ещё среди компьютерных дробных есть два специальных числа: Inf («машинная бесконечность») и NaN («не число»). Их получить проще простого: Inf=1/0, NaN=0/0 (если делить их как дробные числа; на целый ноль делить нельзя). Они также широко используются в качестве особых значений («нет данных», «не найдено», «не установлено»).

Показать полностью 6
Отличная работа, все прочитано!

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества

Недвижимость и ремонт

Теги

Популярные авторы

Сообщества