kremer@cs.odu.edu (Lloyd Kremer) (03/31/89)
Can a double be used directly as a boolean? A few years ago, when DOS C compilers were in their infancy, I was hand optimizing the code of one of our products so that it would still fit in the standard 256K of an IBM XT. (I said it was a few years ago :-) ) The optimizing in the compilers I was using was minimal, and I found that substitutions such as 'if(i)' instead of 'if(i != 0)', and 'if(!n)' in place of 'if(n == 0)' produced smaller code for integral types. When I tried to extend this technique to floating types where the potential gains were even greater (floating point comparisons were expensively implemented), the code broke completely. For example, if I had double a, b; . . if ( a && b ) /* meaning if(a != 0.0 && b != 0.0) */ statement; the entire code fragment silently miscompiled. But if I changed the condition to ( !!a && !!b ) or to ( !( !a || !b ) ) it compiled fine! Even K&R 1 states that the ! operator can be applied to any type, so I believe the latter examples are required to work, but what about the first one? Would these compilers be officially broken by today's standards? Pray, what sayeth the pANS? If it means anything, doubles were implemented as IEEE 754 64-bit reals, where 0.0 was represented by a zero-bit pattern. Maybe that's the only reason the latter cases worked! :-) Lloyd Kremer Brooks Financial Systems {uunet,sun,...}!xanth!brooks!lloyd
bowles@eris.berkeley.edu (Jeff A. Bowles) (03/31/89)
In article <8269@xanth.cs.odu.edu> kremer@cs.odu.edu (Lloyd Kremer) writes: > > Can a double be used directly as a boolean? I don't have a copy of ANSI, but you don't need it for part of the answer: "Are you really, absolutely sure you wanna compare a floating-point number to ANYTHING else, just to see if the numbers are EQUAL?" If you're interested in if a floating-point variable is equal to another floating-point variable, or if it's equal to zero, well, umm, think very carefully about whether you're getting ready to shoot yourself in the foot. It's the same type of thing that makes 3*(1.0/3.0) not equal to 1.0.... Jeff Bowles ps. Comparing to some small amount, like "abs(x) < 0.00001", doesn't do a lot better when the calculations are smaller than that, either.
guy@auspex.auspex.com (Guy Harris) (03/31/89)
> The optimizing in the compilers I was using was minimal, and I > found that substitutions such as 'if(i)' instead of 'if(i != 0)', > and 'if(!n)' in place of 'if(n == 0)' produced smaller code for > integral types. When I tried to extend this technique to floating > types where the potential gains were even greater (floating point > comparisons were expensively implemented), the code broke completely. Proof positive that lack of memory sometimes produces less-than-wonderful compilers - I would hope any *modern* non-toy compiler would not give you any better code for "if (i)" than it gives for "if (i != 0)". > Pray, what sayeth the pANS? 3.1.2.5 Types ... Integral and floating types are collectively called "arithmetic types". Arithmetic types and pointer types are collectively called "scalar types". 3.2.1.5 Usual arithmetic conversions Many binary operators that expect operands of arithmetic type cause conversions and yield result types in a similar way. ... This pattern is called the "usual arithmetic conversions": First, if either operand has type "long double", the other operand is converted to "long double". Otherwise, if either operand has type "double", the other operand is converted to "double". Otherwise, if either operand has type "float", the other operand is converted to "float". 3.3.8 Relational operators ... Semantics If both of the operands have arithmetic type, the usual arithmetic conversions are performed. 3.3.9 Equality operators ... Semantics The == (equal to) and the != (not equal to) operators are analogous to the relational operators except for their lower precedence. Where the operands have types and values suitable for the relational operators, the semantics detailed in section 3.3.8 apply. 3.3.3.3 Unary arithmetic operators Constraints The operand ... of the ! opearator (shall have) scalar type. Semantics The result of the logical negation operator ! is 0 if the value of its operand compares unequal to 0, 1 if the value of its operand compares equal to 0. The result has type "int". The expression "!E" is equivalent to "(0==E)". 3.3.13 Logical AND operator Constraints Each of the operands shall have scalar type. Semantics The && operator shall yield 1 if both of its operands compare unequal to 0, otherwise it yields 0. The result has type "int". 3.3.14 Logical OR operator (same thing, only it yields 1 if *either* of its operands compare unequal to 0) 3.3.15 Conditional operator Constraints The first operand shall have scalar type. ... Semantics The first operand is evalueate; there is a sequence point after its evaluation. The second operand is evaluated only if the first operand compares unequal to 0; the third operand is evaluated only if the first compares equal to 0; the value of the second or third operand (whichever is evaluated) is the result. 3.6.4.1 The "if" statement Constraints The controlling expression of an "if" statement shall have scalar type. Semantics In both forms, the first substatement is executed if the expression compares unequal to 0. When you combine all that stuff, it dictates, among other things, that double d; if (d) had better be equivalent to double d; if (d != 0.0) or if (d != 0) given that the "0" in the latter case is converted to "0.0", and that double a, b; . . if ( a && b ) /* meaning if(a != 0.0 && b != 0.0) */ statement; had better be interpreted precisely the way you state it. > If it means anything, doubles were implemented as IEEE 754 > 64-bit reals, where 0.0 was represented by a zero-bit pattern. > Maybe that's the only reason the latter cases worked! :-) One hopes that if there ever were compilers dumb enough to think that the "if" statement worked by testing whether the all the bits of the value in the parentheses were zero, those compilers are now toast and their authors have repented of their errors.
henry@utzoo.uucp (Henry Spencer) (04/01/89)
In article <8269@xanth.cs.odu.edu> kremer@cs.odu.edu (Lloyd Kremer) writes: > Can a double be used directly as a boolean? Any "scalar" type -- an arithmetic or pointer type -- can. > The optimizing in the compilers I was using was minimal, and I > found that substitutions such as 'if(i)' instead of 'if(i != 0)', > and 'if(!n)' in place of 'if(n == 0)' produced smaller code for > integral types... Talk about lazy compilers... > [compilers that balk at doing implicit comparison against 0 for double] > ... Would these compilers be officially broken by today's standards? Yes. They've been officially broken by the prevailing de-facto standards all along, as well. -- Welcome to Mars! Your | Henry Spencer at U of Toronto Zoology passport and visa, comrade? | uunet!attcan!utzoo!henry henry@zoo.toronto.edu