ISSUE: Allow IEEE Float Comparisons REVISION HISTORY: Version 1, 14-Jan-94, Rob MacLachlan Version 2, 17-Jan-94, Rob MacLachlan STATUS: RELATED ISSUES: IEEE Float Exception Trapping CATEGORY: Change PROBLEM DESCRIPTION: From the book, chapter 9: [somewhat paraphrased] The methods =, /=, <, >, <= and >= are defined in terms of binary= and binary<. By extending the behavior of binary= and binary<, programs can extend the behavior of the six methods. For the protocol to work, all methods on binary= and binary< must preserve the following properties: Identity: if a == b, then a = b Transitivity: if a < b and b < c, then a < c. Trichotomy: Exactly one of a < b, a = b and b < a always holds (assuming the comparison is defined.) [Footnote] The trichotomy rule does not hold for IEEE floating point comparisons. IEEE requires all comparison operations to return false if one of the operands is a NaN. This means that the generic Dylan equality and magnitude predicates will not be IEEE compliant. As noted, it is impossible to implement IEEE floating point comparison under these constraints (actually, identity doesn't hold either.) IEEE conformant implementations are encouraged to provide a way to cause a run-time trap when NaNs are compared, but IEEE conformant language bindings are forbidden by the standard to trap by default (see "IEEE Float Exception Trapping" issue.) Specific problems: -- Numerically sophisticated programmers who use the capabilities of IEEE floating point can't use generic comparison, and lacking any other IEEE-specific proposal, can't write portable code. -- Any language that rejects portions of the IEEE float standard is likely to itself be rejected, even if those portions are deemed tasteless and useless (as NaNs are by some.) -- Float comparison is undefined. What is meant by saying that "generic comparison will not be IEEE compliant"? If a NaN exists, then the comparison protocol will be quietly violated. Are NaNs greater than all other floats? [which a bitwise comparison would give.] -- Assuming trichotomy with the obvious efficient implementations of float arithmetic would cause several anomalous behaviors when a NaN does appear. For example, transitivity might be violated, and the results would depend on whether a particular call to a comparison function is open-coded or not (see examples.) PROPOSAL: Add generic functions: binary> object1 object2 => boolean [generic function] binary>= object1 object2 => boolean [generic function] binary<= object1 object2 => boolean [generic function] binary/= object1 object2 => boolean [generic function] Called by the corresponding n-ary methods to actually do comparisons. Add standard methods: binary> real real => boolean [g.f. method] binary>= real real => boolean [g.f. method] binary<= real real => boolean [g.f. method] binary/= object object => boolean [g.f. method] For the specified argument classes, implement these comparisons in terms of binary< and binary=, implicitly assuming that trichotomy holds. binary> float float => boolean [g.f. method] binary>= float float => boolean [g.f. method] binary<= float float => boolean [g.f. method] binary/= float float => boolean [g.f. method] Floating point comparison probably won't preserve trichotomy and identity, so float specific comparison methods must be defined on these functions. RATIONALE: This proposal does not require support of NaN's in Dylan, but changes the rules so that an implementation can support the full IEEE functionality in a consistent way (perhaps as a loadable library) if it chooses to. We feel that this is more important than the small amount of simplicity that is lost in the binary comparisons. These methods allow float comparison to have different semantics, without requiring extensions of numbers (or for =, of arbitrary objects) to define methods on all the comparison operations. What was the rationale for defining Dylan as it is in the book? Why defy one of the most successful, popular and precise computer standards in existence? I can only guess: 1] The trichotomy rule holds in "naive arithmetic" and is thus easier to understand. [But exceptions can be ignored in simple presentations.] 2] The restrictive contract for < and = is useful in writing generic code that depends on ordering relationships. 3] Basing everything on < and = makes it simpler to define new kinds of numbers. (which can be had by defining methods that delegate <=, /=, etc., to < and =.) I think that a major underlying issues is whether comparison of incomparable values is allowed to return false, or is considered to be erroneous (should signal an error.) Perhaps unfortunately, IEEE floats have already decided this issue in a lowest-common-denominator way by saying that trapping is not enabled by default. See the "IEEE float exception trapping" issue. EXAMPLES: Currently it is unclear what comparisons against NaNs do. Implementing float comparison with the hardware, < and = will be compliant, so the trichotomy assertion in the protocol will quietly be violated: 1.0 < NaN => #f NaN < 1.0 => #f NaN = 1.0 => #f Assuming trichotomy, transitivity is violated: 1.0 > NaN => #t NaN > 2.0 => #t 1.0 > 2.0 => #f More likely, the compiler will compile float > as a real float >, rather than as ~(x < y) & ~(x = y). In this case, transitivity will be preserved, but *only* when > is inline coded. With the proposal, transitivity is preserved, but trichotomy is violated: 1.0 > NaN => #f NaN > 2.0 => #f 1.0 > 2.0 => #f COST TO IMPLEMENTORS: Minimal or beneficial. COST TO USERS: Increases complexity of the language. PERFORMANCE IMPACT: Some interpretations of the current definition would have significant performance impact. Allowing the natural IEEE semantics would avoid this penalty. BENEFITS: -- Allows use of IEEE features. -- Doesn't alienate users who believe the IEEE float standard is a good thing. -- Clarifies the language semantics. AESTHETICS: No less aesthetic than NaNs. Status quo is arguably inconsistent as long as NaNs can appear. Removes trichotomy and identity as protocol requirements, allowing other objects to have unordered values. FUTURE FEATURES: Compatible with proposals that allow access to all IEEE features.