Mail Archives: djgpp-workers/2008/04/10/17:34:03
Am Dienstag, 8. April 2008 22:50 schrieben Sie:
>
> Please add suitable tests to the test for these, and if it all passes,
> it's OK.
I have written a small test program to test a new version of strtold.
This is the output it produces:
Integers.
test string: <0x1 ###> endp: < ###> value: 1.000000e+00
test string: <0x2 ###> endp: < ###> value: 2.000000e+00
test string: <0xF ###> endp: < ###> value: 1.500000e+01
test string: <0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ###> endp: < ###> value: 5.146315e+74
Zeros
test string: <0x0 ###> endp: < ###> value: 0.000000e+00
test string: <0x0. ###> endp: < ###> value: 0.000000e+00
test string: <0x.0 ###> endp: < ###> value: 0.000000e+00
test string: <0x000.000 ###> endp: < ###> value: 0.000000e+00
test string: <0x0.0P-00###> endp: <###> value: 0.000000e+00
test string: <0x0.0P+00###> endp: <###> value: 0.000000e+00
test string: <0x0.P-00###> endp: <###> value: 0.000000e+00
test string: <0x.0P-00###> endp: <###> value: 0.000000e+00
Floating points.
test string: <0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+123###> endp: <###> value: 1.533599e-33
test string: <0x0.0P+9999999999999999###> endp: <###> value: 0.000000e+00
test string: <0x1. ###> endp: < ###> value: 1.000000e+00
test string: <0x1.P00###> endp: <###> value: 1.000000e+00
test string: <0x1P+0###> endp: <###> value: 1.000000e+00
test string: <0x.1P-0###> endp: <###> value: 6.250000e-02
test string: <0x12345678.9ABCDEF1p+12345 ###> endp: < ###> value: 5.014109e+3724
test string: <0xF.EDcba ###> endp: < ###> value: 1.592889e+01
test string: <0x123456789abcdef.fedcba987654321 ###> endp: < ###> value: 8.198553e+16
Overflow and underflow errors.
test string: <0x1.0P+9999999999999999###> endp: <###> value: Inf ERANGE
test string: <0x7.8P+123456789###> endp: <###> value: Inf ERANGE
test string: <0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+987654321###> endp: <###> value: Inf ERANGE
test string: <0x1.0P-9999999999999999###> endp: <###> value: 0.000000e+00 ERANGE
test string: <0x7.8P-123456789###> endp: <###> value: 0.000000e+00 ERANGE
test string: <0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P-987654321###> endp: <###> value: 0.000000e+00 ERANGE
Parsing errors.
test string: <0x 123 ###> endp: < 123 ###> value: 0.000000e+00 EINVAL
test string: <0x123. 123 ###> endp: < 123 ###> value: 2.910000e+02
test string: <0x123.123 p123 ###> endp: < p123 ###> value: 2.910710e+02
test string: <0x123.123p 123 ###> endp: <p 123 ###> value: 2.910710e+02
If I have missed some test case, please let me know. There are 3 versions of
the program with different value ranges to test strto[dfld]. Because my linux
does not support hex floating strings I have checked against the strtod version
from gnulib. Of course the test programs shall only test the new features.
Regards,
Juan M. Guerrero
2008-04-10 Juan Manuel Guerrero <juan DOT guerrero AT gmx DOT de>
Diffs against djgpp CVS head of 2008-04-08.
* src/libc/ansi/stdlib/strtold.c: Conversion of hex floating point
strings of the form 0xH.HHH[P|p][+|-]DDD implemented.
* src/libc/ansi/stdlib/strtold.txh: Info about hex floating point
string conversion added.
* src/libc/ansi/stdlib/strtod.c: Conversion of hex floating point
strings of the form 0xH.HHH[P|p][+|-]DDD implemented.
* src/libc/ansi/stdlib/strtod.txh: Info about hex floating point
string conversion added.
* src/libc/c99/stdlib/strtof.c: Conversion of hex floating point
strings of the form 0xH.HHH[P|p][+|-]DDD implemented.
* src/libc/c99/stdlib/strtof.txh: Info about hex floating point
string conversion added.
*tests/libc/ansi/stdlib/makefile: strtold.c added to the target list.
*tests/libc/ansi/stdlib/strtod.c: Test cases for hex float string
conversion added.
*tests/libc/ansi/stdlib/strtold.c: Initial release.
*tests/libc/c99/stdlib/makefile: strtof.c added to the target list.
*tests/libc/c99/stdlib/strtof.c: Initial release.
diff -aprNU3 djgpp.orig/src/libc/ansi/stdlib/strtod.c djgpp/src/libc/ansi/stdlib/strtod.c
--- djgpp.orig/src/libc/ansi/stdlib/strtod.c 2008-04-08 17:55:48 +0000
+++ djgpp/src/libc/ansi/stdlib/strtod.c 2008-04-10 21:22:46 +0000
@@ -15,6 +15,18 @@
#include <libc/unconst.h>
#include <libc/ieee.h>
+#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_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_EXPONENT(x) (((x[0]) == 'P' || (x[0]) == 'p') && \
+ (x[1] == '+' || x[1] == '-' || IS_DEC_DIGIT(x[1])))
+
+
double
strtod(const char *s, char **sret)
{
@@ -113,8 +125,170 @@ strtod(const char *s, char **sret)
return (t.d);
}
+ /* Handle 0xH.HHH[p|P][+|-]DDD. */
+ if ( ! strnicmp( "0x", s, 2 ) )
+ {
+ int digits, integer_digits;
+ long int bin_exponent;
+ unsigned long long int mantissa;
+ _double_union_t d_value;
+
+
+ /*
+ * Mantissa.
+ * 13 hex digits fit into the fraction part.
+ */
+ bin_exponent = 0;
+ integer_digits = 0;
+ mantissa = 0x00ULL;
+ s += 2;
+ while (integer_digits < 16 && 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;
+ if (mantissa) /* Discarts leading zeros. */
+ integer_digits++; /* Counts hex digits. 16**integer_digits. */
+ s++;
+ }
+ if (integer_digits)
+ {
+ /*
+ * Compute the binary exponent for a normalized mantissa by
+ * shifting the decimal point inside the most significant hex digit.
+ */
+ unsigned long long bit = 0x01ULL;
+
+ digits = 0;
+ if (IS_HEX_DIGIT(*s))
+ {
+ char *t = unconst(s, char *);
+
+ for (; IS_HEX_DIGIT(*t); t++)
+ digits++; /* Counts hex digits. */
+ }
+ bin_exponent = integer_digits * HEX_DIGIT_SIZE - 1; /* 2**bin_exponent. */
+ for (bit <<= bin_exponent; !(mantissa & bit); bin_exponent--)
+ bit >>= 1;
+ bin_exponent += digits * HEX_DIGIT_SIZE;
+ }
+
+ if (*s == decimal)
+ {
+ int fraction_zeros = 0;
+
+ s++;
+ digits = integer_digits;
+ while ((digits - fraction_zeros) < 16 && IS_HEX_DIGIT(*s))
+ {
+ flags = 1;
+ digits++; /* Counts hex digits. */
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ if (mantissa == 0)
+ fraction_zeros++; /* Counts hex zeros. 16**(-fraction_zeros + 1). */
+ s++;
+ }
+ if (!integer_digits && mantissa)
+ {
+ /*
+ * Compute the binary exponent for a normalized mantissa by
+ * shifting the decimal point inside the most significant hex digit.
+ */
+ unsigned long long bit = 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;
+ }
+ }
+
+ if (!flags)
+ {
+ if (sret)
+ *sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
+ return 0.0L;
+ }
+
+ if (mantissa)
+ {
+ /*
+ * Normalize mantissa.
+ */
+ while (!(mantissa & 0x8000000000000000ULL))
+ mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
+ mantissa >>= (63 - 52);
+ /* At this point the mantissa is normalized and the exponent has been adjusted accordingly. */
+ }
+
+
+ /*
+ * After discarting all hex digits left,
+ * if the next character is P or p
+ * continue with the extraction of the
+ * exponent, else any other character
+ * that have appeared terminates the number.
+ */
+ while (IS_HEX_DIGIT(*s))
+ s++;
+
+ /*
+ * Exponent.
+ */
+ if (IS_EXPONENT(s))
+ {
+ long int exponent = 0.0;
+ s++;
+ if (*s == '+')
+ s++;
+ else if (*s == '-')
+ {
+ esign = -1;
+ s++;
+ }
+
+ while ((esign * exponent + bin_exponent) < (MAX_BIN_EXPONENT + 1) && IS_DEC_DIGIT(*s))
+ {
+ exponent *= 10;
+ exponent += *s - '0';
+ s++;
+ }
+ bin_exponent += esign * exponent; /* 2**bin_exponent. */
+ while (IS_DEC_DIGIT(*s))
+ s++; /* Discart rest of exponent. */
+ }
+
+
+ if (sret)
+ *sret = unconst(s, char *);
+ if (mantissa)
+ {
+ if (bin_exponent > MAX_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return sign * HUGE_VAL;
+ }
+ else if(bin_exponent < MIN_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return 0.0;
+ }
+ d_value.dt.sign = (sign == 1) ? 0 : 1;
+ d_value.dt.exponent = 0x7FFFU & (bin_exponent + DOUBLE_BIAS);
+ d_value.dt.mantissah = 0x000FFFFFUL & (mantissa >> 32);
+ d_value.dt.mantissal = 0xFFFFFFFFUL & mantissa;
+ }
+ else
+ d_value.d = sign * 0.0;
+
+ return d_value.d;
+ }
+
/* Handle ordinary numbers. */
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 1;
r *= 10.0;
@@ -151,7 +325,7 @@ strtod(const char *s, char **sret)
s++;
esign = -1;
}
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
e *= 10;
e += *s - '0';
diff -aprNU3 djgpp.orig/src/libc/ansi/stdlib/strtod.txh djgpp/src/libc/ansi/stdlib/strtod.txh
--- djgpp.orig/src/libc/ansi/stdlib/strtod.txh 2003-10-25 11:15:58 +0000
+++ djgpp/src/libc/ansi/stdlib/strtod.txh 2008-04-10 22:31:50 +0000
@@ -5,19 +5,19 @@
@example
#include <stdlib.h>
-double strtod(const char *s, char **endp);
+double strtod(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
-This function converts as many characters of @var{s} as look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number})'',
-``NaN(@var{optional octal-number})''
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+This function converts as many characters of @var{s} that look like a
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
@subheading Return Value
@@ -66,6 +66,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89ABCDefP+123 foobar";
char *bp;
double x, x2, x3, x4;
@@ -73,5 +74,6 @@ x = strtod(buf, &bp);
x2 = strtod(buf2, &bp);
x3 = strtod(buf3, &bp);
x4 = strtod(buf4, &bp);
+x5 = strtod(buf5, &bp);
@end example
diff -aprNU3 djgpp.orig/src/libc/ansi/stdlib/strtold.c djgpp/src/libc/ansi/stdlib/strtold.c
--- djgpp.orig/src/libc/ansi/stdlib/strtold.c 2003-11-08 12:19:40 +0000
+++ djgpp/src/libc/ansi/stdlib/strtold.c 2008-04-10 21:24:16 +0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
@@ -6,11 +7,23 @@
#include <locale.h>
#include <stdlib.h>
#include <ctype.h>
+#include <errno.h>
#include <math.h>
#include <string.h>
#include <libc/unconst.h>
#include <libc/ieee.h>
+#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_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_EXPONENT(x) (((x[0]) == 'P' || (x[0]) == 'p') && \
+ (x[1] == '+' || x[1] == '-' || IS_DEC_DIGIT(x[1])))
+
static long double powten[] =
{
1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L,
@@ -116,8 +129,193 @@ strtold(const char *s, char **sret)
return (t.ld);
}
+ /* Handle 0xH.HHH[p|P][+|-]DDD. */
+ if ( ! strnicmp( "0x", s, 2 ) )
+ {
+ int digits, integer_digits;
+ long long int bin_exponent;
+ unsigned long long int mantissa;
+ _longdouble_union_t ld_value;
+
+
+ /*
+ * Mantissa.
+ * 16 hex digits fit into the mantissa
+ * including the explicit integer bit.
+ */
+ bin_exponent = 0;
+ integer_digits = 0;
+ mantissa = 0x00ULL;
+ s += 2;
+ while (integer_digits < 16 && 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;
+ if (mantissa) /* Discarts leading zeros. */
+ integer_digits++; /* Counts hex digits. 16**integer_digits. */
+ s++;
+ }
+ if (integer_digits)
+ {
+ /*
+ * Compute the binary exponent for a normalized mantissa by
+ * shifting the decimal point inside the most significant hex digit.
+ */
+ unsigned long long bit = 0x01ULL;
+
+ digits = 0;
+ if (IS_HEX_DIGIT(*s))
+ {
+ char *t = unconst(s, char *);
+
+ for (; IS_HEX_DIGIT(*t); t++)
+ digits++; /* Counts hex digits. */
+ }
+ bin_exponent = integer_digits * HEX_DIGIT_SIZE - 1; /* 2**bin_exponent. */
+ for (bit <<= bin_exponent; !(mantissa & bit); bin_exponent--)
+ bit >>= 1;
+ bin_exponent += digits * HEX_DIGIT_SIZE;
+ }
+
+ if (*s == decimal)
+ {
+ int fraction_zeros = 0;
+
+ s++;
+ digits = integer_digits;
+ while ((digits - fraction_zeros) < 16 && IS_HEX_DIGIT(*s))
+ {
+ flags = 1;
+ digits++; /* Counts hex digits. */
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ if (mantissa == 0)
+ fraction_zeros++; /* Counts hex zeros. 16**(-fraction_zeros + 1). */
+ s++;
+ }
+ if (!integer_digits && mantissa)
+ {
+ /*
+ * Compute the binary exponent for a normalized mantissa by
+ * shifting the decimal point inside the most significant hex digit.
+ */
+ unsigned long long bit = 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;
+ }
+ }
+
+ if (!flags)
+ {
+ if (sret)
+ *sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
+ return 0.0L;
+ }
+
+ if (mantissa)
+ {
+ /*
+ * 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.
+ */
+ for (digits = 0; !(mantissa & 0x8000000000000000ULL); digits++)
+ mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
+ if (IS_HEX_DIGIT(*s))
+ {
+ unsigned long long bits = IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+
+ switch (digits)
+ {
+ case 1:
+ mantissa |= (0x01ULL & bits >> 3);
+ s++;
+ break;
+ case 2:
+ mantissa |= (0x03ULL & bits >> 2);
+ s++;
+ break;
+ case 3:
+ mantissa |= (0x07ULL & bits >> 1);
+ s++;
+ break;
+ }
+ }
+ /* At this point the mantissa is normalized and the exponent has been adjusted accordingly. */
+ }
+
+
+ /*
+ * After discarting all hex digits left,
+ * if the next character is P or p
+ * continue with the extracting of the
+ * exponent, else any other character
+ * that have appeared terminates the number.
+ */
+ while (IS_HEX_DIGIT(*s))
+ s++;
+
+ /*
+ * Exponent.
+ */
+ if (IS_EXPONENT(s))
+ {
+ long long int exponent = 0.0L;
+ s++;
+ if (*s == '+')
+ s++;
+ else if (*s == '-')
+ {
+ esign = -1;
+ s++;
+ }
+
+ while ((esign * exponent + bin_exponent) < (MAX_BIN_EXPONENT + 1) && IS_DEC_DIGIT(*s))
+ {
+ exponent *= 10;
+ exponent += *s - '0';
+ s++;
+ }
+ bin_exponent += esign * exponent; /* 2**bin_exponent. */
+ while (IS_DEC_DIGIT(*s))
+ s++; /* Discart rest of exponent. */
+ }
+
+ if (sret)
+ *sret = unconst(s, char *);
+ if (mantissa)
+ {
+ if (bin_exponent > MAX_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return sign * HUGE_VALL;
+ }
+ else if(bin_exponent < MIN_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return 0.0L;
+ }
+ ld_value.ldt.sign = (sign == 1) ? 0 : 1;
+ ld_value.ldt.exponent = 0x7FFFU & (bin_exponent + LONG_DOUBLE_BIAS);
+ ld_value.ldt.mantissah = 0xFFFFFFFFUL & (mantissa >> 32);
+ ld_value.ldt.mantissal = 0xFFFFFFFFUL & mantissa;
+ }
+ else
+ ld_value.ld = sign * 0.0L;
+
+ return ld_value.ld;
+ }
+
/* Handle ordinary numbers. */
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 1;
r *= 10.0L;
@@ -128,7 +326,7 @@ strtold(const char *s, char **sret)
if (*s == decimal)
{
s++;
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 2;
r *= 10.0L;
@@ -141,6 +339,7 @@ strtold(const char *s, char **sret)
{
if (sret)
*sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
return 0.0L;
}
@@ -154,7 +353,7 @@ strtold(const char *s, char **sret)
s++;
esign = -1;
}
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
e *= 10;
e += *s - '0';
diff -aprNU3 djgpp.orig/src/libc/ansi/stdlib/strtold.txh djgpp/src/libc/ansi/stdlib/strtold.txh
--- djgpp.orig/src/libc/ansi/stdlib/strtold.txh 2003-10-25 11:15:58 +0000
+++ djgpp/src/libc/ansi/stdlib/strtold.txh 2008-04-10 22:31:50 +0000
@@ -5,26 +5,26 @@
@example
#include <stdlib.h>
-long double _strtold(const char *s, char **endp);
+long double _strtold(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
This function converts as many characters of @var{s} that look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number})'',
-``NaN(@var{optional octal-number})''
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
There is also a standardised version of this function:
@code{strtold} (@pxref{strtold}).
@subheading Return Value
-The value representedby @var{s}.
+The value represented by @var{s}.
If @var{s} is ``Inf'' or ``Infinity'', with any variations of case and
optionally prefixed with ``+'' or ``-'', the return value is
@@ -63,6 +63,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89ABCDefP+1234 foobar";
char *bp;
long double x, x2, x3, x4;
@@ -70,6 +71,7 @@ x = _strtold(buf, &bp);
x2 = _strtold(buf2, &bp);
x3 = _strtold(buf3, &bp);
x4 = _strtold(buf4, &bp);
+x5 = _strtold(buf5, &bp);
@end example
@node strtold, string
@@ -79,19 +81,19 @@ x4 = _strtold(buf4, &bp);
@example
#include <stdlib.h>
-long double strtold(const char *s, char **endp);
+long double strtold(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
This function converts as many characters of @var{s} that look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number}),
-``NaN(@var{optional octal-number})
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
@subheading Return Value
@@ -137,6 +139,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89abcdefP+1234 foobar";
char *bp;
long double x, x2, x3, x4;
@@ -144,4 +147,5 @@ x = strtold(buf, &bp);
x2 = strtold(buf2, &bp);
x3 = strtold(buf3, &bp);
x4 = strtold(buf4, &bp);
+x5 = strtold(buf5, &bp);
@end example
diff -aprNU3 djgpp.orig/src/libc/c99/stdlib/strtof.c djgpp/src/libc/c99/stdlib/strtof.c
--- djgpp.orig/src/libc/c99/stdlib/strtof.c 2008-04-08 18:50:30 +0000
+++ djgpp/src/libc/c99/stdlib/strtof.c 2008-04-10 21:25:22 +0000
@@ -1,3 +1,4 @@
+/* Copyright (C) 2008 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
@@ -16,6 +17,18 @@
#include <libc/unconst.h>
#include <libc/ieee.h>
+#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_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_EXPONENT(x) (((x[0]) == 'P' || (x[0]) == 'p') && \
+ (x[1] == '+' || x[1] == '-' || IS_DEC_DIGIT(x[1])))
+
+
float
strtof(const char *s, char **sret)
{
@@ -113,8 +126,170 @@ strtof(const char *s, char **sret)
return (t.f);
}
+ /* Handle 0xH.HHH[p|P][+|-]DDD. */
+ if ( ! strnicmp( "0x", s, 2 ) )
+ {
+ int digits, integer_digits;
+ int bin_exponent;
+ unsigned long int mantissa;
+ _float_union_t f_value;
+
+
+ /*
+ * Mantissa.
+ * 6 hex digits fit into the mantissa
+ * including the implicit integer bit.
+ */
+ bin_exponent = 0;
+ integer_digits = 0;
+ mantissa = 0x00U;
+ s += 2;
+ while (integer_digits < 8 && 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;
+ if (mantissa) /* Discarts leading zeros. */
+ integer_digits++; /* Counts hex digits. 16**integer_digits. */
+ s++;
+ }
+ if (integer_digits)
+ {
+ /*
+ * Compute the binary exponent for a normalized mantissa by
+ * shifting the decimal point inside the most significant hex digit.
+ */
+ unsigned long long bit = 0x01ULL;
+
+ digits = 0;
+ if (IS_HEX_DIGIT(*s))
+ {
+ char *t = unconst(s, char *);
+
+ for (; IS_HEX_DIGIT(*t); t++)
+ digits++; /* Counts hex digits. */
+ }
+ bin_exponent = integer_digits * HEX_DIGIT_SIZE - 1; /* 2**bin_exponent. */
+ for (bit <<= bin_exponent; !(mantissa & bit); bin_exponent--)
+ bit >>= 1;
+ bin_exponent += digits * HEX_DIGIT_SIZE;
+ }
+
+ if (*s == decimal)
+ {
+ int fraction_zeros = 0;
+
+ s++;
+ digits = integer_digits;
+ while ((digits - fraction_zeros) < 16 && IS_HEX_DIGIT(*s))
+ {
+ flags = 1;
+ digits++; /* Counts hex digits. */
+ mantissa <<= HEX_DIGIT_SIZE;
+ mantissa += IS_DEC_DIGIT(*s) ? *s - '0' :
+ ((*s >= 'A') && (*s <= 'F')) ? *s - 'A' + 10 : *s - 'a' + 10;
+ if (mantissa == 0)
+ fraction_zeros++; /* Counts hex zeros. 16**(-fraction_zeros + 1). */
+ s++;
+ }
+ if (!integer_digits && mantissa)
+ {
+ /*
+ * Compute the binary exponent for a normalized mantissa by
+ * shifting the decimal point inside the most significant hex digit.
+ */
+ unsigned long long bit = 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;
+ }
+ }
+
+ if (!flags)
+ {
+ if (sret)
+ *sret = unconst(s, char *);
+ errno = EINVAL; /* No valid mantissa, no convertion could be performed. */
+ return 0.0;
+ }
+
+ if (mantissa)
+ {
+ /*
+ * Normalize mantissa.
+ */
+ while (!(mantissa & 0x80000000ULL))
+ mantissa <<= 1; /* Shift a binary 1 into the integer part of the mantissa. */
+ mantissa >>= (31 - 23);
+ /* At this point the mantissa is normalized and the exponent has been adjusted accordingly. */
+ }
+
+
+ /*
+ * After discarting all hex digits left,
+ * if the next character is P or p
+ * continue with the extracting of the
+ * exponent, else any other character
+ * that have appeared terminates the number.
+ */
+ while (IS_HEX_DIGIT(*s))
+ s++;
+
+ /*
+ * Exponent.
+ */
+ if (IS_EXPONENT(s))
+ {
+ int exponent = 0.0;
+ s++;
+ if (*s == '+')
+ s++;
+ else if (*s == '-')
+ {
+ esign = -1;
+ s++;
+ }
+
+ while ((esign * exponent + bin_exponent) < (MAX_BIN_EXPONENT + 1) && IS_DEC_DIGIT(*s))
+ {
+ exponent *= 10;
+ exponent += *s - '0';
+ s++;
+ }
+ bin_exponent += esign * exponent; /* 2**bin_exponent. */
+ while (IS_DEC_DIGIT(*s))
+ s++; /* Discart rest of exponent. */
+ }
+
+
+ if (sret)
+ *sret = unconst(s, char *);
+ if (mantissa)
+ {
+ if (bin_exponent > MAX_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return sign * HUGE_VALF;
+ }
+ else if(bin_exponent < MIN_BIN_EXPONENT)
+ {
+ errno = ERANGE;
+ return 0.0;
+ }
+ f_value.ft.sign = (sign == 1) ? 0 : 1;
+ f_value.ft.exponent = 0x07FFU & (bin_exponent + FLOAT_BIAS);
+ f_value.ft.mantissa = 0x007FFFFFU & mantissa;
+ }
+ else
+ f_value.f = sign * 0.0;
+
+ return f_value.f;
+ }
+
/* Handle ordinary numbers. */
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
flags |= 1;
r *= 10.0;
@@ -151,7 +326,7 @@ strtof(const char *s, char **sret)
s++;
esign = -1;
}
- while ((*s >= '0') && (*s <= '9'))
+ while (IS_DEC_DIGIT(*s))
{
e *= 10;
e += *s - '0';
diff -aprNU3 djgpp.orig/src/libc/c99/stdlib/strtof.txh djgpp/src/libc/c99/stdlib/strtof.txh
--- djgpp.orig/src/libc/c99/stdlib/strtof.txh 2003-10-25 11:16:20 +0000
+++ djgpp/src/libc/c99/stdlib/strtof.txh 2008-04-10 22:31:50 +0000
@@ -5,19 +5,19 @@
@example
#include <stdlib.h>
-float strtof(const char *s, char **endp);
+float strtof(const char *@var{s}, char **@var{endp});
@end example
@subheading Description
-This function converts as many characters of @var{s} as look like a
-floating point number into that number. It also recognises
-(case-insensitively) ``Inf'', ``Infinity'', ``NaN'',
-``NaN(@var{optional decimal-number})'',
-``NaN(@var{optional octal-number})''
-and ``NaN(@var{optional hex-number})''. If @var{endp} is not a null
-pointer, a pointer to the first unconverted character will be stored
-in the location pointed to by @var{endp}.
+This function converts as many characters of @var{s} that look like a
+floating point number into that number. The floating point number may
+also take the form of a hex floating point number (case-insensitively)
+like this [+|-]0xH.HHHp[+|-]DDD. It also recognises (case-insensitively)
+``Inf'', ``Infinity'', ``NaN'', ``NaN(@var{optional decimal-number})'',
+``NaN(@var{optional octal-number})'' and ``NaN(@var{optional hex-number})''.
+If @var{endp} is not a null pointer, a pointer to the first unconverted
+character will be stored in the location pointed to by @var{endp}.
@subheading Return Value
@@ -65,6 +65,7 @@ char buf[] = "123ret";
char buf2[] = "0x123ret";
char buf3[] = "NAN(123)";
char buf4[] = "NAN(0x123)";
+char buf5[] = "0x1234567.89ABCDefP+12 foobar";
char *bp;
float x, x2, x3, x4;
@@ -72,4 +73,5 @@ x = strtof(buf, &bp);
x2 = strtof(buf2, &bp);
x3 = strtof(buf3, &bp);
x4 = strtof(buf4, &bp);
+x5 = strtod(buf5, &bp);
@end example
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdlib/makefile djgpp/tests/libc/ansi/stdlib/makefile
--- djgpp.orig/tests/libc/ansi/stdlib/makefile 2005-05-11 19:59:36 +0000
+++ djgpp/tests/libc/ansi/stdlib/makefile 2008-04-10 22:41:04 +0000
@@ -4,6 +4,7 @@ SRC += env.c
SRC += getenv.c
SRC += mbstowcs.c
SRC += shell.c
+SRC += strtold.c
SRC += strtod.c
SRC += system.c
SRC += system2.c
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdlib/strtod.c djgpp/tests/libc/ansi/stdlib/strtod.c
--- djgpp.orig/tests/libc/ansi/stdlib/strtod.c 2003-05-10 17:16:28 +0000
+++ djgpp/tests/libc/ansi/stdlib/strtod.c 2008-04-10 22:40:42 +0000
@@ -19,6 +19,48 @@ static const char *testnum[] = {
"nan(0)", /* nan */
"Nan(1)", /* nan */
"-NaN(0xfffff)", /* nan */
+ "-NaN(0xfffff.ffffffp+123456)", /* nan */
+ 0
+};
+
+static const char *test_string[] = {
+ /* Integers. */
+ "0x1 ###",
+ "0x2 ###",
+ "0xF ###",
+ "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ###",
+ /* Zeros. */
+ "0x0 ###",
+ "0x0. ###",
+ "0x.0 ###",
+ "0x000.000 ###",
+ "0x0.0P-00###",
+ "0x0.0P+00###",
+ "0x0.P-00###",
+ "0x.0P-00###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+123###",
+ "0x0.0P+9999999999999999###",
+ /* Floating points. */
+ "0x1. ###",
+ "0x1.P00###",
+ "0x1P+0###",
+ "0x.1P-0###",
+ "0x12345678.9ABCDEF1p+345 ###",
+ "0xF.EDcba ###",
+ "0x123456789abcdef.fedcba987654321 ###",
+ /* Overflow. */
+ "0x1.0P+9999999999999999###",
+ "0x7.8P+123456###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+987654321###",
+ /* Underflow. */
+ "0x1.0P-9999999999999999###",
+ "0x7.8P-123456789###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P-987654321###",
+ /* Errors. */
+ "0x 123 ###",
+ "0x123. 123 ###",
+ "0x123.123 p123 ###",
+ "0x123.123p 123 ###",
0
};
@@ -38,5 +80,22 @@ int main (void)
}
}
+ for (i = 0; test_string[i]; i++)
+ {
+ errno = 0;
+ result = strtod(test_string[i], &endp);
+ switch (errno)
+ {
+ case 0:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %e\n", test_string[i], endp, result);
+ break;
+ case ERANGE:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %e ERANGE\n", test_string[i], endp, result);
+ break;
+ case EINVAL:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %e EINVAL\n", test_string[i], endp, result);
+ break;
+ }
+ }
return 0;
}
diff -aprNU3 djgpp.orig/tests/libc/ansi/stdlib/strtold.c djgpp/tests/libc/ansi/stdlib/strtold.c
--- djgpp.orig/tests/libc/ansi/stdlib/strtold.c 1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/ansi/stdlib/strtold.c 2008-04-10 22:40:42 +0000
@@ -0,0 +1,102 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+static const char *testnum[] = {
+ "0e200",
+ "1e2000",
+ "0e2000000000", /* suggested by Morten Welinder */
+ "1e6000000000", /* overflow */
+ "1e5000", /* ditto */
+ "1e-5000", /* underflow */
+ "InF", /* infinity */
+ "-inf", /* infinity */
+ "infinity", /* infinity */
+ "-inFinitY", /* infinity */
+ "nAn", /* nan */
+ "-nan", /* nan */
+ "Nan()", /* nan */
+ "nan(0)", /* nan */
+ "Nan(1)", /* nan */
+ "-NaN(0xffFFFFFfff)", /* nan */
+ "-NaN(0xfffff.ffffffp+123456)", /* nan */
+ 0
+};
+
+static const char *test_string[] = {
+ /* Integers. */
+ "0x1 ###",
+ "0x2 ###",
+ "0xF ###",
+ "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ###",
+ /* Zeros. */
+ "0x0 ###",
+ "0x0. ###",
+ "0x.0 ###",
+ "0x000.000 ###",
+ "0x0.0P-00###",
+ "0x0.0P+00###",
+ "0x0.P-00###",
+ "0x.0P-00###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+123###",
+ "0x0.0P+9999999999999999###",
+ /* Floating points. */
+ "0x1. ###",
+ "0x1.P00###",
+ "0x1P+0###",
+ "0x.1P-0###",
+ "0x12345678.9ABCDEF1p+12345 ###",
+ "0xF.EDcba ###",
+ "0x123456789abcdef.fedcba987654321 ###",
+ /* Overflow. */
+ "0x1.0P+9999999999999999###",
+ "0x7.8P+123456789###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+987654321###",
+ /* Underflow. */
+ "0x1.0P-9999999999999999###",
+ "0x7.8P-123456789###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P-987654321###",
+ /* Errors. */
+ "0x 123 ###",
+ "0x123. 123 ###",
+ "0x123.123 p123 ###",
+ "0x123.123p 123 ###",
+ 0
+};
+
+int main(void)
+{
+ char *endp;
+ long double result;
+ int i;
+
+ for (i = 0; testnum[i]; i++)
+ {
+ printf ("%20s -> %-20.15g\n", testnum[i], strtold (testnum[i], (char **)0));
+ if (errno)
+ {
+ perror ("strtold");
+ errno = 0;
+ }
+ }
+
+ for (i = 0; test_string[i]; i++)
+ {
+ errno = 0;
+ result = strtold(test_string[i], &endp);
+ switch (errno)
+ {
+ case 0:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %Le\n", test_string[i], endp, result);
+ break;
+ case ERANGE:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %Le ERANGE\n", test_string[i], endp, result);
+ break;
+ case EINVAL:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %Le EINVAL\n", test_string[i], endp, result);
+ break;
+ }
+ }
+ return 0;
+}
+
diff -aprNU3 djgpp.orig/tests/libc/c99/stdlib/makefile djgpp/tests/libc/c99/stdlib/makefile
--- djgpp.orig/tests/libc/c99/stdlib/makefile 2003-01-08 20:18:48 +0000
+++ djgpp/tests/libc/c99/stdlib/makefile 2008-04-10 22:43:58 +0000
@@ -2,5 +2,6 @@ TOP=../..
SRC += t-_exit.c
SRC += t-strtof.c
+SRC += strtof.c
include $(TOP)/../makefile.inc
diff -aprNU3 djgpp.orig/tests/libc/c99/stdlib/strtof.c djgpp/tests/libc/c99/stdlib/strtof.c
--- djgpp.orig/tests/libc/c99/stdlib/strtof.c 1970-01-01 00:00:00 +0000
+++ djgpp/tests/libc/c99/stdlib/strtof.c 2008-04-10 22:43:44 +0000
@@ -0,0 +1,101 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+static const char *testnum[] = {
+ "0e20",
+ "1e200",
+ "0e2000000000", /* suggested by Morten Welinder */
+ "1e6000000000", /* overflow */
+ "1e400", /* ditto */
+ "1e-400", /* underflow */
+ "InF", /* infinity */
+ "-inf", /* infinity */
+ "infinity", /* infinity */
+ "-inFinitY", /* infinity */
+ "nAn", /* nan */
+ "-nan", /* nan */
+ "Nan()", /* nan */
+ "nan(0)", /* nan */
+ "Nan(1)", /* nan */
+ "-NaN(0xfffff)", /* nan */
+ "-NaN(0xfffff.ffffffp+123456)", /* nan */
+ 0
+};
+
+static const char *test_string[] = {
+ /* Integers. */
+ "0x1 ###",
+ "0x2 ###",
+ "0xF ###",
+ "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef ###",
+ /* Zeros. */
+ "0x0 ###",
+ "0x0. ###",
+ "0x.0 ###",
+ "0x000.000 ###",
+ "0x0.0P-00###",
+ "0x0.0P+00###",
+ "0x0.P-00###",
+ "0x.0P-00###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+23###",
+ "0x0.0P+9999999999999999###",
+ /* Floating points. */
+ "0x1. ###",
+ "0x1.P00###",
+ "0x1P+0###",
+ "0x.1P-0###",
+ "0x12345678.9ABCDEF1p+34 ###",
+ "0xF.EDcba ###",
+ "0x123456789abcdef.fedcba987654321 ###",
+ /* Overflow. */
+ "0x1.0P+9999999999999999###",
+ "0x7.8P+1234###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P+987654321###",
+ /* Underflow. */
+ "0x1.0P-9999999999999999###",
+ "0x7.8P-123456###",
+ "0X00000.0000000000000000000000000000000000000000000000000000000000FED0123P-987654###",
+ /* Errors. */
+ "0x 123 ###",
+ "0x123. 123 ###",
+ "0x123.123 p123 ###",
+ "0x123.123p 123 ###",
+ 0
+};
+
+int main (void)
+{
+ int i;
+
+ errno = 0;
+
+ for (i = 0; testnum[i]; i++)
+ {
+ printf ("%20s -> %-20.15g\n", testnum[i], strtof (testnum[i], (char **)0));
+ if (errno)
+ {
+ perror ("strtod");
+ errno = 0;
+ }
+ }
+
+ for (i = 0; test_string[i]; i++)
+ {
+ errno = 0;
+ result = strtof(test_string[i], &endp);
+ switch (errno)
+ {
+ case 0:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %e\n", test_string[i], endp, result);
+ break;
+ case ERANGE:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %e ERANGE\n", test_string[i], endp, result);
+ break;
+ case EINVAL:
+ printf("test string: <%s>\tendp: <%s>\tvalue: %e EINVAL\n", test_string[i], endp, result);
+ break;
+ }
+ }
+ return 0;
+}
- Raw text -