Can anyone explain to me why this works...? (Signed integer data)

Continuing the discussion from MODBUS 16bit SIGNED INTEGER:

The post above, 2020 demonstrates a very compact way to read in signed integer values from a Modbus device.

I understand what they are and how they are stored/represented from a bitwise perspective but I don't think I understand why this, msg.payload[i] = (msg.payload[i] << 16) >> 16, method works.

I thought that a negative number was stored in 2's compliment, with the MSb indicating a negative value. I cant get my head around why shifting / rotating, I am assuming <</>> are rotating, the bits is doing anything useful.
Having run this code it seems to work and is easier to implement than an operation on the buffer array using IEEE functions.

Can anyone explain to me what I am missing?
I am feeling uncomfortably ignorant here and cant help thinking that there may be limitations to doing things this way.

They are shift, not rotate. The shift left 16 moves the 16 bit value into the upper half of the 32 bit value. The shift right is a signed shift, so the shift right fills the upper word with the ms bit, which is the sign bit.

Ah... I hadn't considered the new value, or any value for that matter being a 32 bit word, which is why I thought they must have been rotates in order to not loose data.

My number/result looks correct so it clearly works and I am most grateful, I just don't understand why it works.

I have to assume that the value I am getting from the Modbus read is in 2's compliment when it is negative but with the sign bit at [15]
Shifting left moves everything left so the sign bit ends up at [31] and shifting it back right again leaves the sign bit set but shifts [16]-[30] back down to [0]-[14]

Is that correct?
If so it is not something I have come across before but then I typically work with PLC's which are usually 16 bit unless you use a double or float and explicitly convert which is handled by a function.

Sorry if I am being vague... Whatever my level of understanding, or lack thereof, I appreciate the help.

What is the 'but' in there? You are doing a sixteen bit read, so the sign bit can only be bit 15.

The JavaScript shift operators are defined to work on 32 bits, so when the operator is used the value is increased to 32 bit before shifting. After the shift the value is negative but 2^16 times too big. The right shift, shifts right but shifts in whatever is the current sign bit, so it shifts in 1s if the value is negative, or 0s if positive. Look up the definitions of arithmetic and logical shift if you need more information.

1 Like

That is a great explanation thanks... I now fully understand what is going on and why.
I had no idea that a shift right would shift in anything but 0's which is why I didn't look it up and also didn't understand where the 1 in [31] was coming from.
You are a star, thanks so much.

I am going to test this in a PLC because I am reasonably sure that it will always shift in 0's.
This just go's to show that stuff I'd thought I had a handle on for a while can still make me look silly.

Is there much variation between languages with this stuff, would VB or C variants be likely handle shifting the same way, or is this an example of something I should be checking for every platform/IDE?
BTW I am not asking you to check any version of VB or C, just trying to get a handle on the extent of my ignorance :slight_smile: , I will go and look, now I know I need to.

As I have almost always been working in a PLC when doing this kind of stuff, and therefore thinking in terms blocks of memory and endianness, I have never needed to look under the hood.
Sure I shift bits about to access data in a specific way, pulling out BCD timestamps or processing strings for example, but generally numeric conversion is handled by a function and I cant think of an occasion where an implicit conversion has tripped done anything I wasn't expecting.

Thanks again, great to learn something fundamental that I probably should have known in the first place.

Most languages (if not all) support signed and unsigned shift. In JavaScript the >>> operator does an unsigned shift, so zeros are shifted in. You should not need to check individual devices, it should be defined by the language being used.

1 Like

That's good to know, cant quite work out why this hadn't tripped me up before, but I know now.
You are a start, thanks for taking the time.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.