По сути процессор умеет работать только с битами
С целыми числами все выглядит давольно просто:
1й бит числа определяет знак числа - 0 для положительных и 1 для отрицательных
У нас есть операции для управления битами:
- ~ инверсия
- & конъюнкция
- | дизъюнкция
- >> сдвиг вправо
- << сдвиг влево
введем арифметические операции по порядку:
- Сложение, сводится по сути к сложению битов в столбик
- Отрицание или смена знака, -a выражается как ~a + 1
- Вычитание a - b выражается через a + -b
- Умножение, тут несколько вариантов, зависит от компилятора и его оптимизатора:
- Умножение на степени 2 можно представить сдвигом влево: a * 8 приводится к a << 3 т.к. 8 - это 3я степень 2
- Простые случаи вроде a * 3 можно заменить на a + a + a
- Случаи по сложнее a * 11 складывать a 11 раз само с собой не оптимально
раскладываем 11 на степени 2: 11 = 8 + 2 + 1
вычисляем (a << 3) + (a << 1) + a
С вещественными числами все обстоит сложнее, они тоже представлены в виде битов, но часть битов отводится под целую часть, а часть под мантиссу
По сути число хранится в экспоненциальной форме, где мантисса представляет степень 2, на которую нужно умножить целую часть
Операции над вещественными числами с ненулевой мантиссой более затратны по количеству тактов процессора
Здесь нам понадобятся такие вещи как экспонента и натуральный логарифм, которые можно вычислить в виде суммы ряда, так же через суммы ряда вычисляются многие другие математические функции
Имея экспоненту и логарифм можно выразить степенную функцию
Деление же можно представить через умножение и степени
Вот такая вот высшая математика над двоичными числами происходит "за кадром" наших с виду простых программ :)