Пользователь Alex
Alex
10 уровень
Москва

Побитовое отрицание — почему так

Статья из группы Random
Привет всем :) Во время прочтения статьи Побитовые операции у меня, как и у некоторых, возник вопрос: а почему же когда мы инвертируем число 342, то получаем -343. Вот как это выглядит в статье: Побитовое отрицание - почему так - 1У особо пытливых (таких, как я) возник вопрос: "эй, но ведь 010101001 меньше, чем 101010110, логично, что оно должно быть меньше 342 и положительным". Вбивая в любом онлайн-конвертере чисел или же проверяя это с помощью кода:

        Integer a = Integer.valueOf("010101001", 2);
        System.out.println(Integer.toString(a, 10));
неожиданно получаем совсем не -343...
169
Эх, как же хорошо, что когда-то давно на парах по программированию на C я как-то мельком услышал что-то про знаковый разряд в целых числах. Какое-то время погуглив, теперь я могу пояснить, что это за зверь.Побитовое отрицание - почему так - 2На самом деле в статье есть неточность, которая и ставит в тупик. Если мы проверим при помощи кода, что же действительно является результатом инверсии числа 342:

        int a = 342;
        System.out.println(Integer.toBinaryString(~a));
то увидим немного другой результат
11111111111111111111111010101001
Почему же так? Всё дело в том, что в переменной не может лежать просто 101010110, на самом деле оно хранится как
00000000000000000000000101010110
Ведь переменная типа int занимает 4 байта, т.е. 32 бита — 32 ячейки памяти. После инверсии меняются абсолютно все цифры, т.е. и "обрезанные" в начале нули. А теперь самое интересное. Так как в бинарном представлении знак + или - перед числом сохранить не получается, то существует одна хитрость: самый 1й бит на самом деле отвечает за знак и как раз является тем самым знаковым разрядом. А все числа хранятся по такой логике: числа от 00...000 до 01...111 — положительные, начинающиеся с 0 (т.е. от 0 до 2147483647) а начиная с 10...000 до 11...111 — это отрицательные, начиная с самого минимального и заканчивая -1 (т.е. от -2147483648 до -1).

00000000000000000000000000000000 = 0
01111111111111111111111111111111 = 2147483647
10000000000000000000000000000000 = -2147483648
11111111111111111111111111111111 = -1
И дальше вы спросите "Хорошо, Навальный, поверим тебе, но почему ты решил, что это его дворец" но как же при всём этом получается -343? Всё на самом деле просто. Мы можем это просто посчитать вручную. Если мы от двоичной версии получившегося после инверсии числа 342 (11111111111111111111111010101001) "отрежем" (или заменим на 0) самый первый бит и вернём его обратно в десятичную форму.

        String s = "01111111111111111111111010101001";
        System.out.println(s + " = " + Integer.toString(Integer.valueOf(s, 2), 10));
то получим, что
01111111111111111111111010101001 = 2147483305
На самом же деле здесь мы не просто "отрезали" 1 в начале, а вычли из этого числа 10000000000000000000000000000000. Теперь прибавим его обратно, но уже в десятичном виде. Что мы увидим:

~342 =
11111111111111111111111010101001 =
//в двоичном виде//
01111111111111111111111010101001 +
10000000000000000000000000000000
= 
//в десятичном виде//
-2147483648 + 2147483305 = -343
Вот и искомое число -343 :) Ребят, это мой первый пост тут, поставьте, пожалуйста, ему лайк, если понравилось и было познавательно (очень уж я хочу собрать все достижения 😄) Более подробно по этой теме, можно почитать вот тут:Всем удачи и спасибо за внимание)
Комментарии (2)
Чтобы просмотреть все комментарии или оставить свой,
перейдите в полную версию
Anonymous #1384518 35 уровень Expert
5 января 2021
Есть даже задача на побитовые операции. В комментах (популярное) ликбез писал небольшой.