Why doesn't bitwise shift work for 32 bits shift? (X>>32)

 

Normally a bitwise shift operation of 32 bits gives 0x00000000, all bits being shifted out of the integer.

I've noticed the code

n = n>>32;
m = m<<32;

lefts n and m variables unchanged though they should be assigned 0x00000000 !

However

n = n>>31>>1;
m = m<<16<<16;
z = z<<31<<31;

does the job and gives 0x00000000.

This is a bug in my opinion.

Attached TEST_Bitwise_Shift.mq4 code sample for testing.

n>>0  : FFFFFFFF
n>>4  : 0FFFFFFF
n>>28 : 0000000F
n>>31 : 00000001
n>>32 : FFFFFFFF
n>>31>>1 : 00000000
n<<0  : FFFFFFFF
n<<4  : FFFFFFF0
n<<28 : F0000000
n<<31 : 80000000
n<<32 : FFFFFFFF
n<<16<<16 : 00000000
n<<31<<31 : 00000000
Files:
 

It is not a bug, it is a rule (the same present in java). If you shift an int, only the lowest 5 bits of the shift-by parameter will be used, and because 32 = 100000, it is 0. In java, there is a long type with 64 bits, and its shifting parameter will be cut to 6 bits.

2012.04.24 08:10:54     TEST_Bitwise_Shift_1 #FDXM2,M5: Alert: n<<36  : FFFFFFF0
2012.04.24 08:10:54     TEST_Bitwise_Shift_1 #FDXM2,M5: Alert: n<<4  : FFFFFFF0
 
erzo:

It is not a bug, it is a rule (the same present in java). If you shift an int, only the lowest 5 bits of the shift-by parameter will be used, and because 32 = 100000, it is 0. In java, there is a long type with 64 bits, and its shifting parameter will be cut to 6 bits.


Sorry, doesn't behave as described in the documentation at https://book.mql4.com/basics/expressions:

The binary representation of x is shifted by y places to the right. This right shift is logical, it means that all places emptied to the left will be filled with zeros.

x = x >> y;

The binary representation of x is shifted by y places to the left; the emptied places to the left will be filled with zeros.

x = x << y;


Where is that "lowest 5 bits of the shift-by parameter" rule stated ?

 
erzo:

It is not a bug, it is a rule (the same present in java). If you shift an int, only the lowest 5 bits of the shift-by parameter will be used, and because 32 = 100000, it is 0. In java, there is a long type with 64 bits, and its shifting parameter will be cut to 6 bits.

What has Java to do with mql4? Its a totally different language, its not even remotely similar.

If it is a rule then it should be mentioned in the documentation. The real reason why this happens is because x86 assembly has *undefined* behavior for shift operands > 31 (some CPUs do it some don't) which is an ugly discontinuity. You have to read the documentation from the manufacturer of the target CPU when writing assembly for a certain CPU. But mql4 is supposed to be a high level language and as such it should

(1) either re-implement it correctly (abstracting away the shortcomings of the underlying machine in all cases)

(2) or explicitly define the allowed range for the operand and and enforce it in order to be able to efficiently translate it to machine code without ever risking to run into the underlying x86 limitation/inconsistency and then document it so that all users who are not fluent in x86 assembly and all its pitfalls will know how it behaves.

It seems Metaquotes chose the latter of these two options but then forgot the most important part, namely to document what they did. Or alternatively (Option 3: "do it like C") they didn't think about all this at all and just reach this ugly x86 nastiness through to the programmer unchanged, assuming the programmer will figure it out on his own.


Java and C# chose option 2 but they clearly document the behavior.

Real high level languages that deserve this name usually implement option 1 and as a result they don't have to write any lengthy explanations and excuses into their documentation, instead everything just works as expected.

 
7bit,
Thank you for correcting me, in java it is really documented, §15.19 (pdf), in C the behavior is undefined, §5.6.7.3 (pdf).
In mql4 I could not find the right documentation (as you mentioned), so better not using shift 32.
 

Thank you erzo and 7bit for your comments.

My MT4 is running on a AMD CPU.

Following AMD documentation General-Purpose and System Instructions, MQL4 behaves as it was using instructions

SHLD Shift Left Double
SHRD Shift Right Double

Those indeed perform a shift_by_bits modulo 32 shift, left or right.

However following AMD documentation Media and Floating-Point Instructions, MMX instructions

PSRLD Packed Shift Right Logical Doublewords
PSLLD Packed Shift Left Logical Doublewords

perform true shift_by_bits shift, left or right, without any modulo as I expect and as mentioned by the MQL4 doc.

Both AMD and MQL4 docs refer to so called "Logical Shift Operators". What does "logical" mean in this context ?

Don't know how Intel processors behave ...

Some housekeeping needed in the MQL4 reference book, don't you think ?

 
  1. The 32 is a processor limitation.


  2. A logical right shift preserves the sign, a binary right shift shifts zeros in, and a rotate moves the LSB to the MSB.

    a logical right shift 1
    1111 1111 1111 1111 1111 1111 1111 1100
    1111 1111 1111 1111 1111 1111 1111 1111 1110

    -4
    -2
    a binary right shift 11111 1111 1111 1111 1111 1111 1111 1100
    0111 1111 1111 1111 1111 1111 1111 1111 1110

    -4
    2,147,483,646

  3. Some housekeeping needed in the MQL4 reference book, don't you think ?
    You just discovered that?
 

Pardon me asking this, is there any use of bitwise operation in trading ?.

:)

 
( ooooooo:) ) Yes, for rising the logic, bitwise or any signs >1 because with 1 can not be made combinations :( (and results could be predictions of possibles ""like mind does")
 
onewithzachy:
Pardon me asking this, is there any use of bitwise operation in trading ?.
From my code day mask
 

WHRoeder, I checked your logical shift definition and, well, I am puzzled. What you say is not verified, look at this:

int n=0xFEDCBA98;
Alert("n              :  "+ n                +"  "+IntegerToHexString(n));
Alert("n>>8           :  "+ n>>8             +"  "+IntegerToHexString(n>>8));
Alert("0xFEDCBA98>>8  :  "+ 0xFEDCBA98>>8    +"  "+IntegerToHexString(0xFEDCBA98>>8));
Alert("n>>-8          :  "+ n>>(-8)          +"  "+IntegerToHexString(n>>(-8)));
Alert("0xFEDCBA98>>-8 :  "+ 0xFEDCBA98>>(-8) +"  "+IntegerToHexString(0xFEDCBA98>>(-8)));

Result:

n              :  -19088744  FEDCBA98
n>>8           :  16702650  00FEDCBA
0xFEDCBA98>>8  :  -74566  FFFEDCBA
n>>-8          :  254  000000FE
0xFEDCBA98>>-8 :  -2  FFFFFFFE

The result shows a logical shift with the literal 0xFEDCBA98 and a binary shift with the variable n containing the same value !!

Could it be because that code runs on a 64bits CPU ?

Can someone please check that code on a 32bits CPU and post the result ?

To note negative shift also works but returns the bits overflow for the revert shift ... with the same logical/binary shift issue for literal/variable.
With the binary shift behavior, it looks like n>>bits works as n>>(32 + MathMod(bits,32)) do, whatever 'bits' sign is. (MathMod result is signed)

Also read next reply ...

Reason: