Computing the absolute value of an integer

Tim McDaniel mcdaniel at amara.uucp
Tue May 8 05:41:04 AEST 1990


c60c-3cf at e260-3c.berkeley.edu (Dan Kogai) writes:
   >What's wrong with using a macro like the following
   >#define abs(x) (((x) >= 0) ? (x) : -(x))
   {et cetera}

One problem is the use of a macro.  Why optimize if "abs" is not in
the critical path for your program?  In many dubuggers, you can't work
with a macro.  If the argument x has a side effect, as in
   j = abs(i++);
it would be evaluated twice.  You can't take the address of a macro.

"What's [really] wrong" is in the original article by
ka at cs.washington.edu (Kenneth Almquist):
   > I want a function that will compute the absolute value of any
   > integer that can be stored in a variable of type int.  What makes
   > this difficult is that on some machines the absolute value of the
                            ^^ ^^^^ ^^^^^^^^ ^^^ ^^^^^^^^ ^^^^^ ^^ ^^^
   > most negative integer will not fit in an int.
     ^^^^ ^^^^^^^^ ^^^^^^^ ^^^^ ^^^ ^^^ ^^ ^^ ^^^

E.g. suppose we have a two's-complement machine where ints are 2 bytes
long.  Then ints range from -32768 to 32767 inclusive.  However, note
that 32768 is NOT in the valid range, so
   int x = -32768;
   -x;
may overflow.  ANSI C does not guarantee what happens when a signed
integer value overflows.  A conforming implementation may validly send
220 volts AC at 100 amps thru your terminal upon overflow.

Kenneth continues (edited):
   > The following solution works on all machines I know of:
   >	unsigned int my_abs(int a) {
   >	      if (a >= 0)
   >		    return a;
   >	      else
   >		    return -a;
   >	}
   > Does anyone know of machines on which this will fail?

In practice, no.  To explain: this code depends on -INT_MIN ==
INT_MIN, which is true on most machines.  (Two's-complement negation
is "flip the bits and add one"; with a 2-byte int, INT_MIN is 8000
hex.  Flip (invert) the bits to get 7fff and add one, getting 8000
again, if integer overflow is ignored, and it usually is.)  ANSI C
says that INT_MIN assigned to an unsigned int on a two's-complement
machine will produce -INT_MIN.

   > Can anyone suggest a more portable implementation?

How about
   	unsigned int my_abs(int a) {
   	      if (a >= 0)
   		    return (unsigned)a;
   	      else
   		    return -(unsigned)a;
   	}
?  Casting signed to unsigned is well-defined under ANSI C, and ought
to work the same under pre-ANSI.  Ditto for "-" on an unsigned value.

The first cast is not strictly necessary, but I use two rules:
- NEVER mix signed and unsigned values, unless using explicit casts.
  (And then make sure you know what'll happen.)
- ALWAYS REMEMBER: sizeof may be unsigned!
(The second one is harder to remember.)  Failing to follow these rules
can lead to extremely subtle bugs.

--
Tim McDaniel
Applied Dynamics International, Ann Arbor, MI
Internet: mcdaniel at adi.com ((else mcdaniel%amara.uucp at mailgw.cc.umich.edu))
UUCP: {uunet,sharkey}!amara!mcdaniel



More information about the Comp.lang.c mailing list