Inf and NaN values fixed and printing improved. "This time for sure!"

This commit is contained in:
Arnold D. Robbins 2020-12-18 11:57:48 +02:00
parent 982a574e32
commit 8909e00b57
7 changed files with 61 additions and 17 deletions

8
FIXES
View File

@ -25,6 +25,14 @@ THIS SOFTWARE.
This file lists all bug fixes, changes, etc., made since the AWK book This file lists all bug fixes, changes, etc., made since the AWK book
was sent to the printers in August, 1987. was sent to the printers in August, 1987.
December 18, 2020:
Fix problems converting inf and NaN values in lib.c:is_valid_number.
Enhance number to string conversion to do the right thing for
NaN and inf values. Things are now pretty much the same as in
gawk. (Found a gawk bug while we're at it.) Added a torture
test for these values. Thanks to Arnold Robbins. Allows closing
of PR #101.
December 15, 2020: December 15, 2020:
Merge PR #99, which gets the right header for strcasecmp. Merge PR #99, which gets the right header for strcasecmp.
Thanks to GitHub user michaelforney. Thanks to GitHub user michaelforney.

View File

@ -0,0 +1,4 @@
{
for (i = 1; i <= NF; i++)
print i, $i, $i + 0
}

View File

@ -0,0 +1 @@
-inf -inform inform -nan -nancy nancy -123 0 123 +123 nancy +nancy +nan inform +inform +inf

View File

@ -0,0 +1,16 @@
1 -inf -inf
2 -inform 0
3 inform 0
4 -nan -nan
5 -nancy 0
6 nancy 0
7 -123 -123
8 0 0
9 123 123
10 +123 123
11 nancy 0
12 +nancy 0
13 +nan +nan
14 inform 0
15 +inform 0
16 +inf +inf

32
lib.c
View File

@ -784,46 +784,48 @@ bool is_valid_number(const char *s, bool trailing_stuff_ok,
double r; double r;
char *ep; char *ep;
bool retval = false; bool retval = false;
bool is_nan = false;
bool is_inf = false;
if (no_trailing) if (no_trailing)
*no_trailing = false; *no_trailing = false;
while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r') while (isspace(*s))
s++; s++;
if (s[0] == '0' && tolower(s[1]) == 'x') // no hex floating point, sorry // no hex floating point, sorry
if (s[0] == '0' && tolower(s[1]) == 'x')
return false; return false;
// allow +nan, -nan, +inf, -inf, any other letter, no // allow +nan, -nan, +inf, -inf, any other letter, no
if (s[0] == '+' || s[0] == '-') { if (s[0] == '+' || s[0] == '-') {
if (strcasecmp(s+1, "nan") == 0 || strcasecmp(s+1, "inf") == 0) is_nan = (strncasecmp(s+1, "nan", 3) == 0);
return true; is_inf = (strncasecmp(s+1, "inf", 3) == 0);
if ((is_nan || is_inf)
&& (isspace(s[4]) || s[4] == '\0'))
goto convert;
else if (! isdigit(s[1]) && s[1] != '.') else if (! isdigit(s[1]) && s[1] != '.')
return false; return false;
} }
else if (! isdigit(s[0]) && s[0] != '.') else if (! isdigit(s[0]) && s[0] != '.')
return false; return false;
convert:
errno = 0; errno = 0;
r = strtod(s, &ep); r = strtod(s, &ep);
if (ep == s || r == HUGE_VAL || errno == ERANGE) if (ep == s || errno == ERANGE)
return false; return false;
if (isnan(r) && s[0] == '-' && signbit(r) == 0)
r = -r;
if (result != NULL) if (result != NULL)
*result = r; *result = r;
/* retval = (isspace(*ep) || *ep == '\0' || trailing_stuff_ok);
* check for trailing stuff
* allow \r as well. windows files aren't going to go away.
*/
while (*ep == ' ' || *ep == '\t' || *ep == '\n' || *ep == '\r')
ep++;
if (no_trailing) if (no_trailing != NULL)
*no_trailing = (*ep == '\0'); *no_trailing = (*ep == '\0');
// return true if found the end, or trailing stuff is allowed
retval = (*ep == '\0') || trailing_stuff_ok;
return retval; return retval;
} }

2
main.c
View File

@ -22,7 +22,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE. THIS SOFTWARE.
****************************************************************/ ****************************************************************/
const char *version = "version 20201215"; const char *version = "version 20201218";
#define DEBUG #define DEBUG
#include <stdio.h> #include <stdio.h>

15
tran.c
View File

@ -418,10 +418,21 @@ Awkfloat getfval(Cell *vp) /* get float val of a Cell */
return(vp->fval); return(vp->fval);
} }
static char *get_inf_nan(double d)
{
if (isinf(d)) {
return (d < 0 ? "-inf" : "+inf");
} else if (isnan(d)) {
return (signbit(d) != 0 ? "-nan" : "+nan");
} else
return NULL;
}
static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
{ {
char s[256]; char s[256];
double dtemp; double dtemp;
char *p;
if ((vp->tval & (NUM | STR)) == 0) if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "read value of"); funnyvar(vp, "read value of");
@ -458,7 +469,9 @@ static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cel
{ \ { \
if (freeable(vp)) \ if (freeable(vp)) \
xfree(vp->sval); \ xfree(vp->sval); \
if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ if ((p = get_inf_nan(vp->fval)) != NULL) \
strcpy(s, p); \
else if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
snprintf(s, sizeof (s), "%.30g", vp->fval); \ snprintf(s, sizeof (s), "%.30g", vp->fval); \
else \ else \
snprintf(s, sizeof (s), *fmt, vp->fval); \ snprintf(s, sizeof (s), *fmt, vp->fval); \