Как работает оператор ~ инверсии в java?

195
12 февраля 2019, 13:00

Есть код:

   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. Короче, никак у меня в теории не удаётся инвертировать код

Вопрос: Как на самом деле (объясните на единицах и нулях) работает этот проклятый оператор? И зачем разработчики языка сделали его работу именно такой?

Answer 1

Инверсия является побитовой операцией и преобразует хранящиеся в памяти единицы в нули и нули в единицы. Чтобы понять почему она так работает с типом int нужно изучит структуру представления примитивного типа int в памяти. Примитивный тип int состоит из четырех байт. Старший бит старшего байта отвечает за знак числа, остальные - за значение. Отрицательные числа хранятся в дополнительном коде. Разберем пример для числа -2:

System.out.println(Integer.toBinaryString(-2));
//11111111 11111111 11111111 11111110 - битовое представление числа -2

после операции побитовой инверсии мы получим: 00000000 00000000 00000000 00000001, что эквивалентно десятичной 1 Таким образом для корректного использования побитовых операций важно знать внутреннюю структуру обрабатываемых данных и при необходимости работать только с нужной частью битов используя маски и сдвиги. Необходимо учитывать и то, что другие целочисленные типы при многих операциях так же приводятся к типу int.

Answer 2

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

Графы, алгоритм посещения всех ребер в обе стороны

Никак не могу придумать адекватный алгоритм выполнения задачи, гуглил перегуглил не нашел ничего подходящего, разве что Эйлеров путь, но это...

212
Как использовать DataSource в Java

Как использовать DataSource в Java

Хорошей практикой считается использовать DataSource вместо DriverManager'аВ спринге DataSource вообще используется очень часто

216
Найти номер столбца и ряда элемента матрицы

Найти номер столбца и ряда элемента матрицы

Есть матрица, нужно каждый элемент вывести на экран а также вывести его ряд и столбец

151
Удаленный сервер MySQL

Удаленный сервер MySQL

Как сделать так, чтобы после установки на компьютер сервера MySQL 57 сделать его в виде удаленного сервера, и чтобы другие компьютеры на которых...

175