ka@cs.washington.edu (Kenneth Almquist) (05/03/90)
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. The following solution works on all machines I
know of:
unsigned
my_abs(int a) {
if (a >= 0)
return a;
else
return -a;
}
Does anyone know of machines on which this will fail? Can anyone suggest
a more portable implementation?
Kenneth Almquist
c60c-3cf@e260-3c.berkeley.edu (Dan Kogai) (05/04/90)
In article <11679@june.cs.washington.edu> ka@cs.washington.edu (Kenneth Almquist) writes: >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. The following solution works on all machines I >know of: > > unsigned > my_abs(int a) { > if (a >= 0) > return a; > else > return -a; > } > >Does anyone know of machines on which this will fail? Can anyone suggest >a more portable implementation? > Kenneth Almquist What's wrong with using a macro like the following #define abs(x) (((x) >= 0) ? (x) : -(x)) It should cause no problem if x is char|int|long and signed and abs(x) itself is unneccesary if the type is unsigned. And by using a macro you save one jump and makes your code faster. Even though you need to stay away from macro your code could be as simple as long abs(long x){ return ((x >= 0) ? x: -x); } I made it fnc returning long and takes 1 long arg because C has a copability of automatically aligning char|int|long appropriately. You must be careful though, when the conversion is from larger type to smaller such as long to char. Usually upper bits are truncated but sign extention may cause some problem. Remember it doesn't work in general if the variable is double|float use fabs(x) if it's floating point variable. But I think it's a macro, too, that looks like #define fabs(x) (double)(((double)(x) >= 0.0 ? (x) : (-x)) I just took a look at /usr/include/math.h and it was even more concice: #define _abs(x) (x < 0 ? (-x): (x)) In general your code looks too much like Pascal. It's C and when in C you'd better off program like C. Happy coding! --- ################## Dan The "I grok therefore I am God" Man + ____ __ __ + (Aka Dan Kogai) + ||__||__| + E-mail: dankg@ocf.berkeley.edu + ____| ______ + Voice: 415-549-6111 + | |__|__| + USnail: 1730 Laloma Berkeley, CA 94709 + |___ |__|__| + U.S.A + |____|____ + Disclaimer: I'd rather be blackmailed for my long .sig + \_| | + than give up my cool name in Kanji. And my + <- THE MAN -> + citizenship of People's Republic o' Berkeley ################## has nothing 2 do w/ whatever I post, ThanQ.
msb@sq.sq.com (Mark Brader) (05/05/90)
[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.
dsrekml@prism.gatech.EDU (Mike Mitten) (05/06/90)
In article <1990May4.121950.22726@agate.berkeley.edu> c60c-3cf@e260-3c.berkeley.edu (Dan Kogai) writes: >What's wrong with using a macro like the following > >#define abs(x) (((x) >= 0) ? (x) : -(x)) ... > I just took a look at /usr/include/math.h and it was even more >concice: > >#define _abs(x) (x < 0 ? (-x): (x)) Won't both of these macros blow up if x is a function such as: y = abs(foo(bar)); or y = _abs(foo(bar)); Shalom, -Mike Mike Mitten -- Irony is the spice of life. -- WREK Radio, Georgia Tech, Atlanta GA, 30332 (404) 894-2468 ARPA: dsrekml@prism.gatech.edu uucp: ...!{allegra,amd,hplabs,seismo,ut-ngp}!gatech!prism!dsrekml | CAUTION: The above is output of experimental software simulating the | | result of 1000 monkeys typing on 1000 typewriters for 1000 years. |
oesterle@wpi.wpi.edu (Shawn H. Oesterle) (05/06/90)
In article <8977@hydra.gatech.EDU> dsrekml@prism.gatech.EDU (Mike Mitten) writes: >In article <1990May4.121950.22726@agate.berkeley.edu> c60c-3cf@e260-3c.berkeley.edu (Dan Kogai) writes: >>What's wrong with using a macro like the following >> >>#define abs(x) (((x) >= 0) ? (x) : -(x)) >Won't both of these macros blow up if x is a function such as: > > y = abs(foo(bar)); > >or > > y = _abs(foo(bar)); > That's right. That is one thing which I dislike about macros in C. For example, take the following function which finds the height of a binary tree. #define max(a,b) (((a) > (b)) ? (a) : (b)) /* This function returns the height in O(n) time (n is the number of nodes) */ int TreeHeight(const TREE * tree) { if(tree != NULL) { int x = TreeHeight(tree->left), y = TreeHeight(tree->right); return(1 + max(x,y)); } else { return(-1); } } /* because the 'max' macro has functions as its arguments, TreeHeight() is changed from a linear time complexity function to an exponential time complexity function! */ int TreeHeight(const TREE * tree) { if(tree != NULL) { return(1 + max(TreeHeight(tree->left), TreeHeight(tree->right))); } else { return(-1); } } BTW, C++ resolves this problem with the 'inline' keyword for function declarations. -- Shawn Oesterle { oesterle@wpi.wpi.edu } antherea "...I tend to think that there are only two kinds of people in the world anyway: those that oversimplify and those that don't." -Jim Northrup
bph@buengc.BU.EDU (Blair P. Houghton) (05/07/90)
In article <12710@wpi.wpi.edu> oesterle@wpi.wpi.edu (Shawn H. Oesterle) writes: >In article <8977@hydra.gatech.EDU> dsrekml@prism.gatech.EDU (Mike Mitten) >writes: >>In article <1990May4.121950.22726@agate.berkeley.edu> >>c60c-3cf@e260-3c.berkeley.edu (Dan Kogai) writes: >>>What's wrong with using a macro like the following >>>#define abs(x) (((x) >= 0) ? (x) : -(x)) >>Won't both of these macros blow up if x is a function such as: >> y = abs(foo(bar)); > >That's right. That is one thing which I dislike about macros in C. Macros are a textual facility, not a functional one. --Blair "If you want the assembler, you know where to find it. (cf. D. Ritchie.; or was it B. Kernighan?)"
mcdaniel@amara.uucp (Tim McDaniel) (05/08/90)
c60c-3cf@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@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@adi.com ((else mcdaniel%amara.uucp@mailgw.cc.umich.edu)) UUCP: {uunet,sharkey}!amara!mcdaniel
ken@cs.rochester.edu (Ken Yap) (05/09/90)
|? 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. I came across a bug that was caused by exactly this problem. In a boundary case, a fp division by zero happened giving negative infinity silently (another story). This was assigned to an integer. The problem was that the author decided to do his own conversion to a string instead of using printf or sprintf. The code said, in effect: if (x < 0) print leading - x = -x proceed as in positive case Problem is, -maxint is -maxint, so the program printed a minus sign and nothing else. Since this was a converter to Postscript, this bare minus sign caused the printer to barf, aborting the job. Moral of story? Make up your own.