КИТА unofficial

Компьютерный => Программирование => Тема начата: Archangel от Ноябрь 18, 2007, 05:05:57



Название: Инверсия в С/С++
Отправлено: Archangel от Ноябрь 18, 2007, 05:05:57
а=~a;
почему-то получаю: а было 255, а после операции стало -256 ???. Так и должно быть или как? Я вообще ожидал получить 0.


Название: Re: инверсия в С
Отправлено: Storm от Ноябрь 18, 2007, 05:24:20
тип у a какой?

a= !a; будет 0 только это логическая инверсия.


Название: Re: инверсия в С
Отправлено: LazarusLong от Ноябрь 18, 2007, 05:31:31
Вот вот)) Зависит от типа.


Название: Re: инверсия в С
Отправлено: Archangel от Ноябрь 18, 2007, 05:34:34
Цитировать
Давайте теперь смотреть, что эти операторы делают. Начнем мы с оператора битового дополнения - ~. Просто потому, что это - единственный из битовых унарынй оператор, то есть, он работает с одним числом, а не с двумя. В принципе, его название говорит само за себя - он просто инвертирует все биты своего операнда. То есть (в предположении, что в нашем целом числе только 4 бита), проинвертировав беззнаковое число 9, мы получим 6:
9 = 1001
~9 = 0110 = 6
Загуглил нашел такое объяснение действию ~. Вот такое действие мне и нужно, но почему то
printf("%d",~9);
Выводит -10, а не ожидаемые 6.
Тип int.


Название: Re: инверсия в С
Отправлено: LazarusLong от Ноябрь 18, 2007, 06:14:44
Это потому, что при инверсии инвертируются все разряды, в том числе и знаковый. Смотрите:

9, это ведь не 1001, как вам бы хотлеось. Это, на самом деле 0 000 0000 0000 1001, где первый бит - знаковый разряд.

После инверсии мы получаем - 1 111 1111 1111 0110, что сильно напоминает представление числа -10 в дополнительном коде.

10 - 1010 - 0 000 0000 0000 1010 инвертируем - 1 111 1111 1111 0101. Это у нас обратный код. Добавляем единицу, что бы получить дополнительный - 1 111 1111 1111 0110. Вуаля!. Так что всё работает верно ))).

Честно сказать, я теорию уже подзабыл, давненько не возился с обратным и дополнитлеьным кодом, но мне сдается, что объяснение в этом.


Название: Re: инверсия в С
Отправлено: Archangel от Ноябрь 18, 2007, 06:18:47
Ну а если мне надо все таки получить 6, что делать?


Название: Re: инверсия в С
Отправлено: Storm от Ноябрь 18, 2007, 06:21:38
sizeof(a) чему равен?

:)))))
на 32разрядном компьютере :))))))))
:lol:

# /etc/rc.d/rc.brain start

int - знаковое целое 32 бита

31 разряд отдан под знак, обрабатывается отдельно от остальных

int a=255;
// a == 0b 0000 0000  0000 0000  0000 0000 1111 1111
a=~a;
// a== 0b 1111 1111  1111 1111  1111 1111  0000 0000 == -256

компьютер работает правильно ;)

для того чтобы был ноль надо
Код:
  unsigned char a;

  a=255;


  printf("size %d   %d == ~%d",sizeof(a),a,(unsigned char)~a);


Название: Re: инверсия в С
Отправлено: Archangel от Ноябрь 18, 2007, 06:45:56
Это конечно хорошо, а если у меня а расчитывается в цикле, то что надо будет расчитывать в int, а потом переводить в unsigned char? А попроще никак число не проинвертировать?


Название: Re: инверсия в С
Отправлено: Archangel от Ноябрь 18, 2007, 07:13:07
Мне вообще не для printf это все надо, а для outb. То я просто смотрел что получится.


Название: Re: инверсия в С
Отправлено: Storm от Ноябрь 18, 2007, 09:32:43
Операция ~ определена только для типа int, outb работает с младшими 8 битами, не нравиться приведение к типу unsigned char - убирай маской  ненужные биты в ноль. Всегда есть другой способ

Код:
  unsigned short int a;

  a=255;


  printf("size %d   %d == ~%d",sizeof(a),a,(unsigned short int)~a&0xff);





Название: Re: инверсия в С
Отправлено: Archangel от Ноябрь 18, 2007, 09:44:14
Спасибо, но думаю сработает вариант:
не а = 255 - а;


Название: Re: инверсия в С
Отправлено: Storm от Ноябрь 18, 2007, 09:51:05
на знаковом типе не сработает. 

битовые операции и маски, ИМХО, предсказуемее.


Название: Re: инверсия в С
Отправлено: Archangel от Ноябрь 18, 2007, 10:08:07
Мне собственно и надо было избавиться от инверсии знакового бита.


Название: Re: инверсия в С
Отправлено: Артем от Март 24, 2008, 05:49:22
Это потому, что при инверсии инвертируются все разряды, в том числе и знаковый. Смотрите:
9, это ведь не 1001, как вам бы хотлеось. Это, на самом деле 0 000 0000 0000 1001, где первый бит - знаковый разряд.
После инверсии мы получаем - 1 111 1111 1111 0110, что сильно напоминает представление числа -10 в дополнительном коде.
10 - 1010 - 0 000 0000 0000 1010 инвертируем - 1 111 1111 1111 0101. Это у нас обратный код. Добавляем единицу, что бы получить дополнительный - 1 111 1111 1111 0110. Вуаля!.
Так что всё работает верно ))). Честно сказать, я теорию уже подзабыл, давненько не возился с обратным и дополнитлеьным кодом, но мне сдается, что объяснение в этом.

Я вот тоже столкнулся с такой же проблемой, что при побитовой инверсии, ручной просчет и результат который выдает Си значительно расходяться. Почитал эту тему, поискал в инете, но там все "кусками", и не очень понятен сам алгоритм перевода в дополнительный код и обратный, и для чего вообще они используються. 

LazarusLong, не могли бы Вы объяснить сам алгоритм по шагам, как надо считать, ЧТОБЫ РЕЗУЛЬТАТ ИНВЕРТИРОВАНИЯ СОШЕЛСЯ С ТЕМ ЧТО МНЕ ВЫДАЕТ СИ. Вот то что я вроде понял, если что подправтье пожалуйста:

Например, поинвертируем все то же число 9: при  ручном просчете, как уже было сказано, получаеться:
                                                                                                                                                        9 = 1001
                                                                                                                                                      ~9 = 0110 = 6
А теперь, просичтаем так, как считает Си, который выдает что  ~9 = -10, при использовании типа int :

1) Так как используетьс тип int, который занимает 2 байта, то есть 16 бит, то переводим число в 2-ичную систему и дополняем его нулями до 16 знаков, где первый бит знаковый разряд ( 0 -положительный, 1  -отрицательный):

                                                   9 (в 10-тичной)   =   0 000 0000 0000 1001  (в 2-ичной)

2) Далее инвертируем все биты числа:    получаеться   -    1 111 1111 1111 0110.  Это мы получили дополнительный код.
Если перевести это число в 10-тичную систему, то получаеться 65526, такой результат даже выдает Си, но только в том случае если вместо int поставить unsigned int.

Вот здесь возникает 1-ый вопрос по самому алгоритму: что делать дальше ? Получили дополнительный код, а вот как узнать каком числу соответствует этот дополнительный код ???

3) Не знаю правильно ли, но мне кажеться, что нужно перевести этот дополнительный код в обратный? Для этого мы должны отнять единицу от дополнительного кода ??? Если это действительно так, то получаеться:

                                                 1 111 1111 1111 0110   -   1  =   1 111 1111 1111 0101.

4) Вот здесь возникает 2-ой вопрос: по сути дела, нам осталось только проинтвертировать еще раз, чтобы получить обратный код, верно ??? Если, да то получааеться:
 
                                             ~ ( 1 111 1111 1111 0101 )      =     0 000 0000 0000 1010                                     

5) И наконец 3-ий вопрос: если первести это число   0 000 0000 0000 1010    в 10-тичную систему, то получим 10, а куда девалсся минус, он ведь. если верить Си должен присустствовать ??? 

LazarusLong, если у Вас найдеться время ответить, или может у кого-нибудь другого, то буду очень благодарен !
                                                     


Название: Re: инверсия в С
Отправлено: vimmax от Март 24, 2008, 06:14:51
все зависит от типа числа.
если у тебя int, то при инверсии получишь (-10)
если у тебя unsigned int, то при инверсии получишь (4294967286)
а в hex все равно будет (fffffff6)


Название: Re: инверсия в С
Отправлено: Артем от Март 24, 2008, 06:25:44

все зависит от типа числа.
если у тебя int, то при инверсии получишь (-10)
если у тебя unsigned int, то при инверсии получишь (4294967286)
а в hex все равно будет (fffffff6)

vimmax, спасибо за ответ !  А как на счет правильности алгоритма ручного просчета, я правильно все сделал? Почему у меня тогда куда-то пропал минус ?


Название: Re: инверсия в С
Отправлено: Archangel от Март 24, 2008, 07:18:14
artem90, вообще не понял что ты хочешь, дополнительный код к положительному числу получается путем дописывания в старший знаковый разряд 0, и все ничего не инвертируется дальше. А подробнее почитай в  википедии  (http://ru.wikipedia.org/wiki/Дополнительный_код_(представление_числа))там очень понятно написано.


Название: Re: инверсия в С
Отправлено: Артем от Март 24, 2008, 07:21:12
artem90, вообще не понял что ты хочешь.

Я хочу понять, как Си считает так, что получаеться -10. Как мне получить это же значение ВРУЧНУЮ ??? Вот что я хотел. 

А на счет дополнительного кода, я просто в посте у Lazarusa увидел, поэтому и написал его здесь. Но я так и не понял зачем он здесь нужен.

В википедии я читал, но ведь там идет перевод чисел вне зависимости от типа данных. А в Си как раз от этого товсе и зависит, вот я и хочу понять, как?


Название: Re: инверсия в С
Отправлено: vimmax от Март 24, 2008, 07:26:42
artem90 в хексах (в памяти) запись одна и та же. Только:
- если ты объявил переменную как знаковую - компилятор это помнит и переводит fffffff6 в (-10). С учетом первого разряда знакового и доп кода.

- если ты объявил переменную как беззнаковую - компилятор это помнит и переводит fffffff6 в (4294967286). Как просто целое число, без знаковогго разряда.

Часть работы делает компилятор, наверное ты это упустил ?


Название: Re: инверсия в С
Отправлено: Артем от Март 24, 2008, 07:30:57
vimmax, меня больше интересует как проинвертировать ~9 вручную, чтобы получилось -10. В своем посте я писал алгоритм, которым делал ручной просчет, но получилось не то что выдает Си. В чем же там ошибка, Вы не могли бы сказать ? И как же тогда получить ВРУЧНУЮ ~9 = -10 ???


Название: Re: инверсия в С
Отправлено: Archangel от Март 24, 2008, 08:03:08
Элементарно поменять знаковый бит с 0 на 1.
0 1001 =9
1 0110 =-10


Название: Re: инверсия в С
Отправлено: Артем от Март 24, 2008, 08:14:05
1 0110 =-10

1 0110   =   1*2^4 + 0*2^3 + 1*2^2 + 1*2^1 + 0*2^0 = 16 + 4 +2 = 22

Archangel, не знаю как у Вас получилось, что  1 0110 = -10 ?


Название: Re: инверсия в С
Отправлено: Archangel от Март 24, 2008, 08:18:41
Ну я тебе условно показал, отделенные пробелом - знаковые разряды. Ты все время пытаешься перевести числа как положительные. А если старший(знаковый) разряд 1, то число воспринимается как отрицательное. То есть старший разряд показывает будет перед числом минус или нет. Для знакового типа.
PS Прочитай еще раз пост Storm'a на прошлой странице, там же написано, что знаковый разряд обрабатывается отдельно.


Название: Re: инверсия в С
Отправлено: EvilMax от Март 24, 2008, 09:08:16
Пусть signed char x=9;  (чтобы 1 байт был и меньше писать ;) )

x=00001001(2)

~x=11110110(2)

А вот теперь переводим в 10-ную, не забывая, что компьютер хранит числа в дополнительном коде (далее ДК). То есть абсолютное значени отрицательного числа (т.е. у которого старший бит =1) можно всего получить, инвертируя всё, кроме знака и прибавляя 1.

~1110110(2)=0001001(2)

00001001(2)+1 = 00001010(2)=10(10) - итого, модуль числа 10.

Результат: -10



Подробнее про дополнительный код здесь: Дополнительный код (http://ru.wikipedia.org/wiki/%D0%94%D0%BE%D0%BF%D0%BE%D0%BB%D0%BD%D0%B8%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D0%B9_%D0%BA%D0%BE%D0%B4_%28%D0%BF%D1%80%D0%B5%D0%B4%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%B0%29)


Название: Re: инверсия в С
Отправлено: Артем от Март 24, 2008, 09:54:52
EvilMax, спасибо большое, что объснили !