Степени двойки

Материал из Posmotre.li
Перейти к: навигация, поиск
Склифосовский.pngВкратце
От 0 до 255. Или от −128 до 127.
« Чем отличается начинающий программист от законченного? Начинающий думает, что в килобайте 1000 байт, законченный — что в километре 1024 метра »
— Народное творчество
« В мире есть два вида чисел: ноль, и те, которые приводят к ошибке переполнения »
— Автор неизвестен

Компьютеры работают с числами. Причём в подавляющем большинстве случаев число разрядов в этих числах ограничено[1]. Что будет, если место есть под три цифры, а нам надо записать число 9 999? Правильно, одна девятка куда-то потеряется и получится 999. Что будет, если мы к этому 999 прибавим единичку? Получится 1000, но первая цифра опять куда-то потеряется и 1000 превратится в 000. Это собственно суть арифметического переполнения и есть. Для геймера это означает, что невероятно раскачанный персонаж с 999 пунктами здоровья внезапно помрёт, получив еще один пунктик здоровья сверху (999+1=0).

Вернемся теперь к заглавной теме. В отличие от людей, компьютер работает в двоичной системе счисления. То есть знает только две цифры — ноль и единицу. Попытки сделать десятичные или троичные компьютеры предпринимались, но как-то не прижилось. Поэтому описанное в абзаце выше переполнение происходит не когда число достигает степени десятки, а когда оно достигает степени двойки. И вместо 999+1=0 выходит 255+1=0. Пока все понятно и далекому от компьютеров человеку. Однако давайте подумаем, что будет, если теперь вычесть из нуля единицу? Говорите, будет −1? Нет, компьютер у нас знает ноль, знает единицу, а этот ваш минус не знает. Поэтому мы договоримся, что если первая двоичная цифра — ноль, значит число положительное (0 001 = 1). А если единица — отрицательное (1 001 = −1)[2]. Тут жадные программисты и говорят: не хотим мы целый разряд под знак тратить, дайте нам беззнаковые числа. Окей, дают им беззнаковые числа. Но теперь при вычитании из нуля единицы опять фигня получается — ноль превращается в 255! Ну или еще какое-то значение 2n−1. Тут внимательный читатель может возразить: постойте, постойте, даже калькулятор в подобных ситуациях просто выдаст ошибку. Правильно, процессор тоже в таких ситуациях вывешивает флажок (даже два) «ребят, тут фигня какая-то вышла». Но так уж повелось, что в целях повышения быстродействия никто на этот флажок не смотрит.

Стоит отметить, что всё вышесказанное актуально в основном для старых игр. Компьютеры тогда были 8–16-разрядными (с пониманием чисел больше 65535 проблемы), памяти мало (мегабайт оперативки — это круто, да и зачем — «640 килобайт хватит всем»), а у программистов было модно экономить на всем (да зачем тратить на число целых два байта? И одного хватит). Теперь компьютеры стали 64-битовыми (числа переполняются в районе 9 223 372 036 854 775 807), памяти — гигабайты, так что вышеописанные проблемы отошли в прошлое.

Примеры[править]

Как ограничение[править]

  • Традиционная плитка — 16×16 пикселей.
  • WarCraft II, StarCraft — ограничение на ману в 255 единиц.
    • В StarCraft обработано: энергии (космооперной маны) может быть либо 200 (без апгрейда), либо 250 (с апгрейдом и у героев), либо 180 (у брудлингов, которые теряют 1 единицу в секунду и живут 3 минуты с обоснованием, что без энергии жить не могут).
    • В эпичном редакторе карт Warcraft II на лимите в 255 завязано практически все: 25500 — максимум НР любого юнита, 2550 — максимум его цены (в каждом ресурсе), 255 — максимум его маны, защиты, базового и проникающего урона.
      • Вот только максимум разведки все-таки 9, максимум дальнобойности 15, а некоторые апгрейды стоят 3000.
  • В играх серии Heroes of Might and Magic у одного игрока не может быть больше 8 героев.
    • Точнее, героев может быть сколько угодно, не может быть больше восьми армий в поле. По городским гарнизонам, а в четвёртой части и в охране шахт, можно иметь сколько угодно героев.
    • В четвёртой части также существует предел юнитов в 1 отряде — 32767.
  • The Elder Scrolls IV: Oblivion — ограничение на уровень характеристики или навыка в 255 единиц. Лучше всего заметно на скорости бега и высоте прыжка. Впрочем, эти значения не получить без читов.
  • В различных цветовых моделях значения каналов от 0 до 255.
  • Размеры текстур: 256×256, 512×512, 1024×1024 и т. д. Многие игры позволяют расширить текстуру вдвое или вчетверо (на этом основаны HD Pack’и старых игр). Но сделать её, например, 1000×1000 не даст уже видеоплата новые расширения команд графического процессора (уже несколько лет как) позволяют подобное сделать, однако, делать так всё же не стоит — хоть видеокарты и поддерживают текстуры, не являющиеся степенями двойки, на практике такие текстуры заметно тормозят. Потому такие картинки популярны в демках «вау! посмотри, как мы можем!», но практически не встречаются в реальных играх.
  • В Fallout 4 отсутствует ограничение на получение уровня, однако игра не может переварить значения уровня выше 65535, и вылетает.
  • Mount & Blade — В Истории Героя в отряд персонажа могло входить только 32 вида юнитов, что обламывало любителей модов, которые хотели собрать легион из бессмертных NPC.

Как ошибка[править]

  • X-COM: UFO Defense — как только сила или запас ходов солдата превысит 255, он становится немощным. В более поздних версиях на то и другое поставили предел 80.
  • Civilization — сумасшедший Ганди. Уровень агрессивности в игре определялся однобайтовой неотрицательной переменной, у самых агрессивных правителей она была равна 10, у Ганди — единице. Открытие демократии снижало агрессивность на два, в результате чего у Ганди получался «ноль», вместо какового в данном случае присваивалось максимально возможное значение переменной, то есть 255. Это превращало данного пацифиста в кровожадного маньяка, который сразу устраивал тотальную ядерную войну. Данный баг так полюбился игрокам, что в более поздних играх стали добавлять осознанную отсылку к нему, наделяя Ганди повышенной склонностью к использованию ядерного оружия.
  • Pirates! — одна из самых первых культовых игр была, тем не менее, чрезвычайно глючной именно из-за неотслеживаемых переполнений.
  • Hearthstone — Если атака или здоровье существа превысит максимальное значение — существо умрет.
  • Panzer General первых версий: в режиме игры по переписке один из противников мог оказаться с отрицательным значением престижа… Не-а, его престиж оказывался больше 65500!

Как багофича[править]

  • Pokemon — начиная с первого поколения, где покемонов было всего 151, а слотов для их размещения, соответственно, немного больше. В итоге неиспользуемые были просто забиты MissingNo. и прочей забагованной ерундой, которая, однако, многим игрокам сама по себе пришлась по нраву. Так и повелось с тех пор.

Отрицательные значения[править]

Как было замечено, сейчас проблемы с памятью компьютеров исчезли, и восприятие отрицательных чисел пришло в норму. Но это породило другой математический глюк, достаточно редкий и очень забавный, а зачастую полезный. Суть в том, что от пробивания значением потолка или дна образуется не максимально, а минимально противоположный результат, он тем больше, чем сильнее пробитие: допустим, у нас атака наносит урон в 10 единиц. Но вот на её обладателя повесили пачку дебаффов урона суммарной силой 11. При использовании такой атаки игра вычитает из десяти одиннадцать, а потом получившееся значение вычитает из здоровья цели. И если программист что-то не досмотрел и не сделал ограничения и проверки, оно оказывается отрицательным. В результате игра, повинуясь написанной формуле и законам математики, вычитает из вражеского хп −1, и урон превращается в лечение.

Примеры[править]

  • S.T.A.L.K.E.R. самый первый — если набрать редких артефактов на 30 % сопротивления одному типу аномалий так, что оно перевалит за сотню, нахождение в этой аномалии начнёт вас лечить и чинить снаряжение. Пофикшено.
  • DotA 2 — тот самый случай с уроном. Достигается сложно и, скорее всего, пофикшен.
  • Адский эксплойт в ранних версиях Silent Storm: прокачкой рукопашного боя затраты очков действия на него уменьшаются до нуля, а потом удары начинают давать очки действия, позволяя зачистить карту без передачи хода противнику. Причём бить можно было вообще всё подряд.
  • Warframe — сабж заботливо обыгран, и крит шанс при желании разгоняется за 300 %, а урон многократно критических попаданий рассчитывается по специальной формуле. Но вот появились моды разлома, которые могут давать бонусы и штрафы практически к любому параметру. В том числе и множителю критического урона, который может от этого опускаться ниже единицы, и таким образом урон от крита становится меньше обычного.
  • Minecraft — как фича. У блоков есть прочность, которая уменьшается в процессе разбивания, и блок ломается по достижении нуля. А у коренной породы, ограничивающей мир снизу, значение отрицательное, соответственно, оно от вычитания не только не достигнет нуля, но и будет расти.

Примечания[править]

  1. Бывает еще «длинная арифметика», но она тормозная. Поэтому, вы вряд ли встретите ее за пределами математических программ, которым вот кровь из носа, а нужно пересчитать все атомы во Вселенной.
  2. Обычно используется более хитрый «дополнительный код», но суть примерно та же, так что замнем для ясности.