From 7758900b5e12172d7b0306e67a9dc045e7c33643 Mon Sep 17 00:00:00 2001
From: Raymond Toy <toy.raymond@gmail.com>
Date: Thu, 21 Aug 2014 20:32:32 -0700
Subject: [PATCH] Handle invalid correctly.

If the argument is a quiet NaN, then we don't want to signal an
invalid operation. For all other floats, we do want to signal
that. Add function isQNaN to detect quiet NaN.
---
 src/lisp/setexception.c | 43 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/src/lisp/setexception.c b/src/lisp/setexception.c
index a0f568c05..a77a9d8fa 100644
--- a/src/lisp/setexception.c
+++ b/src/lisp/setexception.c
@@ -4,6 +4,37 @@
 
 #include "fdlibm.h"
 
+/*
+ * Test if the given number is a quiet NaN
+ */
+
+int
+isQNaN(double x)
+{
+    int hx;
+    union { int i[2]; double d; } ux;
+
+    ux.d = x;
+    hx = ux.i[HIWORD] & 0x7fffffff;
+
+    if (hx >= 0x7ff00000) {
+        /*
+         * We have some kind of infinity or NaN. Get the (top)
+         * mantissa bits. We have a quiet NaN if the most significant
+         * bit is 1. The other bits of the mantissa don't matter. We
+         * also don't distinguish this from the quiet NaN
+         * floating-point indefinite which only has the most
+         * significant bit set. These are all considered NaNs for our
+         * purposes.
+         */
+        hx &= 0xfffff;
+        
+        return hx & 0x80000;
+    }
+
+    return 0;
+}
+
 /*
  * Signal the floating-point exception of the given |type|, based on
  * the value of |x|.
@@ -36,13 +67,21 @@ fdlibm_setexception(double x, enum FDLIBM_EXCEPTION type)
       case 3:
       {
           /* invalid */
-          feraiseexcept(FE_INVALID);
+
+          if (!isQNaN(x)) {
+              /*
+               * If it's not a quiet NaN, we want to signal an invalid
+               * operation. Otherwise, we silently return a NaN.
+               */
+              feraiseexcept(FE_INVALID);
+          }
+          
           /*
            * FIXME: Of the many NaN values that we have, what NaN
            * should we return?
            */
           union { int i[2]; double d; } ux;
-          ux.i[HIWORD] = 0x7ff00000;
+          ux.i[HIWORD] = 0x7ff80000;
           ux.i[LOWORD] = 0xdeadbeef;
           
           ret = ux.d;
-- 
GitLab