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

Этот пост будет охватывать биты, байты, целые числа и математику.

Биты

В вычислениях все двоично. В Swift префикс0b представляет начало байтового литерала. И все числа (0 или 1) впоследствии представляют биты в байте как little endian.

0b00000000

Этот байт равен 0, поскольку все биты равны 0.

Порядок байтов

Биты отсортированы от большего к меньшему (прямой порядок байтов) или от маленького к большему (прямой порядок байтов). Endian: последний бит в списке - наименьшее или наибольшее число в списке.

0b10100000

Следующее число с прямым порядком байтов - 128 + 0 + 32 + 0 + 0 + 0 + 0 + 0, поэтому 150

Однако при обратном порядке байтов это 1 + 0 + 4 + 0 + 0 + 0 + 0 + 0, то есть 5.

Самый младший бит представляет 1, и каждый шаг умножается на 2.

Порядок байтов с прямым порядком байтов:

1, 2, 4, 8, 16, 32, 64, 128

Или с прямым порядком байтов:

128, 64, 32, 16, 8, 4, 2, 1

Литералы

Обычно при записи целого числа вы пишете десятичное число.

0b00001010 - двоичное число, представляющее 10. Это не особенно полезно при написании человеческого кода. Но иногда при работе с кодом действительно низкого уровня необходимо понимать и / или писать.

let ten = 10
let alsoTen = 0b00001010

Двоичная - это система, в которой каждая степень двойки используется как дополнительное число. Мы называем это «базой 2». Точно так же мы используем десятичную дробь с основанием 10.

Ноль - это 0, один - 1. Но два 10.

В десятичной системе (системе, использующей степень 10) это работает точно так же.

Zewo - это 0, один - 1. Но два 2, так как ниже десяти. Это продолжается до девяти (9). Однако когда мы набираем десять, мы устанавливаем цифру 0 и добавляем 1.

Таким образом, 10 в десятичной форме равно (10¹) + 0), или 10 в степени 1 плюс 0.

Когда мы дойдем до 100 в десятичном виде, это станет (10²) + (0¹) + 0. Видите тенденцию?

Применим это к двоичному файлу.

0b10 == (2¹) + 0

Поскольку 2¹ == 2 это означает, что 0b10 2 в десятичной системе, что верно. Давай сделаем еще один.

0b101 == (2²) + (0¹) + 1

Это сделало бы 101 в двоичном формате, 5 (пять) в десятичном, что также верно.

Шестнадцатеричный

Здесь в игру вступает шестнадцатеричный. Запись больших двоичных чисел, хотя и эффективна, очень быстро становится нечитаемой. Однако запись десятичных чисел плохо работает с двоичными. Представление двоичного числа в десятичном виде сбивает с толку. Таким образом, шестнадцатеричная система счисления (основание 16) заполняет этот пробел.

0b010100000 (или 80 в десятичной системе счисления) сложно читать и вычислять. Итак, мы создали третью систему для работы, которая является шестнадцатеричной или использует степень 16.

Это усиливает существующую десятичную систему, добавляя числа (десять, одиннадцать, двенадцать, тринадцать, четырнадцать и пятнадцать). Или a, b, c, d и f в таком порядке.

Преимущество шестнадцатеричного числа (иногда сокращенно до «шестнадцатеричного») заключается в том, что он может представлять большие числа лучше, чем двоичные и даже десятичные числа, при этом сохраняя удобочитаемость. Помимо удобочитаемости больших чисел, он не теряет совместимости с двоичным кодом, что и десятичный. Подробнее об этом позже, когда мы рассмотрим сдвиг бит и другие математические операции.

0b01010000 в шестнадцатеричном формате - это 0xa0. Или (поскольку a означает 10) (10¹) + 0.

Подписывающий бит

Есть еще одно отличие целых чисел. Вышеупомянутое целое число представляет собой 8-битовое целое число без знака.

Эти целые числа не могут быть отрицательными. Таким образом, максимальное число, которое может быть представлено 8-битным беззнаковым целым числом, равно 255.

Быть 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 или 0b11111111.

Наименьшее представимое число - 0 или 0b00000000.

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

0b10000001 без знака - это 128 + 1 или 129.

Тот же самый номер в подписанном - -1, потому что 128 будет представлять -, а следующее число - 1.

Добавление

Математика с двоичным кодом невероятно проста. Здесь мы будем работать с беззнаковыми наборами из 4 бит, создавая максимальное количество (1 + 2 + 4 + 8) или 15.

0b0001 + 0b0010 == 0b0011

Выше указано 1 + 2 == 3 в десятичном виде. Способ вычисления такой же, как и в десятичном.

C = A + B, если C больше, чем порядок основания, над которым мы работаем, результат C будет 1 на порядок выше. А остальное остается в таком же порядке.

4 + 8 == 12

Поскольку 4 + 8 больше, чем база, над которой мы работаем (база 10), мы создаем 10 (10^(current_magnitude + 1)) и добавляем остаток, умноженный на величину, которая равна 2 * (10 ^ current_magnitude). Поскольку величина равна 0, это становится 12.

Если мы применим это к более высокому порядку величины.

40 + 80 == 120

40 составляет 4 на один порядок, а 80 это 8 на один порядок.

Если 4 + 8 больше 9 (максимальное число по величине), это становится новым порядком величины с остатком 2.

// base (10) ^ (order of magnitude + 1)
let newOrder = (10 ^ (1 + 1))
// 2 ^ order of magnitude
let newRemainder = (20 ^ 1)

И последнее, но не менее важное: вы работаете с более низких порядков. Вы записываете остаток и добавляете новый порядок величины (если есть) к следующей сумме.

119 + 873
3 + 9 is (2 remainder, 1 of the next magnitude)
7 + 1 + 1 is (9 remainder, 0 of the next magnitude)
1 + 8 is (9, 0 to the next magnitude)

В порядке от большего к меньшему, это становится «992», что правильно.
То же самое работает в двоичном формате, только с разными порядками величины.

0b0001 + 0b0001 == 0b0010
0b0011 + 0b0010 == 0b0101

Целочисленные переполнения

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

Первые три, в частности, не такие, как на других языках.

Если сложить 2 числа на любом языке, получится ожидаемая сумма.

1 + 2 == 3

Предположим, у вас есть целое число без знака, в котором хранится 0b11111111. Вы добавляете 0b00000001.

Это приводит к следующему:

0b11111111 + 0b00000001 == 0b100000000

Полученное число состоит из 9 бит. Если вы используете обычное целое число, ничего страшного. Но в этом случае мы работаем с UInt8 или беззнаковым 8-битным целым числом. Как видите, 9 бит не помещаются в 8-битное целое число, поэтому оставшийся (самый высокий) бит будет потерян.

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

Если вы на 100% уверены, что ваши числа никогда не переполнятся, вы можете отключить эту проверку с помощью оператора &+.

let three = 1 &+ 2
let alsoThree = 0b00000010 + 0b00000001

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