unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Kevin Ryde <user42@zip.com.au>
Subject: Re: min, max and nans
Date: Fri, 30 May 2003 10:20:29 +1000	[thread overview]
Message-ID: <87smqxl1yq.fsf@zip.com.au> (raw)
In-Reply-To: 87d6ih5okm.fsf@zagadka.ping.de

[-- Attachment #1: Type: text/plain, Size: 504 bytes --]

Marius Vollmer <mvo@zagadka.de> writes:
>
> That's what I think, too.

        * numbers.c (scm_max, scm_min): For inum, bignum and real, if other
        operand is NaN, then return NaN.  Also avoid passing NaN to mpz_cmp_d.

        * tests/numbers.test (max, min): Add tests involving NaNs.

Some cases just need the sense of the > or < test put the right way to
allow for it being false when involving a NaN.  A couple are right
already.  For bignums and for real/real an actual isnan is necessary.


[-- Attachment #2: numbers.c.min-max-nan.diff --]
[-- Type: text/plain, Size: 3908 bytes --]

--- numbers.c.~1.188.~	2003-05-13 09:14:53.000000000 +1000
+++ numbers.c	2003-05-26 17:42:15.000000000 +1000
@@ -2806,7 +2806,8 @@
       return (sgn < 0) ? x : y;
     } else if (SCM_REALP (y)) {
       double z = xx;
-      return (z <= SCM_REAL_VALUE (y)) ? y : scm_make_real (z);
+      /* if y==NaN then ">" is false and we return NaN */
+      return (z > SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
     } else {
       SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
     }
@@ -2820,7 +2821,11 @@
       scm_remember_upto_here_2 (x, y);
       return (cmp > 0) ? x : y;
     } else if (SCM_REALP (y)) {
-      int cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
+      double yy = SCM_REAL_VALUE (y);
+      int cmp;
+      if (xisnan (yy))
+        return y;
+      cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), yy);
       scm_remember_upto_here_1 (x);
       return (cmp > 0) ? x : y;
     } else {
@@ -2829,13 +2834,23 @@
   } else if (SCM_REALP (x)) {
     if (SCM_INUMP (y)) {
       double z = SCM_INUM (y);
+      /* if x==NaN then "<" is false and we return NaN */
       return (SCM_REAL_VALUE (x) < z) ? scm_make_real (z) : x;
     } else if (SCM_BIGP (y)) {
-      int cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
+      double xx = SCM_REAL_VALUE (x);
+      int cmp;
+      if (xisnan (xx))
+        return x;
+      cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
       scm_remember_upto_here_1 (y);
       return (cmp < 0) ? x : y;
     } else if (SCM_REALP (y)) {
-      return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? y : x;
+      /* if x==NaN then our explicit check means we return NaN
+         if y==NaN then ">" is false and we return NaN
+         a call to isnan is unavoidable, since it's the only way to know
+         which of x or y causes any compares to be false */
+      double xx = SCM_REAL_VALUE (x);
+      return (xisnan (xx) || xx > SCM_REAL_VALUE (y)) ? x : y;
     } else {
       SCM_WTA_DISPATCH_2 (g_max, x, y, SCM_ARGn, s_max);
     }
@@ -2872,6 +2887,7 @@
       return (sgn < 0) ? y : x;
     } else if (SCM_REALP (y)) {
       double z = xx;
+      /* if y==NaN then "<" is false and we return NaN */
       return (z < SCM_REAL_VALUE (y)) ? scm_make_real (z) : y;
     } else {
       SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
@@ -2886,7 +2902,11 @@
       scm_remember_upto_here_2 (x, y);
       return (cmp > 0) ? y : x;
     } else if (SCM_REALP (y)) {
-      int cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), SCM_REAL_VALUE (y));
+      double yy = SCM_REAL_VALUE (y);
+      int cmp;
+      if (xisnan (yy))
+        return y;
+      cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (x), yy);
       scm_remember_upto_here_1 (x);
       return (cmp > 0) ? y : x;
     } else {
@@ -2895,13 +2915,23 @@
   } else if (SCM_REALP (x)) {
     if (SCM_INUMP (y)) {
       double z = SCM_INUM (y);
-      return (SCM_REAL_VALUE (x) <= z) ? x : scm_make_real (z);
+      /* if x==NaN then ">" is false and we return NaN */
+      return (SCM_REAL_VALUE (x) > z) ? scm_make_real (z) : x;
     } else if (SCM_BIGP (y)) {
-      int cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), SCM_REAL_VALUE (x));
+      double xx = SCM_REAL_VALUE (x);
+      int cmp;
+      if (xisnan (xx))
+        return x;
+      cmp = xmpz_cmp_d (SCM_I_BIG_MPZ (y), xx);
       scm_remember_upto_here_1 (y);
       return (cmp < 0) ? y : x;
     } else if (SCM_REALP (y)) {
-      return (SCM_REAL_VALUE (x) < SCM_REAL_VALUE (y)) ? x : y;
+      /* if x==NaN then our explicit check means we return NaN
+         if y==NaN then "<" is false and we return NaN
+         a call to isnan is unavoidable, since it's the only way to know
+         which of x or y causes any compares to be false */
+      double xx = SCM_REAL_VALUE (x);
+      return (xisnan (xx) || xx < SCM_REAL_VALUE (y)) ? x : y;
     } else {
       SCM_WTA_DISPATCH_2 (g_min, x, y, SCM_ARGn, s_min);
     }

[-- Attachment #3: numbers.test.min-max-nan.diff --]
[-- Type: text/plain, Size: 2664 bytes --]

--- numbers.test.~1.23.~	2003-05-10 13:01:51.000000000 +1000
+++ numbers.test	2003-05-26 17:45:08.000000000 +1000
@@ -1646,6 +1646,9 @@
 ;;;
 
 (with-test-prefix "max"
+  (pass-if (= 456.0 (max 123.0 456.0)))
+  (pass-if (= 456.0 (max 456.0 123.0)))
+
   (let ((big*2 (* fixnum-max 2))
         (big*3 (* fixnum-max 3))
         (big*4 (* fixnum-max 4))
@@ -1654,7 +1657,15 @@
     (pass-if (= +inf.0 (max big*5  +inf.0)))
     (pass-if (= +inf.0 (max +inf.0 big*5)))
     (pass-if (= big*5  (max big*5  -inf.0)))
-    (pass-if (= big*5  (max -inf.0 big*5))))
+    (pass-if (= big*5  (max -inf.0 big*5)))
+
+    (pass-if (nan? (max 123 +nan.0)))
+    (pass-if (nan? (max big*5 +nan.0)))
+    (pass-if (nan? (max 123.0 +nan.0)))
+    (pass-if (nan? (max +nan.0 123)))
+    (pass-if (nan? (max +nan.0 big*5)))
+    (pass-if (nan? (max +nan.0 123.0)))
+    (pass-if (nan? (max +nan.0 +nan.0))))
 
   ;; in gmp prior to 4.2, mpz_cmp_d ended up treating Inf as 2^1024, make
   ;; sure we've avoided that
@@ -1672,7 +1683,12 @@
 		  (1+ (ash 1 1024))
 		  (- (1- (ash 1 1024)))
 		  (- (ash 1 1024))
-		  (- (1+ (ash 1 1024))))))
+		  (- (1+ (ash 1 1024)))))
+
+  ;; in gmp prior to 4.2, mpz_cmp_d ended up treating NaN as 3*2^1023, make
+  ;; sure we've avoided that
+  (pass-if (nan? (max (ash 1 2048) +nan.0)))
+  (pass-if (nan? (max +nan.0 (ash 1 2048)))))
 
 ;;;
 ;;; min
@@ -1681,6 +1697,9 @@
 ;; FIXME: unfinished...
 
 (with-test-prefix "min"
+  (pass-if (= 123.0 (min 123.0 456.0)))
+  (pass-if (= 123.0 (min 456.0 123.0)))
+
   (let ((big*2 (* fixnum-max 2))
         (big*3 (* fixnum-max 3))
         (big*4 (* fixnum-max 4))
@@ -1706,7 +1725,15 @@
     (pass-if (= big*5  (min big*5  +inf.0)))
     (pass-if (= big*5  (min +inf.0 big*5)))
     (pass-if (= -inf.0 (min big*5  -inf.0)))
-    (pass-if (= -inf.0 (min -inf.0 big*5))))
+    (pass-if (= -inf.0 (min -inf.0 big*5)))
+
+    (pass-if (nan? (min 123 +nan.0)))
+    (pass-if (nan? (min big*5 +nan.0)))
+    (pass-if (nan? (min 123.0 +nan.0)))
+    (pass-if (nan? (min +nan.0 123)))
+    (pass-if (nan? (min +nan.0 big*5)))
+    (pass-if (nan? (min +nan.0 123.0)))
+    (pass-if (nan? (min +nan.0 +nan.0))))
   
   ;; in gmp prior to 4.2, mpz_cmp_d ended up treating Inf as 2^1024, make
   ;; sure we've avoided that
@@ -1724,7 +1751,12 @@
 		  (1+ (ash 1 1024))
 		  (- (1- (ash 1 1024)))
 		  (- (ash 1 1024))
-		  (- (1+ (ash 1 1024))))))
+		  (- (1+ (ash 1 1024)))))
+
+  ;; in gmp prior to 4.2, mpz_cmp_d ended up treating NaN as 3*2^1023, make
+  ;; sure we've avoided that
+  (pass-if (nan? (min (- (ash 1 2048)) (- +nan.0))))
+  (pass-if (nan? (min (- +nan.0) (- (ash 1 2048))))))
 
 ;;;
 ;;; +

[-- Attachment #4: Type: text/plain, Size: 142 bytes --]

_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/guile-devel

  reply	other threads:[~2003-05-30  0:20 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-05-05 23:26 min, max and nans Kevin Ryde
2003-05-17 20:02 ` Marius Vollmer
2003-05-30  0:20   ` Kevin Ryde [this message]
2003-06-04 16:08     ` Kevin Ryde
2003-06-05 12:48       ` Marius Vollmer
2003-06-06 16:03         ` Mikael Djurfeldt
2003-06-06 23:17           ` Marius Vollmer
2003-06-15  0:17   ` Kevin Ryde
2003-06-18 23:36     ` Marius Vollmer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87smqxl1yq.fsf@zip.com.au \
    --to=user42@zip.com.au \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).