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

This commit is contained in:
Oliver Kiddle 2018-05-13 10:02:01 +02:00
parent f0c2cf8607
commit 373efa085d
5 changed files with 64 additions and 51 deletions

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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 \