tac@cs.brown.edu (Theodore A. Camus) (09/06/90)
I would like to do a portable arithmetic right shift in C. Possible solutions and problems : 1) '>>' will _not_ guarantee the result on a signed argument (ANSI & K&R) 2) dividing by a power of 2 will often compile to arithmetic shifts, but only for the smaller powers of 2, not for the full 2^1 - 2^31 shift range. 3) One could test for a negative argument, and if it was negative, use a negate / shift / negate sequence, but there should be a better way. For most compilers, '>>' will differentiate between signed and unsigned arguments, but again K&R and ANSI allows it to be implementation-defined. Any answers ? - Ted CSnet: tac@cs.brown.edu Ted Camus ARPAnet: tac%cs.brown.edu@relay.cs.net Box 1910 CS Dept BITnet: tac@browncs.BITNET Brown University "An ounce of example is worth a pound of theory." Providence, RI 02912
karl@haddock.ima.isc.com (Karl Heuer) (09/06/90)
In article <49160@brunix.UUCP> tac@cs.brown.edu (Theodore A. Camus) writes: >I would like to do a portable arithmetic right shift in C. >Possible solutions and problems : >1) '>>' will _not_ guarantee the result on a signed argument (ANSI & K&R) True. I've used a machine where ">>" was logical shift even on signed int. >2) dividing by a power of 2 will often compile to arithmetic shifts, but > only for the smaller powers of 2, not for the full 2^1 - 2^31 shift range. If negative divide rounds toward zero (as is very common but not required), you don't even get the right answer: -1 / 2 == 0, -1 >> 1 = -1. (Check for a compiler bug here!) To do this portably you'd have to mask off the low bits before you divide. >3) One could test for a negative argument, and if it was negative, use a > negate / shift / negate sequence, but there should be a better way. Well, how about: #include <limits.h> #define INT_BIT (CHAR_BIT*sizeof(int)) #define INT_HIGHBIT ((unsigned)1 << (INT_BIT-1)) unsigned int ashr(unsigned int i, int nb) { if (~3 >> 1 == ~1) { return ((unsigned int)((signed int)i >> nb)); } else { #if USE_BRANCH return ((i & INT_HIGHBIT) == 0 ? i >> nb : (i >> nb) | (~0 << (INT_BIT-nb))); #else return ((i >> nb) - ((i & INT_HIGHBIT) >> (nb-1))); #endif } } This uses ">>" if it's available (you could test for it with the preprocessor instead of the compiler, if you trust them to be using the same arithmetic), else it will use either a branching test or a straight-line hack. The latter may be faster if a branch would screw up the instruction pipeline. The argument is declared `unsigned int' so as to produce consistent results without depending on two's complement non-overflowing arithmetic. I'm assuming the specification is to propagate the high-order bit of a bitmap, regardless of the integer value it happens to represent. (Have you considered what you want it to do on a one's complement or sign-magnitude machine?) Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint
henry@zoo.toronto.edu (Henry Spencer) (09/06/90)
In article <49160@brunix.UUCP> tac@cs.brown.edu (Theodore A. Camus) writes: >I would like to do a portable arithmetic right shift in C. In a word (well, three words): can't be done. -- TCP/IP: handling tomorrow's loads today| Henry Spencer at U of Toronto Zoology OSI: handling yesterday's loads someday| henry@zoo.toronto.edu utzoo!henry
throopw@sheol.UUCP (Wayne Throop) (09/10/90)
> From: henry@zoo.toronto.edu (Henry Spencer) >> tac@cs.brown.edu (Theodore A. Camus) >>I would like to do a portable arithmetic right shift in C. >In a word (well, three words): can't be done. Well, I can phrase the answer in only TWO words: im possible. -- Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org