summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
authorOliver Kiddle <okiddle@yahoo.co.uk>2018-05-13 10:02:01 +0200
committerOliver Kiddle <okiddle@yahoo.co.uk>2018-05-13 10:02:01 +0200
commit373efa085dcea5fe6b4539cd875b6bd8645f16fa (patch)
treeb318a3be674458848e156e49d1df1c21543f95c6 /Src
parentf0c2cf8607dd055f2b8aaa98664f7328108f2c65 (diff)
downloadzsh-373efa085dcea5fe6b4539cd875b6bd8645f16fa.tar.gz
zsh-373efa085dcea5fe6b4539cd875b6bd8645f16fa.zip
Nelson H. F. Beebe: 19597 (rebased 42369): return Inf, NaN etc from floating point operations instead of errors to allow non-stop IEEE 754 arithmetic
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/mathfunc.c43
-rw-r--r--Src/math.c50
-rw-r--r--Src/params.c16
3 files changed, 58 insertions, 51 deletions
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);