Mail Archives: djgpp-workers/2013/07/10/13:40:43
X-Authentication-Warning: | delorie.com: mail set sender to djgpp-workers-bounces using -f
|
X-Recipient: | djgpp-workers AT delorie DOT com
|
Message-ID: | <51DD9CCD.6070801@gmx.de>
|
Date: | Wed, 10 Jul 2013 19:41:33 +0200
|
From: | Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
|
User-Agent: | Mozilla/5.0 (X11; Linux x86_64; rv:16.0) Gecko/20121025 Thunderbird/16.0.2
|
MIME-Version: | 1.0
|
To: | djgpp-workers AT delorie DOT com
|
Subject: | Some more strto[d|f|ld] issues.
|
X-Provags-ID: | V03:K0:eh7WGOih6ZhuL7O3cMXLCYZnNZKvI6SxyPEYWKUk7GazZcALwFh
|
| vJ/EwSH3srvKA12Nw2I4MngDblScFW4u2tES7uwxf6gLDZr9wq6O/r2z16AAJH4b+0UpmqI
|
| jjtNrCWDWBYGguEZdbw25whSAShaaasYvbb59l1j54hvWOGG0Kv/X4dxa8Z3QmSyZCBtuUi
|
| D6Leyl31wGEg8MwM+Ix1w==
|
Reply-To: | djgpp-workers AT delorie DOT com
|
Some years ago I implemented the hex string conversion method
for the strto[d|ld|f] functions. In those days I decided to
implement rounding towards zero because it was the easiest and
because I did not know it better. While I was porting Lua,
I noted that that was wrong and I have changed the rounding
to round half up. This seems to be the same that glibc does
und it lets successfully pass the testsuite of Lua. That was
not the case with the last port of Lua.
Regards,
Juan M. Guerrero
cvs ci -m"Round half up as glibc does instead of round towards zero." djgpp/src/libc/ansi/stdlib/strtod.c
cvs ci -m"Round half up as glibc does instead of round towards zero." djgpp/src/libc/ansi/stdlib/strtold.c
cvs ci -m"Round half up as glibc does instead of round towards zero." djgpp/src/libc/c99/stdlib/strtof.c
Logging in to :pserver:anonymous AT cvs DOT delorie DOT com:2401/cvs/djgpp
Index: djgpp/src/libc/ansi/stdlib/strtod.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtod.c,v
retrieving revision 1.16
diff -p -U 5 -r1.16 strtod.c
--- djgpp/src/libc/ansi/stdlib/strtod.c 9 Jul 2013 23:00:23 -0000 1.16
+++ djgpp/src/libc/ansi/stdlib/strtod.c 9 Jul 2013 23:25:27 -0000
@@ -14,14 +14,17 @@
#include <ctype.h>
#include <string.h>
#include <libc/unconst.h>
#include <libc/ieee.h>
+
+#define MANTISSA_SIZE (52) /* Number binary digits in the fractional part of the mantissa. */
#define HEX_DIGIT_SIZE (4)
#define DOUBLE_BIAS (0x3FFU)
#define MAX_BIN_EXPONENT (1023) /* Max. and min. binary exponent (inclusive) as */
#define MIN_BIN_EXPONENT (-1022) /* defined in Intel manual (253665.pdf, Table 4.2). */
+#define IS_ZERO_DIGIT(x) ((x) == '0')
#define IS_DEC_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
#define IS_HEX_DIGIT(x) ((((x) >= 'A') && ((x) <= 'F')) || \
(((x) >= 'a') && ((x) <= 'f')) || \
IS_DEC_DIGIT(x))
#define IS_DEC_EXPONENT(x) (((x[0]) == 'E' || (x[0]) == 'e') && \
@@ -120,13 +123,13 @@ strtod(const char *s, char **sret)
}
/* Handle 0xH.HHH[p|P][+|-]DDD. */
if (!strnicmp("0x", s, 2) && (s[2] == '.' || IS_HEX_DIGIT(s[2])))
{
- int digits, integer_digits;
- long int bin_exponent;
- unsigned long long int mantissa;
+ const int max_digits = 1 + MANTISSA_SIZE / HEX_DIGIT_SIZE + 1; /* Two more digits than fit into mantissa. */
+ int bin_exponent, digits, integer_digits;
+ unsigned long long int mantissa, msb_mask;
_double_union_t ieee754;
/*
* Mantissa.
@@ -134,11 +137,11 @@ strtod(const char *s, char **sret)
*/
bin_exponent = 0;
integer_digits = 0;
mantissa = 0x00ULL;
s += 2; /* Skip the hex prefix. */
- while (integer_digits < 16 && IS_HEX_DIGIT(*s))
+ while (integer_digits < max_digits && IS_HEX_DIGIT(*s))
{
flags = 1;
mantissa <<= HEX_DIGIT_SIZE;
mantissa |= IS_DEC_DIGIT(*s) ? *s - '0' :
((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
@@ -150,27 +153,30 @@ strtod(const char *s, char **sret)
{
/*
* Compute the binary exponent for a normalized mantissa by
* shifting the radix point inside the most significant hex digit.
*/
- unsigned long long bit = 0x01ULL;
for (digits = 0; IS_HEX_DIGIT(*s); s++)
digits++; /* Counts hex digits. */
+
+ msb_mask = 0x01ULL;
bin_exponent = integer_digits * HEX_DIGIT_SIZE - 1; /* 2**bin_exponent. */
- for (bit <<= bin_exponent; !(mantissa & bit); bin_exponent--)
- bit >>= 1;
+ for (msb_mask <<= bin_exponent; !(mantissa & msb_mask); msb_mask >>= 1)
+ bin_exponent--;
bin_exponent += digits * HEX_DIGIT_SIZE;
+ integer_digits += digits;
}
+ digits = integer_digits;
if (*s == radix_point)
{
- int fraction_zeros = 0;
+ int extra_shifts, fraction_zeros = 0;
s++;
digits = integer_digits;
- while ((digits - fraction_zeros) < 16 && IS_HEX_DIGIT(*s))
+ while ((digits - fraction_zeros) < max_digits && IS_HEX_DIGIT(*s))
{
flags = 1;
digits++; /* Counts hex digits. */
mantissa <<= HEX_DIGIT_SIZE;
mantissa |= IS_DEC_DIGIT(*s) ? *s - '0' :
@@ -183,16 +189,18 @@ strtod(const char *s, char **sret)
{
/*
* Compute the binary exponent for a normalized mantissa by
* shifting the radix point inside the most significant hex digit.
*/
- unsigned long long bit = 0x01ULL;
+ msb_mask = 0x01ULL;
bin_exponent = -fraction_zeros * HEX_DIGIT_SIZE; /* 2**bin_exponent. */
- for (bit <<= (digits * HEX_DIGIT_SIZE + bin_exponent); !(mantissa & bit); bin_exponent--)
- bit >>= 1;
+ for (msb_mask <<= (digits * HEX_DIGIT_SIZE + bin_exponent); !(mantissa & msb_mask); msb_mask >>= 1)
+ bin_exponent--;
}
+ else if ((extra_shifts = digits - integer_digits) > 0)
+ msb_mask <<= extra_shifts * HEX_DIGIT_SIZE;
}
if (flags == 0)
{
if (sret)
@@ -203,10 +211,28 @@ strtod(const char *s, char **sret)
}
errno = EINVAL; /* No valid mantissa, no conversion could be performed. */
return 0.0L;
}
+ if (digits >= max_digits)
+ {
+ /*
+ * Round half towards plus infinity (round half up).
+ */
+ const int lsd = 0x000000000000000FULL & mantissa; /* Least significant hex digit. Will be rounded out. */
+ if (lsd > 0x07)
+ {
+ mantissa += 0x0000000000000010ULL; /* Smallest float greater than x. */
+ if (!(mantissa & msb_mask))
+ {
+ /* Overflow. */
+ mantissa >>= 1;
+ bin_exponent++;
+ }
+ }
+ }
+
if (mantissa)
{
/*
* Normalize mantissa.
*/
Index: djgpp/src/libc/ansi/stdlib/strtold.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/stdlib/strtold.c,v
retrieving revision 1.16
diff -p -U 5 -r1.16 strtold.c
--- djgpp/src/libc/ansi/stdlib/strtold.c 9 Jul 2013 23:00:25 -0000 1.16
+++ djgpp/src/libc/ansi/stdlib/strtold.c 9 Jul 2013 23:25:27 -0000
@@ -12,14 +12,17 @@
#include <math.h>
#include <string.h>
#include <libc/unconst.h>
#include <libc/ieee.h>
+
+#define MANTISSA_SIZE (64) /* Number binary digits in the integer and fractional part of the mantissa. */
#define HEX_DIGIT_SIZE (4)
#define LONG_DOUBLE_BIAS (0x3FFFU)
#define MAX_BIN_EXPONENT (16383) /* Max. and min. binary exponent (inclusive) as */
#define MIN_BIN_EXPONENT (-16382) /* defined in Intel manual (253665.pdf, Table 4.2). */
+#define IS_ZERO_DIGIT(x) ((x) == '0')
#define IS_DEC_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
#define IS_HEX_DIGIT(x) ((((x) >= 'A') && ((x) <= 'F')) || \
(((x) >= 'a') && ((x) <= 'f')) || \
IS_DEC_DIGIT(x))
#define IS_DEC_EXPONENT(x) (((x[0]) == 'E' || (x[0]) == 'e') && \
@@ -125,13 +128,13 @@ strtold(const char *s, char **sret)
/* Handle 0xH.HHH[p|P][+|-]DDD. */
if (!strnicmp("0x", s, 2) && (s[2] == '.' || IS_HEX_DIGIT(s[2])))
{
const char *next_char = NULL;
- int digits, integer_digits;
- long long int bin_exponent;
- unsigned long long int mantissa;
+ const int max_digits = MANTISSA_SIZE / HEX_DIGIT_SIZE; /* The exact number of digits that fits in mantissa. */
+ int bin_exponent, digits, integer_digits;
+ unsigned long long int mantissa, msb_mask;
_longdouble_union_t ieee754;
/*
* Mantissa.
@@ -140,11 +143,11 @@ strtold(const char *s, char **sret)
*/
bin_exponent = 0;
integer_digits = 0;
mantissa = 0x00ULL;
s += 2; /* Skip the hex prefix. */
- while (integer_digits < 16 && IS_HEX_DIGIT(*s))
+ while (integer_digits < max_digits && IS_HEX_DIGIT(*s))
{
flags = 1;
mantissa <<= HEX_DIGIT_SIZE;
mantissa |= IS_DEC_DIGIT(*s) ? *s - '0' :
((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
@@ -156,28 +159,31 @@ strtold(const char *s, char **sret)
{
/*
* Compute the binary exponent for a normalized mantissa by
* shifting the radix point inside the most significant hex digit.
*/
- unsigned long long bit = 0x01ULL;
next_char = s;
for (digits = 0; IS_HEX_DIGIT(*s); s++)
digits++; /* Counts hex digits. */
+
+ msb_mask = 0x01ULL;
bin_exponent = integer_digits * HEX_DIGIT_SIZE - 1; /* 2**bin_exponent. */
- for (bit <<= bin_exponent; !(mantissa & bit); bin_exponent--)
- bit >>= 1;
+ for (msb_mask <<= bin_exponent; !(mantissa & msb_mask); msb_mask >>= 1)
+ bin_exponent--;
bin_exponent += digits * HEX_DIGIT_SIZE;
+ integer_digits += digits;
}
+ digits = integer_digits;
if (*s == radix_point)
{
- int fraction_zeros = 0;
+ int extra_shifts, fraction_zeros = 0;
s++;
digits = integer_digits;
- while ((digits - fraction_zeros) < 16 && IS_HEX_DIGIT(*s))
+ while ((digits - fraction_zeros) < max_digits && IS_HEX_DIGIT(*s))
{
flags = 1;
digits++; /* Counts hex digits. */
mantissa <<= HEX_DIGIT_SIZE;
mantissa |= IS_DEC_DIGIT(*s) ? *s - '0' :
@@ -191,16 +197,18 @@ strtold(const char *s, char **sret)
{
/*
* Compute the binary exponent for a normalized mantissa by
* shifting the radix point inside the most significant hex digit.
*/
- unsigned long long bit = 0x01ULL;
+ msb_mask = 0x01ULL;
bin_exponent = -fraction_zeros * HEX_DIGIT_SIZE; /* 2**bin_exponent. */
- for (bit <<= (digits * HEX_DIGIT_SIZE + bin_exponent); !(mantissa & bit); bin_exponent--)
- bit >>= 1;
+ for (msb_mask <<= (digits * HEX_DIGIT_SIZE + bin_exponent); !(mantissa & msb_mask); msb_mask >>= 1)
+ bin_exponent--;
}
+ else if ((extra_shifts = digits - integer_digits) > 0)
+ msb_mask <<= extra_shifts * HEX_DIGIT_SIZE;
}
if (flags == 0)
{
if (sret)
@@ -211,38 +219,37 @@ strtold(const char *s, char **sret)
}
errno = EINVAL; /* No valid mantissa, no conversion could be performed. */
return 0.0L;
}
- if (mantissa)
+ if (digits >= max_digits)
{
/*
- * Normalize mantissa.
- * If there is still a valid hex character in the string
- * its bits will be inserted in the LSB of the mantissa,
- * else zeros will be inserted.
+ * Round half towards plus infinity (round half up).
*/
- for (digits = 0; !(mantissa & 0x8000000000000000ULL); digits++)
- mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
- if (IS_HEX_DIGIT(*next_char))
+ const int lsd = IS_DEC_DIGIT(*next_char) ? *next_char - '0' : /* Least significant hex digit. Will be rounded out. */
+ ((*next_char >= 'A') && (*next_char <= 'F')) ? *next_char - 'A' + 10 : *next_char - 'a' + 10;
+ if (lsd > 0x07)
{
- unsigned long long bits = IS_DEC_DIGIT(*next_char) ? *next_char - '0' :
- ((*next_char >= 'A') && (*next_char <= 'F')) ? *next_char - 'A' + 10 : *next_char - 'a' + 10;
-
- switch (digits)
+ mantissa += 0x0000000000000001ULL; /* Smallest float greater than x. */
+ if (!(mantissa & msb_mask))
{
- case 1:
- mantissa |= (0x01ULL & bits >> 3);
- break;
- case 2:
- mantissa |= (0x03ULL & bits >> 2);
- break;
- case 3:
- mantissa |= (0x07ULL & bits >> 1);
- break;
+ /* Overflow. */
+ mantissa >>= 1;
+ mantissa |= 0x8000000000000000ULL;
+ bin_exponent++;
}
}
+ }
+
+ if (mantissa)
+ {
+ /*
+ * Normalize mantissa.
+ */
+ for (digits = 0; !(mantissa & 0x8000000000000000ULL); digits++)
+ mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
/* At this point the mantissa is normalized and the exponent has been adjusted accordingly. */
}
/*
Index: djgpp/src/libc/c99/stdlib/strtof.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/c99/stdlib/strtof.c,v
retrieving revision 1.14
diff -p -U 5 -r1.14 strtof.c
--- djgpp/src/libc/c99/stdlib/strtof.c 9 Jul 2013 23:00:27 -0000 1.14
+++ djgpp/src/libc/c99/stdlib/strtof.c 9 Jul 2013 23:25:27 -0000
@@ -16,14 +16,17 @@
#include <ctype.h>
#include <string.h>
#include <libc/unconst.h>
#include <libc/ieee.h>
+
+#define MANTISSA_SIZE (23) /* Number binary digits in the fractional part of the mantissa. */
#define HEX_DIGIT_SIZE (4)
#define FLOAT_BIAS (0x7FU)
#define MAX_BIN_EXPONENT (127) /* Max. and min. binary exponent (inclusive) as */
#define MIN_BIN_EXPONENT (-126) /* defined in Intel manual (253665.pdf, Table 4.2). */
+#define IS_ZERO_DIGIT(x) ((x) == '0')
#define IS_DEC_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
#define IS_HEX_DIGIT(x) ((((x) >= 'A') && ((x) <= 'F')) || \
(((x) >= 'a') && ((x) <= 'f')) || \
IS_DEC_DIGIT(x))
#define IS_DEC_EXPONENT(x) (((x[0]) == 'E' || (x[0]) == 'e') && \
@@ -120,13 +123,13 @@ strtof(const char *s, char **sret)
}
/* Handle 0xH.HHH[p|P][+|-]DDD. */
if (!strnicmp("0x", s, 2) && (s[2] == '.' || IS_HEX_DIGIT(s[2])))
{
- int digits, integer_digits;
- int bin_exponent;
- unsigned long int mantissa;
+ const int max_digits = 1 + MANTISSA_SIZE / HEX_DIGIT_SIZE + 1; /* One more digit than fits into mantissa. */
+ int bin_exponent, digits, integer_digits;
+ unsigned long int mantissa, msb_mask;
_float_union_t ieee754;
/*
* Mantissa.
@@ -135,11 +138,11 @@ strtof(const char *s, char **sret)
*/
bin_exponent = 0;
integer_digits = 0;
mantissa = 0x00UL;
s += 2; /* Skip the hex prefix. */
- while (integer_digits < 8 && IS_HEX_DIGIT(*s))
+ while (integer_digits < max_digits && IS_HEX_DIGIT(*s))
{
flags = 1;
mantissa <<= HEX_DIGIT_SIZE;
mantissa |= IS_DEC_DIGIT(*s) ? *s - '0' :
((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
@@ -151,27 +154,29 @@ strtof(const char *s, char **sret)
{
/*
* Compute the binary exponent for a normalized mantissa by
* shifting the radix point inside the most significant hex digit.
*/
- unsigned long bit = 0x01UL;
for (digits = 0; IS_HEX_DIGIT(*s); s++)
digits++; /* Counts hex digits. */
+
+ msb_mask = 0x01UL;
bin_exponent = integer_digits * HEX_DIGIT_SIZE - 1; /* 2**bin_exponent. */
- for (bit <<= bin_exponent; !(mantissa & bit); bin_exponent--)
- bit >>= 1;
+ for (msb_mask <<= bin_exponent; !(mantissa & msb_mask); msb_mask >>= 1)
+ bin_exponent--;
bin_exponent += digits * HEX_DIGIT_SIZE;
+ integer_digits += digits;
}
+ digits = integer_digits;
if (*s == radix_point)
{
- int fraction_zeros = 0;
+ int extra_shifts, fraction_zeros = 0;
s++;
- digits = integer_digits;
- while ((digits - fraction_zeros) < 8 && IS_HEX_DIGIT(*s))
+ while ((digits - fraction_zeros) < max_digits && IS_HEX_DIGIT(*s))
{
flags = 1;
digits++; /* Counts hex digits. */
mantissa <<= HEX_DIGIT_SIZE;
mantissa |= IS_DEC_DIGIT(*s) ? *s - '0' :
@@ -184,15 +189,35 @@ strtof(const char *s, char **sret)
{
/*
* Compute the binary exponent for a normalized mantissa by
* shifting the radix point inside the most significant hex digit.
*/
- unsigned long bit = 0x01UL;
+ msb_mask = 0x01UL;
bin_exponent = -fraction_zeros * HEX_DIGIT_SIZE; /* 2**bin_exponent. */
- for (bit <<= (digits * HEX_DIGIT_SIZE + bin_exponent); !(mantissa & bit); bin_exponent--)
- bit >>= 1;
+ for (msb_mask <<= (digits * HEX_DIGIT_SIZE + bin_exponent); !(mantissa & msb_mask); msb_mask >>= 1)
+ bin_exponent--;
+ }
+ else if ((extra_shifts = digits - integer_digits) > 0)
+ msb_mask <<= extra_shifts * HEX_DIGIT_SIZE;
+ }
+
+ if (digits >= max_digits)
+ {
+ /*
+ * Round half towards plus infinity (round half up).
+ */
+ const int lsd = 0x0000000FUL & mantissa; /* Least significant hex digit. Will be rounded out. */
+ if (lsd > 0x07)
+ {
+ mantissa += 0x00000010UL; /* Smallest float greater than x. */
+ if (!(mantissa & msb_mask))
+ {
+ /* Overflow. */
+ mantissa >>= 1;
+ bin_exponent++;
+ }
}
}
if (flags == 0)
{
- Raw text -