Path: utzoo!utgpu!news-server.csri.toronto.edu!clyde.concordia.ca!uunet!jtsv16!geac!sq!msb From: msb@sq.sq.com (Mark Brader) Newsgroups: comp.lang.c Subject: Re: Computing the absolute value of an integer Summary: unsigned my_abs(int a) {if (a>=0) return a; else return -(unsigned)a;} Message-ID: <1990May5.011945.9284@sq.sq.com> Date: 5 May 90 01:19:45 GMT References: <11679@june.cs.washington.edu> <1990May4.121950.22726@agate.berkeley.edu> Organization: SoftQuad Inc., Toronto Canada Lines: 78 [Whitespace in the examples has been compressed for posting purposes.] ? 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. Which in turn means that the operation "-a" on a variable a of any signed integer type is capable of causing overflow, which is allowed to cause the program to abort. You are right to be worried. ? unsigned my_abs(int a) { if (a >= 0) return a; else return -a; } ? Does anyone know of machines on which this will fail? Unfortunately, in this code the negation occurs before the conversion to unsigned, so it can fail on a machine that checks for int overflow. (I don't know of any specific ones, but I'm assured that they exist.) The solution is as simple as reversing the operations: change the final "-a" to "-(unsigned)a". This works because all operations on unsigned integer types, including conversion to them, are defined in modular arithmetic. If M is 2 to the power of the number of bits used for the unsigned type, and the value of "a" is initially negative, then the value of (unsigned)a is M+a, and -(unsigned)a is M-(M+a) which is -a as desired. (In the previous sentence the expressions involving M are written in the notation of mathematics, not C.) > What's wrong with using a macro like the following > #define abs(x) (((x) >= 0) ? (x) : -(x)) Use of a macro does have advantages of avoiding the need to specify the type of its argument, and of speed in the case where its argument is a simple variable rather than a complicated expression. However, it doesn't address the stated problem, which is that -x can overflow! > long abs(long x){ > return ((x >= 0) ? x: -x); > } > I made it fnc returning long and takes 1 long arg ... The use of ?: notation versus if-else is a purely stylistic point; some like one and some like the other. (I like one.) It should have no noticeable effect on the generated code. The use of "long", however, does show another problem with the original example: as written, it does not generalize to longs. It could of course have been written for longs in the first place. Retaining the original style, it would then become: unsigned long my_labs(long a) { if (a >= 0) return a; else return -(unsigned long)a; } As a macro, it could be written #define my_iabs(x) (((x) >= 0) ? (x) : -(unsigned long)(x)) which will work for any *integer* type, but not for floating types. With an insufficiently clever compiler it may also generate unnecessary widening and narrowing operations, if long is wider than int. > I just took a look at /usr/include/math.h and it was even more concice: > #define _abs(x) (x < 0 ? (-x): (x)) Concise, but wrong. The above gives the wrong answer for _abs(z+1). I'm glad /usr/include/math.h on the system *I* use doesn't have that! > In general your code looks too much like Pascal. In general people who write only to criticize the style of someone else's code, while missing important issues relating to the content, do not make a useful contribution by posting to this newsgroup. -- Mark Brader "This is Programming as a True Art Form, SoftQuad Inc., Toronto where style is more important utzoo!sq!msb, msb@sq.com than correctness..." -- Pontus Hedman This article is in the public domain.