awk icon indicating copy to clipboard operation
awk copied to clipboard

Improve detection of errors from math functions

Open tbvdm opened this issue 1 year ago • 2 comments

Checking errno is not always sufficient; check for floating-point exceptions, too.

These changes make the log() and exp() tests in T.errmsg succeed on OpenBSD.

tbvdm avatar Jun 17 '24 19:06 tbvdm

thank you.

plan9 avatar Jun 17 '24 19:06 plan9

Wouldn't it be better for errchk() to return the actual result instead of always returning 1.0 ? So that you get:

$ awk 'BEGIN { print log(-1) }'
-nan
$ awk 'BEGIN { print exp(1000) }'
inf

as done by gawk and mawk?

I'd prepared a similar patch for NetBSD awhile back, but, never got around to sending it in:

diff -urN awk-master.orig/lib.c awk-master/lib.c
--- awk-master.orig/lib.c	2022-12-15 18:34:49.000000000 +0000
+++ awk-master/lib.c	2023-06-05 11:25:41.444557000 +0000
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <limits.h>
+#include <fenv.h>
 #include <math.h>
 #include "awk.h"
 
@@ -738,17 +739,19 @@
 	}
 }
 
+#pragma STDC FENV_ACCESS ON
+
 double errcheck(double x, const char *s)
 {
 
-	if (errno == EDOM) {
+	if (errno == EDOM || fetestexcept(FE_INVALID)) {
 		errno = 0;
+		feclearexcept(FE_INVALID);
 		WARNING("%s argument out of domain", s);
-		x = 1;
-	} else if (errno == ERANGE) {
+	} else if (errno == ERANGE || fetestexcept(FE_OVERFLOW)) {
 		errno = 0;
+		feclearexcept(FE_OVERFLOW);
 		WARNING("%s result out of range", s);
-		x = 1;
 	}
 	return x;
 }
diff -urN awk-master.orig/run.c awk-master/run.c
--- awk-master.orig/run.c	2022-12-15 18:34:49.000000000 +0000
+++ awk-master/run.c	2023-06-05 11:25:24.325359000 +0000
@@ -31,6 +31,7 @@
 #include <fcntl.h>
 #include <setjmp.h>
 #include <limits.h>
+#include <fenv.h>
 #include <math.h>
 #include <string.h>
 #include <stdlib.h>
@@ -1034,6 +1035,8 @@
 	return(True);
 }
 
+#pragma STDC FENV_ACCESS ON
+
 Cell *arith(Node **a, int n)	/* a[0] + a[1], etc.  also -a[0] */
 {
 	Awkfloat i, j = 0;
@@ -1080,6 +1083,7 @@
 			i = ipow(i, (int) j);
                else {
 			errno = 0;
+			feclearexcept(FE_ALL_EXCEPT);
 			i = errcheck(pow(i, j), "pow");
                }
 		break;
@@ -1176,6 +1180,7 @@
 			xf = ipow(xf, (int) yf);
                else {
 			errno = 0;
+			feclearexcept(FE_ALL_EXCEPT);
 			xf = errcheck(pow(xf, yf), "pow");
                }
 		break;
@@ -1626,16 +1631,19 @@
 		break;
 	case FLOG:
 		errno = 0;
+		feclearexcept(FE_ALL_EXCEPT);
 		u = errcheck(log(getfval(x)), "log");
 		break;
 	case FINT:
 		modf(getfval(x), &u); break;
 	case FEXP:
 		errno = 0;
+		feclearexcept(FE_ALL_EXCEPT);
 		u = errcheck(exp(getfval(x)), "exp");
 		break;
 	case FSQRT:
 		errno = 0;
+		feclearexcept(FE_ALL_EXCEPT);
 		u = errcheck(sqrt(getfval(x)), "sqrt");
 		break;
 	case FSIN:

rajeevvp avatar Aug 03 '24 23:08 rajeevvp