За последние 24 часа нас посетили 21023 программиста и 1465 роботов. Сейчас ищут 1024 программиста ...

Побитовое AND с отрицательным числом

Тема в разделе "PHP для новичков", создана пользователем виталий032, 29 мар 2018.

  1. виталий032

    виталий032 Активный пользователь

    С нами с:
    31 янв 2014
    Сообщения:
    227
    Симпатии:
    30
    Адрес:
    Владивосток
    Подскажите, пожалуйста, почему мой ответ на "бумаге" не совпадает с компилятором интерпретатором.

    PHP:
    1. int a = -39;
    2.  
    3. int b = a & 203;
    4. echo b; // 201
    39 в двоичной системе будет 100 111.
    -39 => инвертировал в 011 000 и прибавил 1 => получил 011 001 (при проверке на онлайн calc не сходится:() следовал этой инструкции (абзац отрицательные числа).

    Делаю побитовое AND: ( 1 и 1 дают единицу, все остальное 0)
    203 в двоичной будет 1100 1011.
    1100 1011 // 203
    &
    0001 1001 // -39
    ________
    0000 1001 // не получается 201, как выдает echo

    Онлайн калькулятор говорит, что -39 это -100 111.
    Но, как тогда сделать побитовое AND ручками, на бумаге? Знак минуса смущает.

    1100 1011 //203
    &
    -10 0111 // -39
    ________
    ????????
     
  2. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.597
    Симпатии:
    1.764
    Разрядность не учитываете. На современной машине у php-а (по крайней мере в линусе) 64 разряда на целое.
     
  3. виталий032

    виталий032 Активный пользователь

    С нами с:
    31 янв 2014
    Сообщения:
    227
    Симпатии:
    30
    Адрес:
    Владивосток
    Что значит учитывать разрядность, как ее учитывать?
    Тестирую вообще на яве.
     
    #3 виталий032, 29 мар 2018
    Последнее редактирование: 29 мар 2018
  4. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.857
    Симпатии:
    656
    Это неправильно. Нужно инвертировать весь код в пределах заданной разрядности. Например, для 8-разрядной ячейки должно получиться 11 011 000.
    --- Добавлено ---
    Правильно смущает. Никакого знака минуса в памяти нет, если говорить о популярном представлении целых чисел, например -1 в восьми разрядах – это 255.
     
    виталий032 нравится это.
  5. виталий032

    виталий032 Активный пользователь

    С нами с:
    31 янв 2014
    Сообщения:
    227
    Симпатии:
    30
    Адрес:
    Владивосток
    Ах, какая боль, 200 получается вместо 201.

    1100 1011 // 203
    &
    1101 1000 // -39
    ___________
    1100 1000 => 200 [10]

    [Updated]

    1100 1011 // 203
    &
    1101 1001 // -39 (Нужно было прибавить единицу)
    ___________
    1100 1000 => 200 [10]
     
    #5 виталий032, 29 мар 2018
    Последнее редактирование: 29 мар 2018
  6. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.857
    Симпатии:
    656
    1 забыли прибавить при получении кода -39.
     
    виталий032 нравится это.
  7. виталий032

    виталий032 Активный пользователь

    С нами с:
    31 янв 2014
    Сообщения:
    227
    Симпатии:
    30
    Адрес:
    Владивосток
    Ура! Спасибо! Получилось.

    А как компилятор узнал, и мне узнать, что 1101 1001 ( -39 ) это отрицательное число, ну и, если бы я переводил это число в десятичную с.с., то получил бы 217 (128 + 64 + 16 + 8 + 1)?

    Я читал, что знак определяет старший бит. Если отрицательное число, то 1, в противном случае 0. Но у 39 в двоичной системе старший бит, тоже 1.
     
    #7 виталий032, 29 мар 2018
    Последнее редактирование: 29 мар 2018
  8. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    минус типа первым битом идёт. поэтому либо с 0 по 255, либо -128 до +127.
    Ещё в каких-то архитектурах индейцы вступают в игру, но это редкость.
     
    виталий032 нравится это.
  9. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.857
    Симпатии:
    656
    Никак. Дело только в трактовке. Если вам заранее сказать, что число имеет форму представления «целое со знаком» в восьми разрядах, то 217 вы никак не должны получить.

    Это просто признак, а не специально выделенный знаковый разряд. Кодирование таково, что у кодов отрицательных чисел этот бит всегда установлен (если числа считать отрицательными).

    Опять ошибаетесь, забывая про разрядность сетки. Нужно смотреть на полный дв. код: 00100111 ;)

    P.S. Вообще это школьный материал. У меня племяши такое изучали.
     
    виталий032 нравится это.
  10. виталий032

    виталий032 Активный пользователь

    С нами с:
    31 янв 2014
    Сообщения:
    227
    Симпатии:
    30
    Адрес:
    Владивосток
    Что за индейцы?

    В школе было такое пару занятий, но сдавал по принципу "сдал, забыл". А, сейчас, для игры понадобилось вытащить rgba из пикселя, но с пониманием что делаю.

    Там, есть такой момент:
    PHP:
    1. int rgba = -39;
    2. int red = (rgba >> 16) & 0xFF;
    И, непонятно, зачем делать & с 0xff, так как 0xFF это 1111 1111 и при побитовом AND результат останется тем же, т.е. (rgba >> 16).

    Т.е. чтобы компьютер перевел 8-разрядное 1101 1001 в -39 нужно сообщить ему, что необходимо рассматривать диапазон от -128 до +127, а не от 0 до 255?
     
    #10 виталий032, 30 мар 2018
    Последнее редактирование: 30 мар 2018
  11. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    @виталий032
    ты не правильно считаешь
    с какой стати 0001 1001 это 39, если это 25?
     
  12. виталий032

    виталий032 Активный пользователь

    С нами с:
    31 янв 2014
    Сообщения:
    227
    Симпатии:
    30
    Адрес:
    Владивосток
    Первоначально неправильно инвертировал, ответы выше разве не смотрел?!
     
  13. [vs]

    [vs] Суперстар
    Команда форума Модератор

    С нами с:
    27 сен 2007
    Сообщения:
    10.559
    Симпатии:
    632
    точно, сорян
    в двоичной арифметике, отрицательных чисел не существует. Число 1101 1001 оно и в африке 1101 1001, а 217 или -39 это лишь представление в десятичной системе.
    Когда ты пишешь -39 в PHP, он воспринимает его как 11111111 11111111 11111111 11111111 11111111 11111111 11111111 11011001. ВНЕЗАПНО, это число AND 11001011 (203) даёт то же самое 11001001 (201).
    Для записи отрицательного числа не просто старший бит устанавливается в 1. Возьмём число 6 в восьмибитном регисте, это 00000110, но 10000110 это не -6, а -122. Отрицательное 6 это 11111010. Оно выглядит как инвертированное положительное 5 (0000 0101). И так выглядят все отрицательные числа относительно положительных.
    -39 1 1 0 1 1 0 0 1
    38 0 0 1 0 0 1 1 0
    0000 0000 это самое маленькое число без знака (0). А 1000 0000 - это самое маленькое число со знаком, т.е. -128. С добавлением единиц, число увеличивается, пока не превратится в -1 или 11111111. Прибавлении единицы потребует нового разряда - 100000000 - но поскольку у нас всего 8 бит, то все единицы улетели за край и остался только 0. То есть это получилось само собой. Процессору не нужно как-то особо обозначать отрицательное число. Независимо от того, складывает пользователь, или вычитает, процессор только складывает.
     
    виталий032 нравится это.
  14. miketomlin

    miketomlin Старожил

    С нами с:
    9 авг 2016
    Сообщения:
    3.857
    Симпатии:
    656
    Вымирающий вид.

    Всего-то? Вся команда выделяет значение третьего байта. Два младших байта сдвигаются в небытье. И & 0xFF чистит все, что остается выше младшего (после сдвига) байта.
     
    виталий032 нравится это.
  15. виталий032

    виталий032 Активный пользователь

    С нами с:
    31 янв 2014
    Сообщения:
    227
    Симпатии:
    30
    Адрес:
    Владивосток
    В общем, кажется я разобрался.

    Для тех, кто в поисках ответа на свой вопрос в гугле в будущем найдет эту тему (в том числе и для меня):

    Одним из моих недопониманий было то, почему онлайн калькулятор при переводе из
    двоичной -> десятичную выдавал ВСЕГДА положительное число.

    Пример:
    8-битный byte signed (в java нет типа unsigned)
    Возьмем число -2. В двоичном представлении 8-битном типе byte будет 1111 1110.
    Если ввести в онлайн калькуляторе 1111 1110, то получим не -2, а ну блин 254.

    Это скорее всего потому, что все вводимые в форму на сайте числа:

    • приводятся к большему по диапазону типу, например, (тип byte) 1111 1110 приведется к (тип int) "24нуля и 1111 1110". Проще говоря, 8-битный signed приведется к 32-битному signed дописыванием спереди 24 нуля, соответственно новое десятичное число будет положительным;
    • разбираются на цифры и приводятся в стиле: 1∙2^7+1∙2^6+1∙2^5+1∙2^4+1∙2^3+1∙2^2+1∙2^1+0∙2^0, что тоже всегда даст положительное число
    Из java переломным моментом в моем понимании стало вот этот мой эксперимент:
    PHP:
    1. // int var 1 = 24 нуля + 11111110
    2. int var1 = Integer.parseInt("11111110",2);
    3.  
    4. // понизили до 8 бит, т.е. 24 нуля убрали
    5. byte var2 = (byte)(Integer.parseInt("11111110",2));
    6. System.out.println("int var1 = " + var1); // 254
    7. System.out.println("byte var2 = " + var2); // -2
    А, в примере с & 0xFF вообще просто теперь.
    2 в int это 24 нуля + 0000 0010.
    -2 в int это 24 единицы + 1111 1110
    Предположим, что -2 в двоичном виде это RGBA пикселя, тогда чтобы получить оттенок синего (последний байт) нужно :

    Код (Text):
    1.    A    |   R    |   G    |   B    
    2. 11111111 11111111 11111111 1111 1110 // -2
    3. &
    4. 00000000 00000000 00000000 1111 1111 // 0xFF
    5. __________________________________
    6. 00000000 00000000 00000000 1111 1110 // 254 почти полностью синий пиксель

     
    #15 виталий032, 31 мар 2018
    Последнее редактирование: 31 мар 2018
    [vs] нравится это.