Есть код:
for(int i = -2; i<2; i++)
System.out.printf("Инверсия %d даст %d. \n", i, ~i );
На выходе:
Инверсия -2 даст 1.
Инверсия -1 даст 0.
Инверсия 0 даст -1.
Инверсия 1 даст -2.
Оператор инверсии похоже реализован так:
Operator ~ (int i){
return -i-1;
}
Но пишут, что инверсия инвертирует нули в единицы. Хорошо, для -2 (инт для упрощения 4 бита берём) 1010, первый бит - знак минус. Значит инверсия будет 0101, то есть 5. Дополнительный код: 0101 + 1 = 0110 - итого 6. Короче, никак у меня в теории не удаётся инвертировать код
Вопрос: Как на самом деле (объясните на единицах и нулях) работает этот проклятый оператор? И зачем разработчики языка сделали его работу именно такой?
Инверсия является побитовой операцией и преобразует хранящиеся в памяти единицы в нули и нули в единицы. Чтобы понять почему она так работает с типом int нужно изучит структуру представления примитивного типа int
в памяти. Примитивный тип int
состоит из четырех байт. Старший бит старшего байта отвечает за знак числа, остальные - за значение. Отрицательные числа хранятся в дополнительном коде.
Разберем пример для числа -2:
System.out.println(Integer.toBinaryString(-2));
//11111111 11111111 11111111 11111110 - битовое представление числа -2
после операции побитовой инверсии мы получим: 00000000 00000000 00000000 00000001, что эквивалентно десятичной 1 Таким образом для корректного использования побитовых операций важно знать внутреннюю структуру обрабатываемых данных и при необходимости работать только с нужной частью битов используя маски и сдвиги. Необходимо учитывать и то, что другие целочисленные типы при многих операциях так же приводятся к типу int.
Отрицательные числа компьютер хранит в дополнительном коде. С точки зрения математики, дополнительный код - это кольцо вычетов по модулю 2N. Не пугайтесь, это страшное слово означает всего лишь, что к отрицательным числам добавляется 2N, где N - число разрядов.
К примеру, 32х-битное число -1 в памяти хранится как 232-1 = 4294967295. Или, в двоичном виде, 11111111 11111111 11111111 111111112.
Аналогично, число -2 в памяти хранится как 232-2 = 11111111 11111111 11111111 111111102, а число -3 - как 232-3 = 11111111 11111111 11111111 111111012.
Легко видеть, что инверсия одного бита с точки зрения математики - это вычитание его из 1: 1-1=0, а 1-0=1. Инверсия же всех 32х бит числа - это вычитание их его из 32х единиц. Но, как уже было показано выше, число состоящее из 32х единиц - это -1.
Таким образом, математически вы правы, оператор инверсии действительно работает так как вы написали:
~x = -1-x
Но не следует думать что эта формула - его реализация. Это всего лишь его математическое свойство, а реализован он по определению - как инверсия всех бит числа.
Кстати, если перенести единицу в другую часть, получится более интересная формула:
~x + 1 = -x
Интересна эта формула тем, что является реализацией оператора "унарный минус" в процессоре. Именно так процессоры вычитают целые числа:
x - y = x + ~y + 1
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Никак не могу придумать адекватный алгоритм выполнения задачи, гуглил перегуглил не нашел ничего подходящего, разве что Эйлеров путь, но это...
Хорошей практикой считается использовать DataSource вместо DriverManager'аВ спринге DataSource вообще используется очень часто
Есть матрица, нужно каждый элемент вывести на экран а также вывести его ряд и столбец
Как сделать так, чтобы после установки на компьютер сервера MySQL 57 сделать его в виде удаленного сервера, и чтобы другие компьютеры на которых...