Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watnot!watmath!clyde!rutgers!mit-eddie!uw-beaver!tektronix!reed!psu-cs!omepd!jimv From: jimv@omepd.UUCP Newsgroups: comp.lang.c Subject: Re: C and Floating Point (LONG) Message-ID: <542@omepd> Date: Tue, 7-Apr-87 03:45:56 EST Article-I.D.: omepd.542 Posted: Tue Apr 7 03:45:56 1987 Date-Received: Sat, 11-Apr-87 00:18:45 EST References: <15958@sun.uucp> <5716@brl-smoke.ARPA> <532@omepd> <5725@brl-smoke.ARPA> Reply-To: jimv@omepd.UUCP (Jim Valerio) Organization: Intel Corp., Hillsboro Lines: 113 Summary: IEEE floating-point is good stuff Doug, without intending to beat this subject to death, I just want to point out how the IEEE standard addresses some of the problems you describe with floating-point arithmetic. I don't agree with your statement that the IEEE standard does not address the problem that most programmers are insufficiently aware of pitfalls in floating-point arithmetic. I grant that the IEEE standard won't make the programmers learn more than they choose to learn, but I maintain that the default behavior will deliver correct answers more often, and will also deliver wrong answers less often, than today's typical non-IEEE implementation. In general, the purpose of what you call ``extended "values"'' is to allow the computation to continue in those cases where the programmer didn't provide for better handling of the exceptional situation. By examining the results afterwards, the user can decide whether the answer makes any sense. Sometimes these exceptional conditions don't contaminate the overall computation, and sometimes they do. The rules for the results of operations on infinities and NaNs were defined very carefully to guarantee finite values are returned only when everything worked right. In particular, infinities have 2 important uses. First, a divide-by-zero event can now return an exact result: infinity. This is very useful for computations of quotients of products, or for continued fraction evaluations. This is not to say that an infinity is an absolutely necessary representation to make these sorts of calculations well defined, but it does make many calculations "just work". The standard illustrative exercise is: name the simple refinement to computing the following function to make it compute the correct value on machines where division by zero is fatal: R(x) := 7 - 3/(x - 2 - 1/(x - 7 + 10/(x - 2 - 2/(x - 3)))) The answer is "obvious" once you see it, but very few people do. (Hint 1: pick what precision your intermediate expressions are calculated in. Hint 2: understand why explicit numbers for the constant values are required.) The other use for infinities is for overflows. They do make sense when an overflow occurs, if you look at floating-point arithmetic as computing the exact result of the operation for it's operands and then rounding that result to fit into the destination format. With infinities represented in floating-point numbers, every real number has a single, correct representation (given a particular rounding rule). What's the alternative if infinities didn't exist and the programmer neglected to take overflow into account? Generally the program is aborted and any chance of useful data coming out is gone, even if that particular part of the calculation turned out to not affect the final result. And, since none of the default responses are forced, an IEEE implementation lets the programmer provide explicit actions on exactly those exceptional conditions that he knows how to handle. Sounds like a win-win situation to me. Honestly, I don't understand why you have a problem with infinities (or NaNs). And while I'm responding, here are a few comments on what you recently wrote. Regarding simple equality checks against division by zero: >For the most important example, simply checking that the divisor is non- >zero does NOT guarantee against overflow in the subsequent division. >Truly robust floating-point code must be much more carefully crafted >than that. Granted that overflow is not prevented by checks for zero, but division by zero is. So why do they make this explicit check? I could come up with a number of guesses without looking at the code, only one of which is that they failed to take overflow into account. For example, without looking carefully at the code, I can't tell if some portion of the numbers are guaranteed to be in range and consequently won't overflow. I just made a 3 minute scan over the code in Spice3 which does an explicit equality comparison with 0.0, and I see three categories of what is being done: (1) efficiency (skipping a whole bunch of calculations where a multiplier is zero), (2) avoiding divide-by-zero, and (3) other things that were not immediately obvious. Some of the code in category (3) looked dubious to me, but other parts looked pretty safe. Not knowing exactly what is being computed, I don't know if all the operations in (3) were safe or not. (I wouldn't bet on it. :-)) Regarding: >A simple list of how floating == has been used (e.g. in Spice) is >not the same thing as a lists of contexts in which its use is safe. Very true. It was sloppy of me to suggest that. However, the list of examples pulled from Spice3 and elsewhere did serve the purpose of showing situations where == could very well be the right operation for the job. >I've been burned too many times by floating-point computations that >misbehave when pushed near their extremes. Unfortunately I can't >offer a simple recipe for avoiding such problems, other than to >know what can go wrong and to think carefully when designing the >algorithm. I agree that no simple recipe exists to avoid all floating-point problems. I also agree that floating-point doesn't behave well when pushed near it's extremes. So what? Neither does integer arithmetic. In both cases, it's important to try to keep the problem domain well bounded, or to have explicit rules to handle the boundary cases. And that's exactly what the IEEE standard provides for. -- Jim Valerio {verdix,intelca!mipos3}!omepd!jimv, jimv@omepd.intel.com