Сдвиги
От: McSeem2 США http://www.antigrain.com
Дата: 13.07.06 22:11
Оценка:
Вопрос не вполне по C++, а скорее по железу, но все-таки.

Коллега неожиданно обнаружил. Что напечатает следующая программа?
#include <stdio.h>
int main()
{
    unsigned sh = 0x2F;
    unsigned v = 1u << sh;
    printf("%u", v);
}


Ответ: 32768, что есть "1 << (sh & 31)". Сдвиг на 32 дает единицу.
При этом, в окне отладчика значение выражения "1<<sh" равно нулю. v = 1<<0x2F тоже дает ноль. Получается неувязочка. Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?

Просьба к тем, у кого есть под руками PPC, Sun, HP, SGI и прочие железяки — как там?
Так же интересно, как оно работает на Java и C# (ни того ни другого под руками нет).

Разумеется, речь идет о платформах с 32-битовыми интами.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Сдвиги
От: VoidEx  
Дата: 13.07.06 23:23
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>При этом, в окне отладчика значение выражения "1<<sh" равно нулю. v = 1<<0x2F тоже дает ноль. Получается неувязочка. Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?


warning C4293: '<<' : shift count negative or too big, undefined behavior

Хотя, как я понял, интересуют именно реальные причины такого поведения. Хз, подождем, что ответят
Re: Сдвиги
От: MuTPu4  
Дата: 14.07.06 00:03
Оценка: 5 (1) +2
Здравствуйте, McSeem2, Вы писали:

MS>Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?

(ISO 14882:2003: 5.8/1):

The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.

Из компиляторов которыми я располагаю на платформе x86 все кроме MSVC (/O2) выдали значение 32768.

MS>Так же интересно, как оно работает на Java и C# (ни того ни другого под руками нет).

(ECMA-334, June 2005: 14.8)

For the predefined operators, the number of bits to shift is computed as follows:

If the resulting shift count is zero, the shift operators simply return the value of x.


(The Java Language Specification Third Edition: 15.19)

If the promoted type of the left-hand operand is int, only the five lowestorder bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f. The shift distance actually used is therefore always in the range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the six lowestorder bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f. The shift distance actually used is therefore always in the range 0 to 63, inclusive.

Re: Сдвиги
От: Ubivetz Украина  
Дата: 14.07.06 11:04
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Вопрос не вполне по C++, а скорее по железу, но все-таки.


MS>Коллега неожиданно обнаружил. Что напечатает следующая программа?

MS>
MS>#include <stdio.h>
MS>int main()
MS>{
MS>    unsigned sh = 0x2F;
MS>    unsigned v = 1u << sh;
MS>    printf("%u", v);
MS>}
MS>


MS>Ответ: 32768, что есть "1 << (sh & 31)". Сдвиг на 32 дает единицу.

MS>При этом, в окне отладчика значение выражения "1<<sh" равно нулю. v = 1<<0x2F тоже дает ноль. Получается неувязочка. Как стандарт регламентирует поведение сдвигов? Или это считается HW dependent?

MS>Просьба к тем, у кого есть под руками PPC, Sun, HP, SGI и прочие железяки — как там?

MS>Так же интересно, как оно работает на Java и C# (ни того ни другого под руками нет).

MS>Разумеется, речь идет о платформах с 32-битовыми интами.


0x2f = 47
1u << 47 = 0
А что ты хотел?
Эх, люблю выпить и переспать с кем нибудь!
Но чаще выходит перепить с кем — нибудь и выспаться...
Re: Сдвиги
От: Erop Россия  
Дата: 14.07.06 17:24
Оценка:
Здравствуйте, McSeem2, Вы писали:

MS>Разумеется, речь идет о платформах с 32-битовыми интами.


Всё просто. На Intel, кажется с 486-го проца есть оптимизация циклических сдвигов.
Типа для операций сдвига используется только младшие пять бит сдвига.

Например на PPC это не так.

Ну а с другой стороны, это всё вполне себе соответсвует стандарту, так как поведение неопределено в таких случаях.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Сдвиги
От: McSeem2 США http://www.antigrain.com
Дата: 14.07.06 18:23
Оценка:
Здравствуйте, Ubivetz, Вы писали:

U>0x2f = 47

U>1u << 47 = 0
U>А что ты хотел?

В том-то и фишка, что 1<<47 (с константами) дает ноль, а с переменными — 32768:
int sh = 47;
int v = 1 << sh; // 32768

Более того, значение v зависит от опций оптимизатора (сейчас проверил). Если он сумеет вывести константу, будет 0. Если честно сгенерирует инструкции, то 32768.

В общем, куда ни ткни, везде UB (калабур).
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Сдвиги
От: trophim Россия  
Дата: 16.07.06 18:20
Оценка: 3 (1)
Есть такая особенность у операции сдвига в процессорах x86 — он берет только младшие 5 бит (в общем типа сам накладывает маску 0x1F) от величины сдвига, а потом двигает значение. Я очень долго удивлялся когда сдвигал значения в своем классе эмуляции 64-битного числа. Сдвиг в тесте был на 32 бита — по идее регистр (старшая часть) должен был бы очиститься, а фиг — он вообще не изменился, будто операции и не было.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Let it be! — Давайте есть пчелу!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.