Автор Тема: Чертов сдвиг вправо  (Прочитано 8013 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Чертов сдвиг вправо
« : 05 Декабря 2011, 16:27:01 »
Решил написать криптовалку на пурике, столкнулся с неожиданными проблемами.
Нет команды верчения байтов в переменной, ладно, нашел в инете готовый пример Rola влево на асме:

Procedure Rol(num,count) ; rotate left
 
    !MOV dword ECX,[p.v_count]
    !ROL dword [p.v_num],cl
 
  ProcedureReturn num
EndProcedure

Отлично работает, ладно.

Сдвиг влево и вправо есть, слава богу, НО! Влево работает зашибись а вправо фигня какая-то получается.

Пример - есть число типа лонг - D7 4C A7 A3, сдвигаю его право на пять бит. В баскоме все отлично, получается число 06  BA 65 3D, баском услужливо показывает это число в переменной во всех ракурсах - в десятичном - 112878909 и бинарном виде - все честно - сдвинуто на 5 бит.

Чертов PureBasic же упорно показывает результат сдвига того же числа на 5 как десятичное число  X2 = -21338819, то есть FE BA 65 3D - после сдвига остаются еденицы а не ноли???

С горя я переделал вышеприведенную процедуру,  на сдвиг вправо -

Procedure SAR(num,count) ; shift right
 
    !MOV dword ECX,[p.v_count]
    !SAR dword [p.v_num],cl
 
  ProcedureReturn num
EndProcedure

Но и она, сука, возвращает -21338819 !!! Пипец. Жесть. В чем дело?

С горя загрузил виндовсседьмой калькулятор программиста, там есть подозрительные кнопки lsh и rsh но ОНИ НЕ РАБОТАЮТ! Блин, мегакорпорация, а описания кнопок во всем интернете нет, и в помощи, одни описание горячих клавиш,  которое вообще мне не упирались в одно место.

« Последнее редактирование: 05 Декабря 2011, 16:31:45 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Чертов сдвиг вправо
« Ответ #1 : 05 Декабря 2011, 18:47:08 »
В пуребасике для сдвига вправо используется команда SAR - арифметический сдвиг. А он забивает освободившиеся биты не нулями, а значением старшего бита. Надо использовать SHR.

Вот пример кода:
Цитировать
Procedure Shl(num,count) ; shift left
    !MOV dword ECX,[p.v_count]
    !SHL dword [p.v_num],cl
  ProcedureReturn num
EndProcedure

Procedure Shr(num,count) ; shift right
    !MOV dword ECX,[p.v_count]
    !SHR dword [p.v_num],cl
  ProcedureReturn num
EndProcedure

Procedure Rol(num,count) ; rotate left
    !MOV dword ECX,[p.v_count]
    !ROL dword [p.v_num],cl
  ProcedureReturn num
EndProcedure

Procedure Ror(num,count) ; rotate right
    !MOV dword ECX,[p.v_count]
    !ROR dword [p.v_num],cl
  ProcedureReturn num
EndProcedure


If OpenConsole()
 
  PrintN("Handmade functions:");
 
  X.l = Val("$D74CA7A3")
  PrintN("X      : "+RSet(Hex(X.l,#PB_Long),8,"0")+" ("+RSet(Bin(X.l,#PB_Long),32,"0")+")");
  Y.l = Rol(X.l, 5)
  PrintN("Rol 5  : "+RSet(Hex(Y.l,#PB_Long),8,"0")+" ("+RSet(Bin(Y.l,#PB_Long),32,"0")+")");
 
  X.l = Val("$D74CA7A3")
  PrintN("X      : "+RSet(Hex(X.l,#PB_Long),8,"0")+" ("+RSet(Bin(X.l,#PB_Long),32,"0")+")");
  Y.l = Ror(X.l, 5)
  PrintN("Ror 5  : "+RSet(Hex(Y.l,#PB_Long),8,"0")+" ("+RSet(Bin(Y.l,#PB_Long),32,"0")+")");
 
  X.l = Val("$D74CA7A3")
  PrintN("X      : "+RSet(Hex(X.l,#PB_Long),8,"0")+" ("+RSet(Bin(X.l,#PB_Long),32,"0")+")");
  Y.l = Shl(X.l, 5)
  PrintN("Shl 5  : "+RSet(Hex(Y.l,#PB_Long),8,"0")+" ("+RSet(Bin(Y.l,#PB_Long),32,"0")+")");
 
  X.l = Val("$D74CA7A3")
  PrintN("X      : "+RSet(Hex(X.l,#PB_Long),8,"0")+" ("+RSet(Bin(X.l,#PB_Long),32,"0")+")");
  Y.l = Shr(X.l, 5)
  PrintN("Shr 5  : "+RSet(Hex(Y.l,#PB_Long),8,"0")+" ("+RSet(Bin(Y.l,#PB_Long),32,"0")+")");
 
  PrintN("");
  PrintN("Built-in operators:");
 
  X.l = Val("$D74CA7A3")
  PrintN("X      : "+RSet(Hex(X.l,#PB_Long),8,"0")+" ("+RSet(Bin(X.l,#PB_Long),32,"0")+")");
  Y.l = X.l << 5
  PrintN("<<  5  : "+RSet(Hex(Y.l,#PB_Long),8,"0")+" ("+RSet(Bin(Y.l,#PB_Long),32,"0")+")");
 
  X.l = Val("$D74CA7A3")
  PrintN("X      : "+RSet(Hex(X.l,#PB_Long),8,"0")+" ("+RSet(Bin(X.l,#PB_Long),32,"0")+")");
  Y.l = X.l >> 5
  PrintN(">>  5  : "+RSet(Hex(Y.l,#PB_Long),8,"0")+" ("+RSet(Bin(Y.l,#PB_Long),32,"0")+")");
 
  Input()
EndIf

А вот результат выводимый на экран
Цитировать
Handmade functions:
X      : D74CA7A3 (11010111010011001010011110100011)
Rol 5  : E994F47A (11101001100101001111010001111010)
X      : D74CA7A3 (11010111010011001010011110100011)
Ror 5  : 1EBA653D (00011110101110100110010100111101)
X      : D74CA7A3 (11010111010011001010011110100011)
Shl 5  : E994F460 (11101001100101001111010001100000)
X      : D74CA7A3 (11010111010011001010011110100011)
Shr 5  : 06BA653D (00000110101110100110010100111101)

Built-in operators:
X      : D74CA7A3 (11010111010011001010011110100011)
<<  5  : E994F460 (11101001100101001111010001100000)
X      : D74CA7A3 (11010111010011001010011110100011)
>>  5  : FEBA653D (11111110101110100110010100111101)

В калькуляторе семерки та же фигня, SAR а не SHR. Если старшим битом будет 0, тогда и заполнять будет нулями.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Чертов сдвиг вправо
« Ответ #2 : 06 Декабря 2011, 01:48:55 »
Привет, pumpkin! Рад тебя видеть на форуме.

Стало быть меня цинично обманули в мануале - http://pure-basic.narod.ru/docs/books/3.htm

Сегодня в помощи пурика посмотрю насчет правого сдвига. Мне даже в голову не пришло, что сдвиги разные бывают.

Проверю, отпишусь.
« Последнее редактирование: 06 Декабря 2011, 01:50:23 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Прохожий

  • Гость
Re: Чертов сдвиг вправо
« Ответ #3 : 06 Декабря 2011, 07:59:21 »
Цитировать
Влево работает зашибись а вправо фигня какая-то получается.
Хм, а причем тут бейсик?
Вы ведь вращаете биты с помощью ассемблера.

Цитировать
Стало быть меня цинично обманули в мануале
Я там не увидел ни асма, ни вращения бит.
В чем именно обманули?

PS.
Что за прикол, - процитировал ссылку, а форум матюгнулся на нее?

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Чертов сдвиг вправо
« Ответ #4 : 06 Декабря 2011, 09:30:00 »
Для прохожих объясняю популярно:

Сдвиг вправо в пурике работает не как в мануале - смотрите раздел свиг вправо. Он реализован в точь в точь как в  моем примере -    
!MOV dword ECX,[p.v_count]
!SAR dword [p.v_num],cl
и скорее всего так и сделан внутренне.

Правлильная работа как в мануале обеспечивается, когда в процедуре меняешь SAR (арифметический сдвиг) на SHR - обычный сдвиг с нулевыми байтами. Другими словами, пурик вместо простого сдвига делает арифметический, и победить это можно с помощью ассемблера. В мануле же написано с табличкой как пурик делает обычный сдвиг вправо, хотя это не так.
Цитировать
Оператор >> (Сдвиг вправо)

 Оператор >> работает точно так же, как оператор <<, но  в противоположном направлении. Вот код демонстрирующий использование этого оператора:

NumberOne.b = 50
NumberTwo.b = NumberOne >> 1
Debug NumberTwo

В этом примере мы назначаем переменной NUMBERONE значение 50. Затем мы создаем переменную NumberTwo и присваиваем ей значение NUMBERONE, но обработанное оператором >>. Результат этой операции  25  мы и наблюдаем в окне вывода отладки.И конечно же посмотрите таблицу:

Значение 50            0            0            1            1           0            0           1           0
Значение 25            0            0            0            1           1            0           0           1
Как вы можете видеть результат вычисления имеет просто смещение двоичных битов вправо от их исходного положения, в данном случае на одно место При переключении разрядов вправо, (как в нашем случае на 1) крайний правый бит пропадает навсегда, а крайний левый заполняется нулем, остальные сдвигаются.


« Последнее редактирование: 06 Декабря 2011, 09:32:28 от admin »
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Форум проекта "Минилаб-Мастер"

Re: Чертов сдвиг вправо
« Ответ #4 : 06 Декабря 2011, 09:30:00 »

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Чертов сдвиг вправо
« Ответ #5 : 06 Декабря 2011, 11:48:27 »
@ Прохожий

Речь, как уже сказал Andy, идет о PureBasic и его встроенном операторе ">>" (shift right), который компилирется в SAR.

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Чертов сдвиг вправо
« Ответ #6 : 07 Декабря 2011, 15:40:23 »
Прочитал помощь, там написано четко про сдвиг, в вышеприведенном мануале все упростили.

>> Arithmetic shift right. Shifts each bit in the value of the expression on the LHS right by the number of places given by the value of the expression on the RHS. Additionally, when the result of this operator is not used and the LHS contains a variable, that variable will have its value shifted. It probably helps if you understand binary numbers when you use this operator, although you can use it as if each position you shift by is dividing by an extra factor of 2.

пример:
d=16 >> 1 ; The value of d will be 8. 16=%10000, 8=%1000
e.w=%10101010 >> 4 ; The value of e will be %1010. %10101010=170, %1010=10. Bits shifted out of the right edge of the result are lost (which is why you do not see an equal division by 16)
f.b=-128 >> 1 ; The value of f will be -64. -128=%10000000, -64=%11000000. When shifting to the right, the most significant bit is kept as it is.

Как говорится святая простота..
Интерестно, а в паскале делфи и си какие сдвиги имеются ввиду?

И еще такой вопрос, можно ли так написать процедуру, чтобы не писать всегда
X=SHL (X , 5)

а писать просто

SHL (X , 5)

и переменная X сдвинется?
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

pumpkin

  • Модератор Раздела
  • Профи
  • *
  • Сообщений: 240
  • Карма: 2
  • Пол: Мужской
  • Это Я :-)
    • Просмотр профиля
Re: Чертов сдвиг вправо
« Ответ #7 : 07 Декабря 2011, 17:49:52 »
Цитировать
И еще такой вопрос, можно ли так написать процедуру, чтобы не писать всегда
X=SHL (X , 5)

а писать просто

SHL (X , 5)

и переменная X сдвинется?
Можно, в принципе, но тогда надо ей передавать не икс, а адрес икса (Shl(@X,5)). И в самой процедуре написать извлечение значения по адресу в регистр, сдвиг в регистрах, запись результата по адресу.

Такая процедура в использовании более похожа на баскомовский, конечно, но появляется куча ограничений: ее не воткнешь в длинные выражения (например, A*B+Shl(C,D)), ей не пердашь в качестве параметра выражение (например Shl(A+B*C, 5)) и т.д.

В том виде в котором она в твоем первом и моем втором посте, она прекрасно заменяет оператор "<<". Так что лучше оставить так как есть.
« Последнее редактирование: 07 Декабря 2011, 17:51:56 от pumpkin »

Andy

  • Администратор Форумa
  • Эксперт
  • *
  • Сообщений: 1803
  • Карма: 15
  • Пол: Мужской
  • Нельзя отремонтировать то, что не сломано...
    • minilabmaster
    • Просмотр профиля
    • Форум "Минилаб-Мастер"
Re: Чертов сдвиг вправо
« Ответ #8 : 08 Декабря 2011, 02:12:28 »
Все понял, спасибо.
Заклинило деталь - надави на нее, если она сломалась - ничего, ее все равно надо было менять.

Форум проекта "Минилаб-Мастер"

Re: Чертов сдвиг вправо
« Ответ #8 : 08 Декабря 2011, 02:12:28 »