[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gawk-diffs] [SCM] gawk branch, long-double, updated. 26bfdfdc9bb065dfc1
From: |
John Haque |
Subject: |
[gawk-diffs] [SCM] gawk branch, long-double, updated. 26bfdfdc9bb065dfc1ea7f2494070f826e81b874 |
Date: |
Wed, 23 Jan 2013 12:27:58 +0000 |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".
The branch, long-double has been updated
via 26bfdfdc9bb065dfc1ea7f2494070f826e81b874 (commit)
from ecf5161fabf105c8a50834e5bbc7ada5b322ce03 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=26bfdfdc9bb065dfc1ea7f2494070f826e81b874
commit 26bfdfdc9bb065dfc1ea7f2494070f826e81b874
Author: John Haque <address@hidden>
Date: Wed Jan 23 06:25:50 2013 -0600
Use different routines to format long double integers and floats.
diff --git a/ChangeLog b/ChangeLog
index 361a0e8..d0daef3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-01-23 John Haque <address@hidden>
+
+ * long_double.c (format_uint_1): New inline routines to format integers.
+ * long_double.h (format_float_1): Remove integer formatting code.
+ (format_awkldbl_printf): Use format_uint_1() to format integers.
+
2013-01-19 John Haque <address@hidden>
For C long double and without "%Lf" in printf, provide "%.0Lf" to
diff --git a/float128.c b/float128.c
index 0910a68..15582b8 100644
--- a/float128.c
+++ b/float128.c
@@ -34,28 +34,42 @@
/* end of Macros from quadmath.h */
+
#define LDBL_FRAC_BITS FLT128_MANT_DIG
+#define LDBL_INT_BITS 128
#define AWKLDBL __float128
#define LDBL_VAL(n) (*((AWKLDBL *) (n)->qnumbr))
#define LDC(x) x##Q
-#define LDBL_INT_BITS 128
-
#define get_long_double(d) emalloc(d, void *, sizeof(AWKLDBL), "float128")
#define free_long_double(d) efree(d)
-static int format_float_1(char *str, size_t size, const char *format, ...);
+static int format_float_1(char *str, size_t size, const char *format, int fw,
int prec, AWKLDBL x);
+static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
+
+/*
+ * format_uint_1 --- format a AWKLDBL as an unsigned integer. The double value
+ * must be finite and >= 0.
+ */
+
+static inline int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+ int ret;
+ if ((ret = format_uint_finite_p(str, size, x)) < 0)
+ return snprintf(str, size, "%.0f", (double) x);
+ return ret;
+}
+
static AWKLDBL double_to_int(AWKLDBL);
+/* if have __float128, also have strtold. No ? */
+
static inline AWKLDBL
gawk_strtold(const char *str, char **endptr)
{
-#ifdef HAVE_STRTOLD
return strtold(str, endptr);
-#else
- return strtod(str, endptr);
-#endif
}
/* Define isnan() and isinf() before including the two files */
@@ -73,8 +87,10 @@ static inline int isinf_awkldbl(AWKLDBL x) { return isnan(x
- x); }
#define isinf isinf_awkldbl
#define GAWK_INFINITY HUGE_VALQ
-#define GAWK_NAN (LDC(0.0Q) / LDC(0.0Q))
+#define GAWK_NAN (LDC(0.0) / LDC(0.0))
+
+/* XXX: Don't want floorl() or ceill() */
#ifdef HAVE_FLOORL
#undef HAVE_FLOORL
diff --git a/long_double.c b/long_double.c
index a2fc40e..593cd97 100644
--- a/long_double.c
+++ b/long_double.c
@@ -181,9 +181,40 @@ gawk_sqrtl(AWKLDBL x)
#endif /* PRINTF_HAS_LF_FORMAT */
#if ! defined(PRINTF_HAS_LF_FORMAT)
-static int format_float_1(char *str, size_t size, const char *format, ...);
+static int format_float_1(char *str, size_t size, const char *format, int fw,
int prec, AWKLDBL x);
+static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
+
+/*
+ * format_uint_finite_p --- format a long double as an unsigned integer. The
double value
+ * must be finite and >= 0.
+ */
+
+static inline int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+ int ret;
+ if ((ret = format_uint_finite_p(str, size, x)) < 0)
+ return snprintf(str, size, "%.0f", (double) x);
+ return ret;
+}
#else
-#define format_float_1 snprintf
+
+/*
+ * format_float_1 --- format a single AWKLDBL value according to FORMAT.
+ * The value must be finite.
+ */
+
+static inline int
+format_float_1(char *str, size_t size, const char *format, int fw, int prec,
AWKLDBL x)
+{
+ return snprintf(str, size, format, fw, prec, x);
+}
+
+static inline int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+ return snprintf(str, size, "%.0Lf", x);
+}
#endif
#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
diff --git a/long_double.h b/long_double.h
index f117bb8..023ece1 100644
--- a/long_double.h
+++ b/long_double.h
@@ -1202,8 +1202,8 @@ get_ieee_magic_val(const char *val)
if (val == ptr) { /* Older strtod implementations don't support inf or
nan. */
if (first) {
first = false;
- nan = gawk_sqrtl(-LDC(1.0));
- inf = -gawk_logl(LDC(0.0));
+ nan = gawk_sqrtl(-LDC(1.0)); /* FIXME -- this isn't
right */
+ inf = -gawk_logl(LDC(0.0)); /* Ditto */
}
v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
if (val[0] == '-')
@@ -1429,7 +1429,7 @@ format_awkldbl_printf(NODE *arg, struct format_spec
*spec, struct print_fmt_buf
* Use snprintf return value to tell if there
* is enough room in the buffer or not.
*/
- while ((i = format_float_1(intbuf, intbuf_size, "%.0Lf",
tmpval)) >= intbuf_size) {
+ while ((i = format_uint_1(intbuf, intbuf_size, tmpval)) >=
intbuf_size) {
if (intbuf == stackbuf)
intbuf = NULL;
intbuf_size = i + 1;
@@ -1725,8 +1725,8 @@ double_to_int(AWKLDBL x)
#if ! defined(PRINTF_HAS_LF_FORMAT)
/*
- * format_uint_finite_p --- format a double as an unsigned integer. The double
value
- * must be finite and >= 0.
+ * format_uint_finite_p --- format a AWKLDBL as an unsigned integer. The
AWKLDBL value
+ * must be finite and in the range 0 <= x < 2^LDBL_FRAC_BITS.
*/
static int
@@ -1772,12 +1772,9 @@ format_uint_finite_p(char *str, size_t size, AWKLDBL x)
gawk_uint_t d0, d1, d2, d3, d4, q;
gawk_uint_t chunk[4];
- assert(!!isnan(x) == 0);
- assert(!!isinf(x) == 0);
assert(x >= LDC(0.0));
- if (size <= 35) /* maximum size ever needed excluding
terminating null */
- return 35;
+ assert(size > 35); /* maximum size ever needed excluding
terminating null */
if (gawk_floorl_finite_p(x, chunk) < LDC(0.0)) /* outside range */
return -1;
@@ -1814,46 +1811,24 @@ format_uint_finite_p(char *str, size_t size, AWKLDBL x)
}
/*
- * format_float_1 --- format a single double value according to FORMAT.
- * The value must be finite and >= 0.
+ * format_float_1 --- format a single AWKLDBL value according to FORMAT.
+ * The value must be finite.
*/
static int
-format_float_1(char *str, size_t size, const char *format, ...)
+format_float_1(char *str, size_t size, const char *format, int fw, int prec,
AWKLDBL x)
{
- va_list argp;
char alt_format[16];
size_t len;
- int ret = -1;
- AWKLDBL x;
-
- va_start(argp, format);
len = strlen(format);
/* expect %Lf, %LF, %Le, %LE, %Lg or %LG */
assert(len >= 2 && format[len - 2] == 'L');
-
+
memcpy(alt_format, format, len - 2);
alt_format[len - 2] = format[len - 1]; /* skip the `L' */
alt_format[len - 1] = '\0';
-
- if (strcmp(format, "%.0Lf") == 0) {
- /* format as integer */
- x = va_arg(argp, AWKLDBL);
- va_end(argp);
- if ((ret = format_uint_finite_p(str, size, x)) < 0)
- ret = snprintf(str, size, alt_format, (double) x);
- } else {
- int fw, prec;
-
- fw = va_arg(argp, int);
- prec = va_arg(argp, int);
- x = va_arg(argp, AWKLDBL);
- ret = snprintf(str, size, alt_format, fw, prec, (double) x);
- }
-
- va_end(argp);
- return ret;
+ return snprintf(str, size, alt_format, fw, prec, (double) x);
}
#endif
diff --git a/misc/fp_math.awk b/misc/fp_math.awk
index 51583fa..80fe7d8 100644
--- a/misc/fp_math.awk
+++ b/misc/fp_math.awk
@@ -2,7 +2,9 @@
#
# TODO: * finish fmod().
-# * replace all usages of %, and int() or any other math builtin;
and() is ok!
+# * replace all usages of %, and int() or any other math builtin;
and() is ok!.
+# implement double_to_int() and remove floor/ceil.
+# * fix sqrt(x) for x > DBL_MAX or x < -DBL_MIN.
#
@@ -370,9 +372,17 @@ function __log2( \
return 2 * sum
}
+function pow2(n, k)
+{
+ if (n <= 64)
+ return __POW2__[n]
+ for (k = 1; n > 64; n -= 64)
+ k *= __POW2__[64]
+ return k * __POW2__[n]
+}
function fp_log(x, \
- k, i, y, ypow2, ypow_odd, sum, err, term, sqrt_2, sign)
+ k, i, y, ypow2, ypow_odd, sum, err, term, sign, high, low, mid)
{
#
# ln(x) = 2 * arctanh(y)
@@ -392,17 +402,33 @@ function fp_log(x, \
return __LOG2__
k = 0
if (x > 2) {
- # FIXME -- use power2 table
- while (x > 2) {
- x /= 2
- k++
+ low = 0
+ high = LDBL_MAX_EXP - 1 # XXX: should be 4 *
LDBL_MAX_EXP - 1 if FLT_RADIX = 16
+ while (low <= high) {
+ mid = int ((low + high) / 2)
+ y = x / pow2(mid)
+ if (y > 2)
+ low = mid + 1
+ else
+ high = mid - 1
}
+ x /= pow2(low)
+ k = low
+# printf("x = %0.18e, k = %d\n", x / pow2(low), low)
+
} else if (x < 1) {
- # FIXME -- use power2 table
- while (x < 1) {
- x *= 2
- k--
+ low = 0
+ high = LDBL_MAX_EXP - 1 # could be -LDBL_MIN_EXP, but
no harm in using LDBL_MAX_EXP
+ while (low <= high) {
+ mid = int ((low + high) / 2)
+ y = x * pow2(mid)
+ if (y < 1)
+ low = mid + 1
+ else
+ high = mid - 1
}
+ x *= pow2(low)
+ k = -low
}
# arctanh(x) series has faster convergence when x is close to 1
@@ -724,7 +750,7 @@ function fixprec(str, numdigs, \
if (str ~ /^[-+]?(nan|inf)/)
return str
if (! numdigs)
- numdigs = __DIGITS__
+ numdigs = LDBL_DIG
if (str ~ /^[-+]?0[\.]/)
return str
sign = ""
@@ -760,9 +786,24 @@ function fixprec(str, numdigs, \
BEGIN {
# define some constants
- # reltive error < 5 X 10^-k for rounding to k significant digits
- __DIGITS__ = 34
- __REL_ERROR__ = 5.0e-34
+ LDBL_DIG = 33
+ # relative error < 5 X 10^-k for rounding to k significant digits
+ __REL_ERROR__ = 5.0e-35
+ LDBL_MAX_EXP = 16384
+ LDBL_MANT_DIG = 113
+
+ # We can read hex/octal numbers without using strtod/strtodl
+ if (0x10000000000000000 == 0x10000000000000001) {
+ # x86 long double
+ LDBL_MANT_DIG = 64
+ LDBL_DIG = 18
+ __REL_ERROR__ = 5.0e-20
+ } else if (0x400000000000000000000000000 ==
0x400000000000000000000000001) {
+ # double-double
+ LDBL_MANT_DIG = 106
+ LDBL_DIG = 31
+ LDBL_MAX_EXP = 309
+ }
__PLUS_INF__ = "+inf" + 0
__MINUS_INF__ = "-inf" + 0
@@ -774,15 +815,7 @@ BEGIN {
__LOG2__ = __log2() # cannot use fp_log()
__PI_OVER_4__ = 4 * euler_atan_one_over(5) - euler_atan_one_over(239)
-
-##if LDBL_MANT_DIG == 64
-# 80 bit long double .. 18 or 34 digits?
-# use 2^64 power 2 table
-##elif LDBL_MANT_DIG == 113
-# 128 bit long double .. 34 digits
-# use 2^112 power 2 table
-##endif
-
+ # pre-calculate 2^0 - 2^64
__POW2__[0] = 1
for (i = 1; i <= 64; i++)
__POW2__[i] = __POW2__[i - 1] * 2
diff --git a/misc/gawk_math.h b/misc/gawk_math.h
index e34bfae..909bd69 100644
--- a/misc/gawk_math.h
+++ b/misc/gawk_math.h
@@ -50,7 +50,7 @@ gawk_logl(AWKLDBL x)
static AWKLDBL
gawk_expl(AWKLDBL x)
{
-#ifdef HAVE_LOGL
+#ifdef HAVE_EXPL
return expl( (long double) x);
#else
return exp( (double) x);
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 6 ++++
float128.c | 32 ++++++++++++++++-----
long_double.c | 35 ++++++++++++++++++++++-
long_double.h | 47 +++++++------------------------
misc/fp_math.awk | 79 ++++++++++++++++++++++++++++++++++++++---------------
misc/gawk_math.h | 2 +-
6 files changed, 131 insertions(+), 70 deletions(-)
hooks/post-receive
--
gawk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gawk-diffs] [SCM] gawk branch, long-double, updated. 26bfdfdc9bb065dfc1ea7f2494070f826e81b874,
John Haque <=