Re: [Sbcl-commits] master: Correctly round floats converted from ratios

Christophe Rhodes via Sbcl-devel <[email protected]>
Newsgroups gmane.lisp.steel-bank.devel
Message-ID <[email protected]>
stassats via Sbcl-commits <[email protected]> writes:

> +(defun check-ratio-to-float (ratio type)
> +  (declare (ratio ratio))
> +  (let* ((result (float ratio type))
> +         (new-ratio (rational result)))
> +    (multiple-value-bind (sig exp sign) (integer-decode-float result)
> +      (let* ((prev-float (scale-float (float (* sign (1- sig)) type) exp))

I think this line is off-by-one if the float in question is a
non-denormal and exactly at a power-of-two boundary, where the
resolution is twice as fine below the float as above the float.

One might say "well that just makes the test marginally weaker", but
it's in exactly these cases that it's more likely that the
implementation is wrong, so it would be nice for the test to be as
strong as possible there.  Or else some explicit tests near halfway points
of [1,1+eps], [1-eps/2,1] and related?  And some tests near
least-positive-normalized-fooble-float?

Also, how should conversion to float behave above
most-positive-fooble-float?  Is there an implicit interval above the
maximum where we convert down and don't error, or does anything above
the rational value of the most-positive float signal overflow?

Christophe

> +             (next-float (scale-float (float (* sign (1+ sig)) type) exp))
> +             (error (abs (- ratio new-ratio)))
> +             (error-prev (abs (- ratio (rational prev-float))))
> +             (error-next (abs (- ratio (rational next-float)))))
> +        
> +        (cond
> +          ((< error-next error)
> +           (error "(float ~a ~a) = ~a, while ~a is closer" ratio type result next-float))
> +          ((< error-prev error)
> +           (error "(float ~a ~a) = ~a, while ~a is closer" ratio type result prev-float))
> +          ((or (= error error-prev) (= error error-next))
> +           (unless (evenp sig)
> +             (error "(float ~a ~a) = ~a, not rounded to even" ratio type result))))))))
> +
> +(with-test (:name :ratio-to-float)
> +  (let ((*random-state* (make-random-state t)))
> +    (loop repeat 50000
> +          do
> +          (let* ((n-bits (random 100))
> +                 (d-bits (random 100))
> +                 (num (random (ash 1 n-bits)))
> +                 (den (max 1 (random (ash 1 d-bits))))
> +                 (ratio (/ num den)))
> +            (when (typep ratio 'ratio)
> +              (check-ratio-to-float ratio 1f0)
> +              (check-ratio-to-float ratio 1d0))))))
>
> -----------------------------------------------------------------------
>
>
> hooks/post-receive
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.