Видеокурсы по изучению языка программирования Swift. Подробнее

Операторы переполнения

Если вы нашли опечатку в тексте, выделите ее и нажмите CTRL + ENTER.

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

Для примера, целочисленный тип Int16 может держать любое знаковое целое число от -32768 и до 32767. Если вы попытаетесь установить число (константу или переменную) типа Int16 за границами приведенного диапазона, то вы получите ошибку:

var potentialOverflow = Int16.max
// potentialOverflow равняется 32767, что является самым большим значением, которое может содержаться в Int16
potentialOverflow += 1
// это вызовет ошибку

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

Однако, когда вы специально хотите осуществить условие переполнения, чтобы обрезать количество доступных битов, то вы можете получить именно такое поведение, вместо отчета об ошибке переполнения. Swift предоставляет три арифметических оператора переполнения, которые помогают перейти к поведению переполнения для целочисленных вычислений. Все эти операторы начинаются с символа амперсанда (&):

  • Оператор переполнения с добавлением (&+)
  • Оператор переполнения с вычитанием (&-)
  • Оператор переполнения с умножением (&*)

Переполнение значения

Ниже приведен пример того, что случится, когда беззнаковое значение позволяет переполнить себя, с использованием оператора (&+):

var willOverflow = UInt8.max
// willOverflow равняется 255, что является наибольшим числом, которое может держать UInt
willOverflow = willOverflow &+ 1
// willOverflow теперь равно 0

Переменная willOverflow инициализирована самым большим числом, которое может держать UInt8 (255 или в бинарном виде 11111111). Затем оно увеличивается на 1 при помощи оператора переполнения (&+). Это выталкивает бинарное представление размерности UInt8, вызывая тем самым переполнение границ, что отображено на диаграмме ниже. Значение, которое остается в пределах границ значения типа UInt8 после переполнения и добавления выглядит как 00000000, или попросту 0 в десятичной форме:

Числа так же могут быть слишком маленькими, чтобы соответствовать определенному типу. Ниже приведен пример с использованием оператора недополнения (&-)

var unsignedOverflow = UInt8.min
// unsignedOverflow равен 0, что является наименьшим возможным значением UInt8
unsignedOverflow = unsignedOverflow &- 1
// unsignedOverflow теперь равно 255

Самое маленькое значение, которое может держать UInt8 равно 0 (что отображается как 00000000 в восьмибитной бинарной форме). Если вы из 00000000 вычтите 1, с использованием оператора недополнения, число переполнится в обратную сторону к 11111111, или к 255 в десятичной форме:

Аналогичное недополнение случается и с знаковыми целыми числами. Все вычитание для знаковых целых чисел проводится как прямое бинарное вычитание с учетом знакового бита, в качестве части вычитаемых чисел, что описано в Операторы побитового левого и правого сдвига.

var signedUnderflow = Int8.min
// signedUnderflow равняется -128, что является самым маленьким числом, которое может держать Int8
signedUnderflow = signedUnderflow &- 1
// signedUnderflow теперь равняется 127

Самым маленьким числом, которое может держать Int8, является –128, что записывается в бинарной форме как 10000000. Вычитая 1 из этого бинарного числа с оператором недополнения, дает нам значение 01111111, что переключает наш знаковый бит на противоположный и дает нам положительное 127, что является самым большим числом, которое может держать Int8:

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

 

Swift: 
4.0