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