about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Src/Modules/mathfunc.c43
-rw-r--r--Src/math.c50
-rw-r--r--Src/params.c16
-rw-r--r--configure.ac1
5 files changed, 64 insertions, 51 deletions
diff --git a/ChangeLog b/ChangeLog
index 485d4a254..7d0c66bd1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2018-05-13  Oliver Kiddle  <okiddle@yahoo.co.uk>
 
+	* Nelson H. F. Beebe: 19597 (rebased 42369): Src/math.c,
+	Src/params.c. Src/Modules/mathfunc.c, configure.ac:
+	return Inf, NaN etc from floating point operations instead
+	of errors to allow non-stop IEEE 754 arithmetic
+
 	* 42760: Src/Zle/zle_thingy.c: move stack variable outside
 	while loop scope as it is accessed in the while condition
 
diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c
index a7e8b294c..a62154c50 100644
--- a/Src/Modules/mathfunc.c
+++ b/Src/Modules/mathfunc.c
@@ -208,49 +208,6 @@ math_func(char *name, int argc, mnumber *argv, int id)
   if (errflag)
     return ret;
 
-  if (id & 0xff00) {
-      int rtst = 0;
-
-      switch ((id >> 8) & 0xff) {
-      case BF_POS:
-	  rtst = (argd <= 0.0);
-	  break;
-	  
-      case BF_NONNEG:
-	  rtst = (argd < 0.0);
-	  break;
-
-      case BF_FRAC:
-	  rtst = (fabs(argd) > 1.0);
-	  break;
-
-      case BF_GE1:
-	  rtst = (argd < 1.0);
-	  break;
-
-      case BF_FRACO:
-	  rtst = (fabs(argd) >= 1.0);
-	  break;
-
-      case BF_INTPOS:
-	  rtst = (argd <= 0 && (double)(zlong)argd == argd);
-	  break;
-
-      case BF_GTRM1:
-	  rtst = (argd <= -1);
-	  break;
-
-      case BF_POS2:
-	  rtst = (argd2 <= 0.0);
-	  break;
-      }
-
-      if (rtst) {
-	  zerr("math: argument to %s out of range", name);
-	  return ret;
-      }
-  }
-
   switch (id & 0xff) {
   case MF_ABS:
       ret.type = argv->type;
diff --git a/Src/math.c b/Src/math.c
index c3831602b..cdfe80bb4 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -578,6 +578,37 @@ int outputradix;
 /**/
 int outputunderscore;
 
+#ifndef HAVE_ISINF
+/**/
+int
+isinf(double x)
+{
+    if ((-1.0 < x) && (x < 1.0))       /* x is small, and thus finite */
+       return (0);
+    else if ((x + x) == x)             /* only true if x == Infinity */
+       return (1);
+    else                               /* must be finite (normal or subnormal), or NaN */
+       return (0);
+}
+#endif
+
+#if !defined(HAVE_ISNAN)
+/**/
+static double
+store(double *x)
+{
+    return (*x);
+}
+
+/**/
+int
+isnan(double x)
+{
+    /* (x != x) should be sufficient, but some compilers incorrectly optimize it away */
+    return (store(&x) != store(&x));
+}
+#endif
+
 /**/
 static int
 zzlex(void)
@@ -791,6 +822,21 @@ zzlex(void)
 	    break;
 	/* Fall through! */
 	default:
+	    if (strcmp(ptr-1, "NaN") == 0) {
+		yyval.type = MN_FLOAT;
+		yyval.u.d = 0.0;
+		yyval.u.d /= yyval.u.d;
+		ptr += 2;
+		return NUM;
+	    }
+	    else if (strcmp(ptr-1, "Inf") == 0) {
+		yyval.type = MN_FLOAT;
+		yyval.u.d = 0.0;
+		yyval.u.d = 1.0 / yyval.u.d;
+		ptr += 2;
+		return NUM;
+	    }
+
 	    if (idigit(*--ptr) || *ptr == '.')
 		return lexconstant();
 	    if (*ptr == '#') {
@@ -1068,10 +1114,6 @@ callmathfunc(char *o)
 static int
 notzero(mnumber a)
 {
-    if ((a.type & MN_INTEGER) ? a.u.l == 0 : a.u.d == 0.0) {
-	zerr("division by zero");
-	return 0;
-    }
     return 1;
 }
 
diff --git a/Src/params.c b/Src/params.c
index 36f5f0676..51f6e6d9a 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -36,6 +36,8 @@
 #else
 #include "patchlevel.h"
 
+#include <math.h>
+
 /* If removed from the ChangeLog for some reason */
 #ifndef ZSH_PATCHLEVEL
 #define ZSH_PATCHLEVEL "unknown"
@@ -5431,10 +5433,16 @@ convfloat(double dval, int digits, int flags, FILE *fout)
 	ret = NULL;
     } else {
 	VARARR(char, buf, 512 + digits);
-	sprintf(buf, fmt, digits, dval);
-	if (!strchr(buf, 'e') && !strchr(buf, '.'))
-	    strcat(buf, ".");
-	ret = dupstring(buf);
+	if (isinf(dval))
+	    ret = dupstring((dval < 0.0) ? "-Inf" : "Inf");
+	else if (isnan(dval))
+	    ret = dupstring("NaN");
+	else {
+	    sprintf(buf, fmt, digits, dval);
+	    if (!strchr(buf, 'e') && !strchr(buf, '.'))
+		strcat(buf, ".");
+	    ret = dupstring(buf);
+	}
     }
 #ifdef USE_LOCALE
     if (prev_locale) setlocale(LC_NUMERIC, prev_locale);
diff --git a/configure.ac b/configure.ac
index d15a6cda2..4329afb9e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1317,6 +1317,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
 	       erand48 open_memstream \
 	       posix_openpt \
 	       wctomb iconv \
+	       isinf isnan \
 	       grantpt unlockpt ptsname \
 	       htons ntohs \
 	       regcomp regexec regerror regfree \