0

From this link here to compute the sign of an integer

int v;      // we want to find the sign of v
int sign;   // the result goes here 

sign = v >> (sizeof(int) * CHAR_BIT - 1);
// CHAR_BIT is the number of bits per byte (normally 8)

If I understand this correctly, if sizeof(int) = 4 bytes => 32 bits

MSB or 32nd bit is reserved for the sign. So, we right shift by (sizeof(int) * CHAR_BIT - 1) and all the bits fall off from the right side, leaving only the previous MSB at index 0. If MSB is 1 => v is negative otherwise it is positive.

Is my understanding correct ?

If so, then can someone please explain me what author meant here by this approach being architecture specific:

This trick works because when signed integers are shifted right, the value of the far left bit is copied to the other bits. The far left bit is 1 when the value is negative and 0 otherwise; all 1 bits gives -1. Unfortunately, this behavior is architecture-specific.

How will this be any different for a 32 bit or 64 bit architecture ?

brainydexter
  • 19,826
  • 28
  • 77
  • 115
  • 2
    64 bit is no different but maybe the author meant that twos complement may not be universal (although I don't know of any computer system that does it differently) - http://en.wikipedia.org/wiki/Signed_number_representation – Roger Rowland Jun 01 '13 at 07:34
  • @RogerRowland Can you please elaborate on that ? – brainydexter Jun 01 '13 at 07:37
  • *Little endian* vs *big endian* is the issue - MSB might be on some architectures on the right side. http://en.wikipedia.org/wiki/Endianness#Endianness_and_operating_systems_on_architectures – Pavel Horal Jun 01 '13 at 07:55
  • The part of your quote *"The far left bit is 1 when the value is negative and 0 otherwise; all 1 bits gives -1"* is only true for twos complement. Also @PavelHoral makes the point that *"far left"* may not always be in the same place. – Roger Rowland Jun 01 '13 at 08:00
  • I think the author is talking more about CPU type and not bit size, e.g. powerpc, arm, etc... The effect of ">>" is implementation defined, and not all CPUs provide the same, single-instruction shift behavior with regards to shifting a negative value, so you can't count on it beyond x86-32/64. – kfsone Jun 01 '13 at 08:00
  • @PavelHoral I don't think that matters here. If you were to split the integer into an array of `char`, then look at the MS char, *then* it would make a difference. But not from applying a bit shift to a single `int`. – juanchopanza Jun 01 '13 at 08:02
  • 1
    See the last paragraph of this: http://msdn.microsoft.com/en-us/library/336xbhcz.aspx – kfsone Jun 01 '13 at 08:03
  • See also the last paragraph of [the link you posted](http://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign) which explains exactly what is goind on. – juanchopanza Jun 01 '13 at 08:08
  • @juanchopanza you are right, endianness does not matter. http://stackoverflow.com/questions/4009885/arithmetic-bit-shift-on-a-signed-integer http://stackoverflow.com/questions/1041554/bitwise-operators-and-endianness – Pavel Horal Jun 01 '13 at 08:12
  • @PavelHoral: Endianness is the way that values are stored on memory, it does NOT affect how values are computed. The problem above is because right shift implementation depends on compiler, and some architectures may not use a encoding that the MSB is the sign bit such as 2's complement, 1's complement... – phuclv Aug 28 '13 at 06:34

2 Answers2

3

I believe that the "architecture dependent" is based on what sorts of shift operations the processor supports. x86 (16, 32 and 64-bit modes) support an "arithmetic shift" and "logical shift". The arithmetic variant copies the top bit of the shifted value down along as it shifts, the logical shift does not, it fills with zeros.

However, to avoid the compiler having to generate code along the lines of:

int temp = (1 << 31) & v; 
sign = v;
for(i = 0; i < 31; i++)
  sign = temp | (sign >> 1);

to avoid the problem of an architecture that ONLY has the "logical" shift.

Most architectures have both variations, but there are processors that don't. (Sorry, I can't find a reference that shows which processors has and hasn't got two variants of shift).

There may also be issues with 64-bit machines that can't distinguish between 64 and 32 bit shifts, and thus shift in the upper 32 bits from the number, rather than the lesser sign bit. Not sure if such processors exist or not.

The other part is of course to determine if the sign for -0 in a ones complement is actually a "0" or "-1" result in terms of sign. This really depends on what you are trying to do.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Even if an architecture only had a logical right shift, `x>>n` could be computed as `x < 0 ? ~(int)(~(unsigned)x >> n): x >> n`. – supercat Jul 09 '14 at 18:11
0

It's "architecture-dependent" because in C++ the effect of a right shift of a negative value is implementation defined (in C it produces undefined behavior). That, in turn, means that you cannot rely on the result unless you've read and understood your compiler's documentation of what it does. Personally, I'd trust the compiler to generate appropriate code for v < 0 ? -1 : 0.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165