| Date: Mon, 27 Jun 2005 18:09:04 -0400 | From: Paul Schlie <xxxxxx@comcast.net> | | > From: Aubrey Jaffer <xxxxxx@alum.mit.edu> | > | Date: Mon, 27 Jun 2005 02:29:12 -0400 | > | From: Paul Schlie <xxxxxx@comcast.net> | > | ... | > | Thereby one could define that an unsigned 0 compares = to signed 0's to | > | preserve existing code practices which typically compare a value against | > | a sign-less 0. i.e.: | > | | > | (= 0 0.0 -0 -0.0) => #t | > | (= 0 0.0 +0 +0.0) => #t | > | | > | (= -0 -0.0 +0 +0.0) => #f | > | > The `=' you propose is not transitive, which is a requirement of R5RS. | | - then alternatively one could define: | | (= -0 -0.0 0 0.0 +0 +0.0) => #t | | while retaining the remaining relationships, as it seems | that = and < relationships need not be mutually exclusive? R5RS says: -- procedure: = z1 z2 z3 ... -- procedure: < x1 x2 x3 ... -- procedure: > x1 x2 x3 ... -- procedure: <= x1 x2 x3 ... -- procedure: >= x1 x2 x3 ... These procedures return #t if their arguments are (respectively): equal, monotonically increasing, monotonically decreasing, monotonically nondecreasing, or monotonically nonincreasing. These predicates are required to be transitive. Equal cannot be monotonically increasing. ... | | > Mathematical division by 0 is undefined; if you return 1, then code | > receiving that value can't detect that a boundary case occured. | | - yes, as above; and corrected below for unsigned 0's and 0.0's: | | 1/0 == inf :: 1/inf == 0 :: 0/0 == inf/inf == ~1 | | where although inf equivalent in magnitude to +/-inf, | it's sign is is undefined, thereby similar to nan, with | the exception that if one were to introduce the convention | that '~' may designate an ambiguous sign then the result of | any division by inf or 0 may be considered to only yield | an ambiguous sign although not necessarily magnitude, in | in lieu of considering the value as undefined, i.e. | | inf => ~inf ; either +inf or -inf | (* 3 (/ 0 0)) => ~3 ; either -3 or +3, thereby: | (abs (* 3 (/ 0 0))) => +3 So ~ generates an algebraic field extension attaching the roots of x^2=1. Note that ~ is not a real number because it doesn't fit in the total ordering. | (as this is how an implementation would behave if it considered | +-inf and +-0 it's greatest and smallest represent-able but | non-accumulating values; which effectively enables calculations | to loose precision more gracefully, than falling of the edge of | the value system potentially resulting in a run-time fault.) Section 6.2.2 Exactness says: If two implementations produce exact results for a computation that did not involve inexact intermediate results, the two ultimate results will be mathematically equivalent. So loss of precision must not be platform dependent; thresholds of "greatest and smallest represent-able" values can not affect precision. Losing precision in calculation is an attribute of inexact numbers. | > ... | > Nearly all of the SLIB occurences of EXPT have at least one | > literal constant argument. In these cases, (expt 0 0) signaling | > an error would catch coding errors. MODULAR:EXPT tests for a | > zero base (and returns 0) before calling EXPT. | | - ??? The responsibility of an implementation's arithmetic | implementation is to be generically as correct and consistent as | reasonably possible. If slib chooses to optionally signal a | runtime error for any arbitrary set of argument values, that's it's | prerogative; but should have nothing to do with what the arithmetic | value of (expt 0 0) or any other function is most consistently | defined as being. My point is that (expt 0 0) is unlikely to occur when EXPT is being used as a continuous function; its occurrences will be exponentiating integers. In the integer context, arguments about limits of continuous functions are irrelevant. | (all arithmetic functions should always return values). 6.2.3 Implementation restrictions: If one of these procedures is unable to deliver an exact result when given exact arguments, then it may either report a violation of an implementation restriction or it may silently coerce its result to an inexact number. Always returning a value is a stronger requirement than R5RS or SRFI-70, which gives the implementation a choice between returning 0/0 and signaling an error for (/ 0.0 0.0). Can you justify that mandate? Do you consider QUOTIENT, MODULO, and REMAINDER arithmetic? | > Grepping through a large body of Scheme code found no use of EXPT | > where the two arguments are related. | | - which has nothing to do with anything, functions should be considered | to be evaluated about static points: | | i.e. (f x y) == (f (+ x ~1/inf) (+ y ~1/inf)) The integer uses for EXPT should also be considered. | there's nothing special about 0, as any function may impose | relative trajectories for their arguments: | | (define (f x y) (/ x (* y y y (- y 1))) | | as such the only consistent thing that an implementation can | warrant is that all primitive arithmetic expressions are | evaluated equivalently about the static values passed to them, | independently of whether or not the values passed to them have | begun to loose precision due to the limited dynamic range of an | implementation's number system. Thereby at least as a function's | arguments begin to loose precision, the function correspondingly | degrades in precision correspondingly and consistently, without | after already yielding relatively inaccurate results decides it | doesn't know the answer at all, or chooses to return a value | which is inconsistent with it's previous results. (admittedly in | my opinion) SRFI-73 is about exact numbers. EXPT will only return exact numbers for exact arguments. Loss of precision means inexact numbers. | > (expt 0 0) ==> 1 is one of the possibilities for SRFI-70. But I | > am leaning toward the "0/0 or signal an error" choice to catch | > the rare coding error. | | - Again, in just my opinion, I'd rather a function return the most | likely useful static value as a function of it's arguments, rather | than it trying to pretend it knows something about the arguments | passed to it and potentially generating a runtime fault. | | However it does seem potentially useful to be optionally warned | whenever the precision of a primitive calculation drops below | some minimal precision; i.e. it's likely much more useful to know | when a floating point value is demoralized (as it means that the | value now no longer has a represent-able reciprocal, or when an | argument to an addition is less than the represented precision of | the other operand, as these are the type of circumstances which | result in inaccuracies, which by the time one may underflow to 0, | or overflow to inf, and hope it gets trapped by some misguided | function implementation which should have simply just returned | the correct value based upon the arguments it was given and have | the application check for what it believes is correct, it's | already much too late, as regardless of whether some | implementation's arithmetic system discontinuity was ticked, the | results of a calculation are at best already suspect. xxxxxx@sonic.net is also interested in specifying precision. See <http://srfi.schemers.org/srfi-70/mail-archive/msg00088.html> about an idea for latent precisions. | > | Where I understand that all inf's are not strictly equivalent, | > | but when expressed as inexact values it seems more ideal to | > | consider +-inf.0 to be equivalent to the bounds of the inexact | > | representation number system, thereby +-inf.0 are simply | > | treated as the greatest, and +-0.0 the smallest representable | > | inexact value; | > | > <http://srfi.schemers.org/srfi-70/srfi-70.html#6.2.2x> shows that | > inexact real numbers correspond to intervals of the real number line. | > Infinities corresponding to the remaining half-lines gives very clean | > semantics for inexact real numbers. Infinitesimals (+-0.0) are a | > solution in search of a problem. | | - only if it's not considered important that inexact infinities have | corresponding reciprocals; Inexact infinities have reciprocals: zero. Their reciprocals are not unique, but that is already the case with IEEE-754 floating-point representations: 179.76931348623151e306 ==> 179.76931348623151e306 179.76931348623157e306 ==> 179.76931348623157e306 (/ 179.76931348623151e306) ==> 5.562684646268003e-309 (/ 179.76931348623157e306) ==> 5.562684646268003e-309 | which seems clearly desirable as otherwise any expression which | may overflow the dynamic range of the number system can't | preserve the sign of it's corresponding infinitesimal value, | which if not considered important, there's no reason to have | signed infinities, either, etc. ? #i+1/0 is the half-line beyond the largest floating-point value. The projection of that interval through / is a small open interval bordering 0.0. That interval overlaps the interval of floating-point numbers closer to 0.0 than to any other. Thus the reciprocal of #i+1/0 is 0.0.