Это первая запись в серии статей, посвященных пониманию вашего компьютера и его программного обеспечения. Наша цель - узнать больше о внутреннем устройстве 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
Сняв чек, вы не только отключите механизм безопасности, но и повысите производительность. Но используйте это осторожно. Использование этого оператора где угодно может привести к серьезным ошибкам и сделать ваше приложение более уязвимым для взлома. Однако в некоторых случаях с гарантией стоит приложить усилия для повышения производительности.