Hi, Tomas Volf <[email protected]> writes:
>> I lack the background information about numbers to judge what’s correct
>> here. Can you judge that?
>
> Returning NaN is consistent with Chez, but I am not qualified to say
> whether it is correct. I just did basically white-box testing of both
> yours and the built-in version and took note of the differences. ^_^
>
>>
>> It seems like we’ll need a full set of tests for min and max before we
>> can replace them.
I just realized that we actually have quite a few tests.
The following is a slower version, but it passes all tests in our
numbers.test. It looks *much* slower, but in my test with one million
numbers, it’s factor 2 slower than min in C -- on the slow path. The
syntax-case part is faster than C.
The tests only check with small numbers of arguments, so only the
syntax-case is actually tested, the rest copied over in the hope to make
no mistake:
(import (ice-9 match))
(define-syntax-rule (define-minmax-expansion f %f compare)
(begin
(define %f
(case-lambda
(() (error 'wrong-num-args))
((x) x)
((x y) (cond ((compare x y) (if (inexact? y) (exact->inexact x) x))
((compare y x) (if (inexact? x) (exact->inexact y) y))
((eqv? x y) x) ;; not for -0. 0.
((= x y) (if (zero? x) 0. x)) ;; -0. and 0.
(else (nan))))
((x . rest)
(let lp ((m x)
(rest rest)
(inex? (inexact? x)))
(match rest
(() (if (real? m)
(if inex? (exact->inexact m) m)
(error "Wrong type argument" 'wrong-type-arg)))
((x . rest)
(cond
((compare x m) (lp x rest (or inex? (inexact? x))))
((compare m x) (lp m rest (or inex? (inexact? x))))
((eqv? m x) (lp m rest (or inex? (inexact? x)))) ;; not for -0.
0.
((= m x) (lp (if (zero? m) 0. m) rest (or inex? (inexact? x))))
;; -0. and 0.
;; neither > nor < nor = means (nan): nothing more to do
(else
(nan)))))))))
(define-syntax f
(lambda (stx)
(syntax-case stx ()
(f (identifier? #'f) #'%f)
((_) #'(error "Wrong number of arguments to" 'wrong-num-args))
((_ x) #'(if (real? x) x (error "Wrong type argument"
'wrong-type-arg)))
((_ x y)
#'(let ((x* x)
(y* y)
(inex? (or (inexact? x) (inexact? y))))
(cond ((compare x* y*) (if inex? (exact->inexact x*) x*))
((compare y* x*) (if inex? (exact->inexact y*) y*))
((eqv? x* y*) x*) ;; not for -0. 0.
((= x* y*) (if (zero? x*) 0. x*)) ;; -0. and 0.
(else (nan)))))
((_ x . y)
#'(f x (f . y))))))))
(define-minmax-expansion max %max >)
(define-minmax-expansion min %min <)
> I believe this simplifies it a bit too much. The 2019 version (well,
> the draft, I am not buying the final document, and consider the very
> need to *buy* a standard to be absurd) specifies both `minimum' and
> `minimumNumber' with different behavior regarding NaNs (section 9.6). I
> do not know whether r7rs prescribes which of those shall be used, but
> probably not.
I don’t think it does.
>> But from r7rs:
>>
>> An arithmetic operation where one operand is NaN
>> returns NaN, unless the implementation can prove that the
>> result would be the same if the NaN were replaced by any
>> rational number.
>>
>> Are min and max arithmetic operations?
>
> ¯\_(ツ)_/¯
:-)
I think this means: don’t change behavior.
>> Do I need to import something?
>
> Ah, my bad, it is an extension[0] from my library, it helps to make
> large numbers more readable. It is sourced automatically on REPL start
> and I did not realize I have used it. You can just drop all of the _,
> including the #_ prefix, and it will work. Sorry about that.
>
> 0: https://git.wolfsden.cz/guile-wolfsden/tree/wolfsden/x/underscore.scm
No worries, that looks pretty useful.
> In all the above I see large variances in GC time, so I wonder whether
> that had some effect on the result. In my tests I have always executed
> ,gc first, so you can see the GC is always 0 (min/max should not really
> need to trigger GC anyway). I am unsure how large the effect of that is
> though, possibly not large.
In the benchmarks, gc made a difference for the very large lists. So it
may have some optimization to do.
Best wishes,
Arne
--
Unpolitisch sein
heißt politisch sein,
ohne es zu merken.
draketo.de
signature.asc
Description: PGP signature
