Implement and fix fenceposts in inf and NaN encoding.
authorTaylor R Campbell <campbell@mumble.net>
Fri, 30 Nov 2018 18:06:44 +0000 (18:06 +0000)
committerTaylor R Campbell <campbell@mumble.net>
Fri, 30 Nov 2018 18:06:44 +0000 (18:06 +0000)
src/runtime/ieee754.scm
tests/runtime/test-ieee754.scm

index d878fb9669e36013276f6e9a3b8636dd66e253a4..9ca331c27783371fc68b4351a51ee7aaecf063d2 100644 (file)
@@ -46,28 +46,27 @@ USA.
 (define (decompose-ieee754-binary x exponent-bits precision)
   (receive (base emin emax bias exp-subnormal exp-inf/nan)
            (ieee754-binary-parameters exponent-bits precision)
-    (decompose-ieee754 x base emax precision
-      (lambda (sign)                    ;if-zero
-        (values sign 0 0))
-      (lambda (sign significand)        ;if-subnormal
-        (assert (= 0 (shift-right significand (- precision 1))))
-        (values sign (+ exp-subnormal bias) significand))
-      (lambda (sign exponent significand) ;if-normal
-        (assert (<= emin exponent emax))
-        ;; The integer part is always 1.  Strip it for the binary
-        ;; interchange format.
-        (assert (= 1 (shift-right significand (- precision 1))))
-        (values sign
-                (+ exponent bias)
-                (extract-bit-field (- precision 1) 0 significand)))
-      (lambda (sign)                    ;if-infinite
-        (values sign exp-inf/nan 0))
-      (lambda (sign quiet payload)      ;if-nan
-        (assert (not (and (zero? quiet) (zero? payload))))
-        (assert (zero? (extract-bit-field (- precision 1) 1 payload)))
-        (values sign
-                exp-inf/nan
-                (replace-bit-field (- precision 1) 1 payload quiet))))))
+    (let ((t (- precision 1)))
+      (decompose-ieee754 x base emax precision
+        (lambda (sign)                  ;if-zero
+          (values sign 0 0))
+        (lambda (sign significand)      ;if-subnormal
+          (assert (= 0 (shift-right significand t)))
+          (values sign (+ exp-subnormal bias) significand))
+        (lambda (sign exponent significand) ;if-normal
+          (assert (<= emin exponent emax))
+          ;; The integer part is always 1.  Strip it for the binary
+          ;; interchange format.
+          (assert (= 1 (shift-right significand t)))
+          (values sign (+ exponent bias) (extract-bit-field t 0 significand)))
+        (lambda (sign)                  ;if-infinite
+          (values sign (+ exp-inf/nan bias) 0))
+        (lambda (sign quiet payload)    ;if-nan
+          (assert (not (and (zero? quiet) (zero? payload))))
+          (assert (zero? (extract-bit-field 1 (- t 1) payload)))
+          (values sign
+                  (+ exp-inf/nan bias)
+                  (replace-bit-field 1 (- t 1) payload quiet)))))))
 
 (define (ieee754-sign x)
   (cond ((< 0 x) 0)
@@ -82,12 +81,9 @@ USA.
 (define (decompose-ieee754 x base emax precision
           if-zero if-subnormal if-normal if-infinite if-nan)
   (cond ((not (= x x))
-         ;; There are, of course, b^p different NaNs.  There is no
-         ;; obvious way to computationally detect the sign of a NaN,
-         ;; and no portable way to get at the quiet bit or the payload
-         ;; bits, so we'll just assume every NaN is a trivial positive
-         ;; signalling NaN and hope the caller has a good story...
-         (if-nan 0 0 1))
+         (if-nan (if (flo:sign-negative? x) 1 0)
+                 (if (flo:nan-quiet? x) 1 0)
+                 (flo:nan-payload x)))
         ((and (< 1 (abs x)) (= x (/ x 2)))
          (if-infinite (if (< 0. x) 0 1)))
         (else
@@ -138,9 +134,9 @@ USA.
             ((= exponent exp-inf/nan)
              (if (zero? trailing-significand)
                  (compose-ieee754-infinity sign)
-                 (let ((quiet   (extract-bit-field 1 t trailing-significand))
-                       (payload (extract-bit-field t 0 trailing-significand)))
-                   (compose-ieee754-nan sign quiet payload))))
+                 (let ((q (extract-bit-field 1 (- t 1) trailing-significand))
+                       (p (extract-bit-field (- t 1) 0 trailing-significand)))
+                   (compose-ieee754-nan sign q p))))
             (else
              (assert (<= emin exponent emax))
              (let ((significand
@@ -165,8 +161,12 @@ USA.
      (flo:+inf.0)))
 
 (define (compose-ieee754-nan sign quiet payload)
-  (declare (ignore sign quiet payload))
-  (flo:nan.0))
+  ;; XXX Using the native microcode's idea of NaN is a little hokey:
+  ;; if, for example, we wanted to use this for cross-compilation of
+  ;; a Scheme with binary128 floating-point using a Scheme with
+  ;; binary64 floating-point, many NaNs that could appear in the
+  ;; source code would be unrepresentable in the host.
+  (flo:make-nan (= sign 1) (= quiet 1) payload))
 
 (define (ieee754-binary-parameters exponent-bits precision)
   (assert (zero? (modulo (+ exponent-bits precision) 32)))
index 4b36d8363578bb2c9986f8ad3693ac52b632c1bb..c71e364d6f7a23ef202df617b13cf82509e5ec93 100644 (file)
@@ -43,23 +43,19 @@ USA.
 (define ((test-ieee754-roundtrip exponent-bits precision
                                  compose exact? decompose)
          bits)
-  (receive (base emin emax bias exp-subnormal exp-inf/nan)
-           (ieee754-binary-parameters exponent-bits precision)
-    base emin emax exp-subnormal
-    (let ((w exponent-bits)             ;Width of exponent
-          (t (- precision 1)))          ;Trailing significand width
-      (let ((sign (extract-bit-field 1 (+ w t) bits))
-            (biased-exponent (extract-bit-field w t bits))
-            (trailing-significand (extract-bit-field t 0 bits)))
-        (if (not (= (- biased-exponent bias) exp-inf/nan))
-            (let ((x (compose sign biased-exponent trailing-significand)))
-              (assert (exact? x))
-              ;; Confirm that it yields the same bits.
-              (receive (sign* biased-exponent* trailing-significand*)
-                       (decompose x)
-                (assert-= sign* sign)
-                (assert-= biased-exponent* biased-exponent)
-                (assert-= trailing-significand* trailing-significand))))))))
+  (let ((w exponent-bits)             ;Width of exponent
+        (t (- precision 1)))          ;Trailing significand width
+    (let ((sign (extract-bit-field 1 (+ w t) bits))
+          (biased-exponent (extract-bit-field w t bits))
+          (trailing-significand (extract-bit-field t 0 bits)))
+      (let ((x (compose sign biased-exponent trailing-significand)))
+        (assert (or (not (finite? x)) (exact? x)))
+        ;; Confirm that it yields the same bits.
+        (receive (sign* biased-exponent* trailing-significand*)
+                 (decompose x)
+          (assert-= sign* sign)
+          (assert-= biased-exponent* biased-exponent)
+          (assert-= trailing-significand* trailing-significand))))))
 
 (define-test 'binary32-roundtrip-exhaustive
   (lambda ()
@@ -110,7 +106,9 @@ USA.
     (-2 (normal - 1 #x10000000000000))
     (,(flo:+inf.0) (infinity +))
     (,(flo:-inf.0) (infinity -))
-    (,(flo:nan.0) (nan + s 1)))
+    (,(flo:qnan 12345) (nan + q 12345))
+    (,(flo:snan 54321) (nan + s 54321))
+    (,(flo:make-nan #t #t 0) (nan - q 0)))
   (lambda (x y)
     (define (signify sign)
       (case sign