From 373efa085dcea5fe6b4539cd875b6bd8645f16fa Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Sun, 13 May 2018 10:02:01 +0200 Subject: 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 --- ChangeLog | 5 +++++ Src/Modules/mathfunc.c | 43 ------------------------------------------- Src/math.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++---- Src/params.c | 16 ++++++++++++---- configure.ac | 1 + 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 + * 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 + /* 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 \ -- cgit 1.4.1