Arithmetic right shift examples in my textbook shift in ones when the MSB was zero

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP



Arithmetic right shift examples in my textbook shift in ones when the MSB was zero



I am currently studying assembly, and with it the workings of bitwise operations amongst them shifting. Specifically arithmetic rightshifting is bothering me.



Now, in the book i am reading there are several practice problems, amongst them, I need to perform this operation on a byte consisting of:


0100 0100



Now, seeing as the arithmetic rightshift fills in the value of the most significant bit, it seems to me this should be right shited like so:


00001000



However, the book states that it should be


11101000



That is, 1's are filled in from the left instead of 0's. But wasn't the most significant bit a 0?



well, there's another as well:


0110 0100 >> 3 = 0000 1100



But, apparently that's wrong as well, and it should be:


11101100



Again, I don't get it the most significan't bit value is clearly 0, the one the furthest to the left, yet the solution tells me 1's should be filled in?



so i have a final one here that apparently is correct:


0111 0010 >> 3 = 0000 1110



This is what I would expect. So why aren't these others correct?



Reading assembly is incredibly hard without understanding this, since a lot of multiplication and division is compiled to shift operations.





Which book? (errors in books do happen, and this looks like an error unless there's more context to explain this oddity). Is this supposed to be 2's complement or something else (like one's complement)? Not that that should matter; 0100 0100 is positive in 1's complement as well. Yes, it should shift in zeros to produce a result with the same sign as the initial value.
– Peter Cordes
Aug 10 at 9:16



0100 0100





The book (which i find to be good otherwise) is: Computer Systems a programmers perspective by Randal E. Bryant and David R. O'Hallaron The Practice Problem is 2.16 on page 94, solution is given on page 184
– user3801839
Aug 10 at 13:00





3 Answers
3



No shift will ever fill with 1 when the input's MSB was 0. Note that the reverse isn't true (logical right shift always fills with zero).



If the book doesn't have some extra context, then it's simply an error. That's not a rotate or anything else. Not even 1's complement or sign/magnitude could explain it (because the number is positive in all 3 of those representations).



Arithmetic right shifts in 2's complement shift in copies of the sign bit. (so for example sar eax, 31 broadcasts the sign bit to all bits of the 32-bit register.


sar eax, 31



The sign of an arithmetic shift result will always be the same as the sign of the input.



Logical right shifts always shift in zeros.



Left shifts are the same for logical and arithmetic: they shift in zeros. (x86 has a sal mnemonic, but it's just an alternate name for the same opcode as shl. Later x86 extensions don't bother mentioning an arithmetic left shift, e.g. there's a SIMD pslld (packed-integer shift left logical) but no pslad.)


pslld


pslad



In sign/magnitude, arithmetic left shifts would I guess leave the sign bit untouched. I'm not sure if 1's complement arithmetic left shifts would need any special treatment.



But 2's complement arithmetic left shift is identical to logical. (And identical to add same,same to left shift by 1 aka multiply by 2.)


add same,same





JFYI: Z80 has undocumented (unofficial) "sll" or "sl1" opcode, which does shift left and sets LSB to one. But I can't recall seeing similar oddity for "right" shift.
– Ped7g
Aug 10 at 12:23




A left shift is an increase by the base power a right a decrease. So base 2 (binary) a right shift is a decrease by a power of 2, a left an increase. So right is divide by 2 a left a multiply by 2.



The problem is with the right shift and negative numbers, which means assume twos complement, and also understand the processor doesnt know or care, bits is bits, they mean something to the programmer.



A negative twos complement number means the msbit is set as you clearly understand.



So if I want to divide -2 0b11111110 by 2 to get -1 0b11111111 it would be nice to just right shift that but a logical right shift generally means fill in the top with zeros so 0b11111110 logical shifted right becomes 0b01111111 which is not -1 it is 127. Some processors have an arithmetic right shift which instead of shifting in zeros it duplicates the top bit so 0b11111110 ASR becomes 0b11111111.
Which is the right/desired answer for using a shift to divide -2 / 2.



Likewise understand that 0b11111110 at the same time also represents the value 254 and 254/2 = 127. So an arithmetic right shift gives 255 which is the wrong answer. So far for signed we want to do an ASR for unsigned an LSR.



You are correct, your book is probably wrong or you are only giving us fragments of the book.


0b01000100 ASR is 0b00100010
0b01000100 LSR is 0b00100010
0b10001000 ASR is 0b11000100
0b10001000 LSR 0s 0b01000100



Multibit arithmetic shifts just think of them as multiple single bit or just fill the top with the msbit of the original number



0b10001000 ASR 3 = 0bBBB10001 where B was a 1 so 0b11110001
for LSR the BBBes are zeros 0b00010001



Note that an arithmetic shift LEFT and a logical shift left are the same operation they simply fill in zeros from the right.



Speaking of C, this would be an error on the book, according to the standard:



So, the shifting on unsigned numbers is well-defined, but not for signed numbers (better said, there is no a general definition of).



For completeness sake, the standard says:



The result of E1 >> E2is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined ().



So taking OP's example into account (positive numbers), there is no reason to fill with one's.



Talking about arithmetic shift (let's use x86 as example):



In an arithmetic shift (also referred to as signed shift), like a logical shift, the bits that slide off the end disappear (except for the last, which goes into the carry flag). But in an arithmetic shift, the spaces are filled in such a way to preserve the sign of the number being slid. For this reason, arithmetic shifts are better suited for signed numbers in two's complement format.



The SAR instruction will fill with one's when the number is negative (in order to keep the sign), for instance:


SAR



sar 10110011b, 2 #the result is 11101100b


sar 10110011b, 2 #the result is 11101100b



(shr 10110011b, 2 #the result is 00101100b)


shr 10110011b, 2 #the result is 00101100b



But again, OP's example is talking about positive numbers, so there is no reason to fill with one's.



Summarising, it is possible to fill with one's when a right shift is applied, but not in those cases.






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Firebase Auth - with Email and Password - Check user already registered

Dynamically update html content plain JS

How to determine optimal route across keyboard