[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gawk-diffs] [SCM] gawk branch, long-double, updated. 88304b52a0dc79b4b3
From: |
John Haque |
Subject: |
[gawk-diffs] [SCM] gawk branch, long-double, updated. 88304b52a0dc79b4b33b038acb6f20aaacf01092 |
Date: |
Wed, 16 Jan 2013 11:39:39 +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 88304b52a0dc79b4b33b038acb6f20aaacf01092 (commit)
from 5f4dbd4819a7dae080c6ff4833a06cf1ca8d502c (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=88304b52a0dc79b4b33b038acb6f20aaacf01092
commit 88304b52a0dc79b4b33b038acb6f20aaacf01092
Author: John Haque <address@hidden>
Date: Wed Jan 16 05:38:11 2013 -0600
Add files sprintf*_0Lf.awk, bin2dec.awk.
diff --git a/TODO.LDBL b/TODO.LDBL
index 3e2732f..f81fe53 100644
--- a/TODO.LDBL
+++ b/TODO.LDBL
@@ -9,10 +9,6 @@ Also, append suffix L to all long double constants.
* Convert gawk math routines to C for platforms lacking any. Without ceil()
and floor()
for long doubles, these can't even get 64 bit integers!
-- finish fp_fmod() in misc/fp_math.awk.
- -- write test script(s) to verify (some) output, but DON'T add it to
the dist.
- 80 bit vs 128 bit, and the C math library CANNOT be trusted to produce
- correctly rounded results. Double check any discrepencies using
arbitrary-precision
- math.
* Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM. What
is the point
of floor() and ceil() wrappers? Don't have a clue.
diff --git a/configure b/configure
index 4bf106b..0bb8f5f 100755
--- a/configure
+++ b/configure
@@ -5554,7 +5554,7 @@ $as_echo "yes" >&6; }
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
- CFLAGS="$CFLAGS -DNDEBUG" # turn off assertions
+ CFLAGS="$CFLAGS" # DONOT TURN OF ASSERTIONS
fi
diff --git a/configure.ac b/configure.ac
index d3780bd..e8686e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -95,7 +95,7 @@ then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
- CFLAGS="$CFLAGS -DNDEBUG" # turn off assertions
+ CFLAGS="$CFLAGS" # DONOT TURN OF ASSERTIONS
fi
AC_SUBST(CFLAGS)
diff --git a/misc/bin2dec.awk b/misc/bin2dec.awk
new file mode 100644
index 0000000..04a82e1
--- /dev/null
+++ b/misc/bin2dec.awk
@@ -0,0 +1,83 @@
+# bcd.awk --- Calculate the magic numbers in:
+# Binary to Decimal Conversion in Limited Precision - Douglas B.
Jones
+# URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+#
+# Usage: ./gawk -M -f bin2dec.awk
+#
+
+BEGIN {
+ UINT32_MAX = 4294967296
+ UINT64_MAX = 18446744073709551616
+
+ N = 4 # number of chunks
+
+## 64-bit integers
+# CHUNK_SIZE = CHUNK3_SIZE = 16
+# DEC_BASE = 10000 # 4 decimal digits per chunk, 20 total
+
+## 96-bit integers
+# CHUNK_SIZE = CHUNK3_SIZE = 24
+# DEC_BASE = 10000000 # 7 decimal digits per chunk, 35 total
+
+# 128-bit integers
+ CHUNK_SIZE = 32
+ CHUNK3_SIZE = 17 # the useful size of the first (MSB) chunk <=
CHUNK_SIZE
+ # 17 + 32 + 32 + 32 = 113, precision of 128-bit
double
+ DEC_BASE = 10000000 # 7 decimal digits per chunk, 35 total
+
+######################################################
+
+ CHUNK_MAX = 2^CHUNK_SIZE
+ CHUNK3_MAX = 2^CHUNK3_SIZE
+
+ print "CHUNK_SIZE = ", CHUNK_SIZE
+ print "N = ", N
+ print "DEC_BASE = ", DEC_BASE
+
+ # powers of 2^CHUNK_SIZE
+ POWER_2_C[0] = 1
+ for (i = 1; i < N; i++)
+ POWER_2_C[i] = 2 ^(CHUNK_SIZE * i)
+
+ # powers of DEC_BASE
+ POWER_BASE[0] = 1
+ for (i = 1; i < N; i++)
+ POWER_BASE[i] = DEC_BASE^i
+
+ coeff[N-1][N-1] = int(POWER_2_C[N-1] / POWER_BASE[N-1])
+ for (i = N-2; i >= 0; i--) {
+ for (k = N-1; k >= i; k--) {
+ coeff[i][k] = int(POWER_2_C[k]/POWER_BASE[i])
+ for (m = 1; m <= k - i; m++)
+ coeff[i][k] -= POWER_BASE[m] * coeff[m + i][k]
+ }
+ }
+
+ for (i = N - 1; i >= 0; i--) {
+ for (j = N - 1; j >= i; j--) {
+ printf("%d ", coeff[i][j])
+ }
+ print "";
+ }
+
+ print "----- a0, a1, a2, a4 upper bounds -----"
+ print "UINT32_MAX =", UINT32_MAX
+ print "UINT64_MAX =", UINT64_MAX
+ for (i = N - 1; i >= 0; i--) {
+ a[i] = 0;
+ for (j = N - 1; j >= i; j--) {
+ if (j == 3)
+ a[i] += coeff[i][j] * CHUNK3_MAX
+ else
+ a[i] += coeff[i][j] * CHUNK_MAX
+ }
+ printf("a%d <= %d\n", i, a[i])
+ }
+
+ print "----- c1, c2, c3 upper bounds -----"
+ c[0] = 0
+ for (i = 1; i < N; i++) {
+ c[i] = (a[i - 1] + c[i - 1])/ DEC_BASE
+ printf("c%d <= %d\n", i, c[i])
+ }
+}
diff --git a/misc/sprintf128_0Lf.awk b/misc/sprintf128_0Lf.awk
new file mode 100644
index 0000000..e3e61a9
--- /dev/null
+++ b/misc/sprintf128_0Lf.awk
@@ -0,0 +1,308 @@
+#
+# sprintf128_0Lf.awk -- format integers stored as long doubles and
+# don't have %Lf in (s)printf.
+# This test script handles integers < 2^113 i.e. 128-bit long doubles.
+# Requires -M -vPREC=113 (or -B if have 128-bit long doubles)
+#
+# Usage:
+#
+# $ echo "2^113-1" | ./gawk -M -vPREC=113 -f sprintf128_0Lf.awk
+# 2^113-1 (1.03845937170696552570609926584401910e+34) is an integer
+# sprintf_int128 :10384593717069655257060992658440191
+# arbitrary-prec :10384593717069655257060992658440191
+# floor = 10384593717069655257060992658440191
+# ceil = 10384593717069655257060992658440191
+# $ echo "2^113" | ./gawk -M -vPREC=113 -f sprintf128_0Lf.awk
+# 2^113 (1.03845937170696552570609926584401920e+34) is an integer
+# sprintf_int128 :10384593717069655257060992658440192
+# arbitrary-prec :10384593717069655257060992658440192
+# floor = 10384593717069655257060992658440192
+# ceil = 10384593717069655257060992658440192
+# $ echo "2^113+1" | ./gawk -M -vPREC=113 -f sprintf128_0Lf.awk
+# 2^113+1 (1.03845937170696552570609926584401920e+34) is an integer
+# sprintf_int128 :10384593717069655257060992658440192 ***
+# arbitrary-prec :10384593717069655257060992658440193
+# floor = 10384593717069655257060992658440192 ***
+# ceil = 10384593717069655257060992658440192 ***
+#
+
+BEGIN {
+ # Only need 113 for 128-bit long double.
+
+ LDBL_MANT_DIG = 128
+ POW2[0] = 1
+ for (i = 1; i <= LDBL_MANT_DIG; i++)
+ POW2[i] = POW2[i - 1] * 2
+}
+
+{
+ #
+ # Compare apples to apples, setting PREC=128;
+ #
+
+ eval = sprintf("./gawk -M -vPREC=128 'BEGIN { printf(\"%%0.40e\", %s);
print \"\";\
+ printf(\"%%035d\", %s); print \"\";\
+ printf(\"%%d\", int(%s) == %s + 0); print \"\"}'", $0, $0, $0,
$0)
+ eval | getline num
+ eval | getline ap_intval
+ eval | getline ap_isint
+ close(eval)
+
+ pnum = num + 0
+ sign = ""
+ if (pnum < 0) {
+ pnum = -pnum
+ sign = "-"
+ }
+
+ isint = isinteger(pnum, W)
+ if (isint) {
+ if (! ap_isint)
+ print "!!!!!!!!!MPFR says it is not an integer!!!!!!!!!"
+ printf("%s (%s) is an integer\n", $0, sprintf("%0.35e", num))
+ printf("sprintf_int128 :%c%s\n", sign, sprintf_int128(W))
+ printf("arbitrary-prec :%s\n", ap_intval)
+ } else {
+ if (ap_isint)
+ print "!!!!!!!!!MPFR says it is an integer!!!!!!!!!"
+ printf("%s (%s) is not an integer\n", $0, sprintf("%0.35e",
num))
+ }
+
+#
+# Don't have %Lf !
+# printf("floor = %d\n", floor(num))
+# printf("ceil = %d\n", ceil(num))
+#
+ # use MPFR to format floor(), ceil() returned value
+ eval = sprintf("./gawk -M -vPREC=128 'BEGIN { printf(\"%%d\", %s);
print \"\";\
+ printf(\"%%d\", %s); print \"\"; }'", floor(num), ceil(num))
+ eval | getline floor_val
+ eval | getline ceil_val
+ close(eval)
+
+ print "floor =", floor_val
+ print "ceil =", ceil_val
+}
+
+
+function sprintf_int128(chunk, d0, d1, d2, d3, d4, q, k, dec_base)
+{
+ #
+ # Binary to Decimal Conversion in Limited Precision - Douglas B. Jones
+ # URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+ #
+
+ #
+ # Results from the application of the idea in the article to the
128-bit conversion
+ # problem:
+ #
+ # Divide a 128-bit number into 32-bit chunks, and use 10,000,000 as the
+ # working decimal base. This gives us 7 digits per chunk, and 35 total
decimal digits.
+ # Using the notations used in the article,
+ #
+ # a3 = 79228162 n3
+ # a2 = 5142643 n3 + 184467 n2
+ # a1 = 3400832 n3 + 4407370 n2 + 429 n1
+ # a0 = 3585223950336 n3 + 9551616 n2 + 4967296 n1 + 1 n0
+ #
+ # n3, n2, n1 and n0 are the 32-bit chunks, n3 represents the most
+ # significant 32 bits. Assuming these chunks are at their maximum
possible
+ # value, which is 2^32:
+ #
+ # UINT64_MAX = 18446744073709551616
+ # a3 <= 340282364712189952
+ # a2 <= 22879763232194560
+ # a1 <= 33537814771531776
+ # a0 <= 15398481973785556680704
+ # c1 <= 1539848197378555
+ # c2 <= 3507766296
+ # c3 <= 2287976673
+ #
+ # c1, c2 and c3 are carries from one digit position to the next
+ # (results from integer divisions by the decimal base; see below).
+ #
+ # The maximum value of a0 is > UINT64_MAX. If we restrict n3 to be
+ # in the range 0 < n3 < 2^17, corresponding to the 113-bit
precision available
+ # from a 128-bit long double, we instead get these upper bounds:
+ #
+ # UINT64_MAX = 18446744073709551616
+ # a3 <= 10384593649664
+ # a2 <= 792953788694528
+ # a1 <= 18931798306193408
+ # a0 <= 532280730126909440
+ # c1 <= 53228073012
+ # c2 <= 1893185153
+ # c3 <= 79295568
+ #
+ # We can use 64-bit signed or unsigned long type! QED.
+ #
+ # All these numbers calculated using the script misc/bin2dec.awk.
+ #
+
+
+ dec_base = 10000000
+
+ if (DEBUG) {
+ for (k = 0; k < 4; k++) {
+ if (chunk[k] > 4294967296)
+ printf("chunk[%d] > 4294967296, this ain't
right\n", k)
+ }
+ print "(32 MSB bits first):", chunk[3], "|", chunk[2], "|",
chunk[1], "|", chunk[0]
+ }
+
+ d0 = 3585223950336 * chunk[3] + 9551616 * chunk[2] + 4967296 *
chunk[1] + chunk[0];
+
+ q = int(d0 / dec_base); # int() may call floorl(), but double
version is good enough
+ # in this case. This is only a consideration in
the awk code,
+ # not in the C translation.
+
+ d0 = d0 - q * dec_base; # not using % operator, may not have
fmodl()
+
+ d1 = q + 3400832 * chunk[3] + 4407370 * chunk[2] + 429 * chunk[1];
+ q = int(d1 / dec_base);
+ d1 = d1 - q * dec_base;
+
+ d2 = q + 5142643 * chunk[3] + 184467 * chunk[2];
+ q = int(d2 / dec_base);
+ d2 = d2 - q * dec_base;
+
+ d3 = q + 79228162 * chunk[3];
+ q = int(d3 / dec_base);
+ d3 = d3 - q * dec_base;
+
+ d4 = q;
+ return sprintf("%7.7u%7.7u%7.7u%7.7u%7.7u", \
+ d4, d3, d2, d1, d0); # don't need %Lf support here
+}
+
+function floor(x, d, sign, chunk, isint)
+{
+ x = +x
+
+#
+# if (isnan(x) || isinf(x) || x == 0)
+# return x
+
+ sign = 1
+ if (x < 0) {
+ sign = -1
+ x = -x
+ }
+
+ #
+ # For x >= 2^LDBL_MANT_DIG, use floor for C-double. Bailing out here.
+ #
+
+ if (x >= POW2[LDBL_MANT_DIG]) {
+ printf("number %0.35e is too big (> %0.35e), bailing out\n", x,
POW2[LDBL_MANT_DIG] - 1)
+ exit(1);
+ }
+
+ isint = isinteger(x, chunk)
+
+ # d is long double type
+ d = chunk[3] * POW2[96] + chunk[2] * POW2[64] + chunk[1] * POW2[32] +
chunk[0]
+
+ if (isint) # d == x
+ return sign * d
+ return (sign > 0) ? d : -d - 1
+}
+
+
+function ceil(x, d, sign, chunk, isint)
+{
+ x = +x
+
+#
+# if (isnan(x) || isinf(x) || x == 0)
+# return x
+
+ sign = 1
+ if (x < 0) {
+ sign = -1
+ x = -x
+ }
+
+ #
+ # For x >= 2^LDBL_MANT_DIG, use ceil for C-double. Bailing out here.
+ #
+
+ if (x >= POW2[LDBL_MANT_DIG]) {
+ printf("number %0.35e is too big (> %0.35e), bailing out\n", x,
POW2[LDBL_MANT_DIG] - 1)
+ exit(1);
+ }
+
+ isint = isinteger(x, chunk)
+ # d is long double type
+ d = chunk[3] * POW2[96] + chunk[2] * POW2[64] + chunk[1] * POW2[32] +
chunk[0]
+
+ if (isint) # d == x
+ return sign * d
+ return (sign > 0) ? d + 1 : -d
+}
+
+
+function isinteger(x, D, j, low, high)
+{
+ # x >= 0
+
+ if (x >= POW2[LDBL_MANT_DIG]) {
+ printf("number %0.40e is too big (> %0.40e), bailing out\n", x,
2^LDBL_MANT_DIG - 1)
+ exit(1);
+ }
+
+ D[0] = D[1] = D[2] = D[3] = 0
+
+ # binary search
+ high = LDBL_MANT_DIG - 1
+ while (x >= 2) {
+ low = 0
+ while (low <= high) {
+ mid = int((low + high) / 2)
+ if (x < POW2[mid])
+ high = mid - 1
+ else
+ low = mid + 1
+ }
+
+ if (x < POW2[low]) {
+ x -= POW2[low - 1]
+
+ #
+ # Easier to seperate the 128 bits into 32-bit chunks now
+ # then bit fiddling later.
+ # | D[3] | D[2] | D[1] | D[0] |
+ # |<------- x (128 bits) ----->|
+ #
+
+ if (low <= 32) { D[0] += POW2[low - 1] }
+ else if (low <= 64) { D[1] += POW2[low - 33] }
+ else if (low <= 96) { D[2] += POW2[low - 65] }
+ else { D[3] += POW2[low - 97] }
+ }
+
+ high = low
+ }
+
+#
+# # XXX -- O(n^2) vs. O(n * log(n)) -- how much do we really gain?
+# # Consider extra additions and divisions, but lower # of <
comparisons.
+#
+# while (x >= 2) {
+# for (j = 1; j <= LDBL_MANT_DIG; j++) {
+# if (x < POW2[j]) {
+# x -= POW2[j - 1]
+# break
+# }
+# }
+# }
+#
+
+ if (x >= 1) {
+ D[0]++
+ x -= 1
+ }
+
+ return (x == 0)
+}
+
diff --git a/misc/sprintf64_0Lf.awk b/misc/sprintf64_0Lf.awk
new file mode 100644
index 0000000..2ec38ac
--- /dev/null
+++ b/misc/sprintf64_0Lf.awk
@@ -0,0 +1,247 @@
+#
+# sprintf64_0Lf.awk -- format integers stored as long doubles and
+# don't have %Lf in (s)printf. This test script handles integers < 2^64.
+# Requires both -M (for verification) and -B
+# Usage:
+# echo "2^63 + 2^54 + 2^13" | ./gawk -B -f misc/sprintf_0Lf.awk
+#
+
+BEGIN {
+ # 113 for 128-bit long double, but can only get 64-bit ints.
+ LDBL_MANT_DIG = 64
+ POW2[0] = 1
+ for (i = 1; i <= LDBL_MANT_DIG; i++)
+ POW2[i] = POW2[i - 1] * 2
+}
+
+{
+ #
+ # Compare apples to apples, setting PREC=64; With real 128-bit long
doubles,
+ # one probably should use PREC=quad or 113.
+ # %0.34e ain't the right format but then ..
+ #
+
+ eval = sprintf("./gawk -M -vPREC=64 'BEGIN { printf(\"%%0.34e\", %s);
print \"\";\
+ printf(\"%%020d\", %s); print \"\";\
+ printf(\"%%d\", int(%s) == %s + 0); print \"\"}'", $0, $0, $0,
$0)
+ eval | getline num
+ eval | getline ap_intval
+ eval | getline ap_isint
+ close(eval)
+
+ pnum = num + 0
+ sign = ""
+ if (pnum < 0) {
+ pnum = -pnum
+ sign = "-"
+ }
+
+ isint = isinteger(pnum, chunk16)
+ if (isint) {
+ if (! ap_isint)
+ print "!!!!!!!!!MPFR says it is not an integer!!!!!!!!!"
+ printf("%s (%s) is an integer\n", $0, sprintf("%0.34e", num))
+ printf("sprintf_int64 :%c%s\n", sign, sprintf_int64(chunk16))
+ printf("arbitrary-prec :%s\n", ap_intval)
+ printf("LDBL %%0.Lf :%c%020d\n", sign, pnum) # or
garbage if no %Lf
+ } else {
+ if (ap_isint)
+ print "!!!!!!!!!MPFR says it is an integer!!!!!!!!!"
+ printf("%s (%s) is not an integer\n", $0, sprintf("%0.34e",
num))
+ }
+
+#
+# Don't have %Lf !
+# printf("floor = %d\n", floor(num))
+# printf("ceil = %d\n", ceil(num))
+#
+ # use MPFR to format floor(), ceil() returned values
+ eval = sprintf("./gawk -M -vPREC=64 'BEGIN { printf(\"%%d\", %s); print
\"\";\
+ printf(\"%%d\", %s); print \"\"; }'", floor(num), ceil(num))
+ eval | getline floor_val
+ eval | getline ceil_val
+ close(eval)
+
+ print "floor =", floor_val
+ print "ceil =", ceil_val
+}
+
+
+function sprintf_int64(chunk, d0, d1, d2, d3, d4, q, k, dec_base)
+{
+ #
+ # Binary to Decimal Conversion in Limited Precision - Douglas B. Jones
+ # URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+ #
+
+ dec_base = 10000
+
+ if (DEBUG) {
+ for (k = 0; k < 4; k++) {
+ if (chunk[k] > 65535)
+ printf("chunk[%d] > 65535, this ain't right\n",
k)
+ }
+ print "(16 MSB bits first):", chunk[3], "|", chunk[2], "|",
chunk[1], "|", chunk[0]
+ }
+
+ d0 = 656 * chunk[3] + 7296 * chunk[2] + 5536 * chunk[1] + chunk[0];
+
+ q = int(d0 / dec_base); # int() may call floorl(), but double
version is good enough
+ # in this case. This is only a consideration in
the awk code,
+ # not in the C translation.
+
+ d0 = d0 - q * dec_base; # not using % operator, may not have
fmodl()
+
+ d1 = q + 7671 * chunk[3] + 9496 * chunk[2] + 6 * chunk[1];
+ q = int(d1 / dec_base);
+ d1 = d1 - q * dec_base;
+
+ d2 = q + 4749 * chunk[3] + 42 * chunk[2];
+ q = int(d2 / dec_base);
+ d2 = d2 - q * dec_base;
+
+ d3 = q + 281 * chunk[3];
+ q = int(d3 / dec_base);
+ d3 = d3 - q * dec_base;
+
+ d4 = q;
+ return sprintf("%4.4u%4.4u%4.4u%4.4u%4.4u", \
+ d4, d3, d2, d1, d0); # don't need %Lf support here
+}
+
+
+function floor(x, d, sign, chunk)
+{
+ x = +x
+
+#
+# if (isnan(x) || isinf(x) || x == 0)
+# return x
+
+ sign = 1
+ if (x < 0) {
+ sign = -1
+ x = -x
+ }
+
+ #
+ # For x >= 2^LDBL_MANT_DIG, use floor for C-double. Bailing out here.
+ #
+
+ if (x >= POW2[LDBL_MANT_DIG]) {
+ printf("number %0.34e is too big (> %0.34e), bailing out\n", x,
2^64 - 1)
+ exit(1);
+ }
+
+ isinteger(x, chunk)
+
+ # d is long double type
+ d = chunk[3] * POW2[48] + chunk[2] * POW2[32] + chunk[1] * POW2[16] +
chunk[0]
+
+ if (d == x)
+ return sign * d
+ return (sign > 0) ? d : -d - 1
+}
+
+
+function ceil(x, d, sign, chunk)
+{
+ x = +x
+
+#
+# if (isnan(x) || isinf(x) || x == 0)
+# return x
+
+ sign = 1
+ if (x < 0) {
+ sign = -1
+ x = -x
+ }
+
+ #
+ # For x >= 2^LDBL_MANT_DIG, use ceil for C-double. Bailing out here.
+ #
+
+ if (x >= POW2[LDBL_MANT_DIG]) {
+ printf("number %0.34e is too big (> %0.34e), bailing out\n", x,
2^64 - 1)
+ exit(1);
+ }
+
+ isinteger(x, chunk)
+ # d is long double type
+ d = chunk[3] * POW2[48] + chunk[2] * POW2[32] + chunk[1] * POW2[16] +
chunk[0]
+
+ if (d == x)
+ return sign * d
+ return (sign > 0) ? d + 1 : -d
+}
+
+
+function isinteger(x, D, j, low, high)
+{
+ # Assume x >= 0
+
+ #
+ # FIXME -- x >= 2^LDBL_MANT_DIG; C-double test is adequate, these
integers have same representations.
+ # output maybe incorrect anyway.
+ #
+
+ if (x >= POW2[LDBL_MANT_DIG]) {
+ printf("number %0.34e is too big (> %0.34e), bailing out\n", x,
2^64 - 1)
+ exit(1);
+ }
+
+ D[0] = D[1] = D[2] = D[3] = 0
+
+ # binary search
+ high = LDBL_MANT_DIG - 1
+ while (x >= 2) {
+ low = 0
+ while (low <= high) {
+ mid = int((low + high) / 2)
+ if (x < POW2[mid])
+ high = mid - 1
+ else
+ low = mid + 1
+ }
+
+ if (x < POW2[low]) {
+ x -= POW2[low - 1]
+
+ #
+ # Easier to seperate the 64 bits into 16-bit chunks now
+ # then bit fiddling later.
+ # | D[3] | D[2] | D[1] | D[0] |
+ # |<------- x (64 bits) ----->|
+ #
+
+ if (low <= 16) { D[0] += POW2[low - 1] }
+ else if (low <= 32) { D[1] += POW2[low - 17] }
+ else if (low <= 48) { D[2] += POW2[low - 33] }
+ else { D[3] += POW2[low - 49] }
+ }
+
+ high = low
+ }
+
+#
+# # XXX -- O(n^2) vs. O(n * log(n)) -- how much do we really gain?
+# # Consider extra additions and divisions, but lower # of <
comparisons.
+#
+# while (x >= 2) {
+# for (j = 1; j <= LDBL_MANT_DIG; j++) {
+# if (x < POW2[j]) {
+# x -= POW2[j - 1]
+# break
+# }
+# }
+# }
+#
+
+ if (x >= 1) {
+ D[0]++
+ x -= 1
+ }
+ return (x == 0)
+}
+
diff --git a/misc/sprintf_0Lf.awk b/misc/sprintf_0Lf.awk
deleted file mode 100644
index d504604..0000000
--- a/misc/sprintf_0Lf.awk
+++ /dev/null
@@ -1,172 +0,0 @@
-#
-# sprintf_0Lf.awk -- format integers stored as long doubles and
-# don't have %Lf in (s)printf.
-# This test script handles integers < 2^64 even with 128-bit long doubles.
-# Requires both -M (for verification) and -B
-# Usage: echo "2^63 + 2^54 + 2^13" | ./gawk -B -f misc/sprintf_0Lf.awk
-#
-
-BEGIN {
- # 113 for 128-bit long double, but can only get 64-bit ints.
- LDBL_MANT_DIG = 64
- POW2[0] = 1
- for (i = 1; i <= LDBL_MANT_DIG; i++)
- POW2[i] = POW2[i - 1] * 2
-}
-
-{
- #
- # Compare apples to apples, setting PREC=64; With real 128-bit long
doubles,
- # one probably should use PREC=quad or 113.
- #
-
- eval = sprintf("./gawk -M -vPREC=64 'BEGIN { printf(\"%%0.34e\", %s);
print \"\";\
- printf(\"%%020d\", %s); print \"\";\
- printf(\"%%d\", int(%s) == %s + 0); print \"\"}'", $0, $0, $0,
$0)
- eval | getline num
- eval | getline ap_intval
- eval | getline ap_isint
- close(eval)
-
- pnum = num + 0
- sign = ""
- if (pnum < 0) {
- pnum = -pnum
- sign = "-"
- }
-
- isint = isinteger(pnum, W)
- if (isint) {
- if (! ap_isint)
- print "!!!!!!!!!MPFR says it is not an integer!!!!!!!!!"
- printf("%s (%s) is an integer\n", $0, sprintf("%0.34e", num))
- printf("sprintf_int64 :%c%s\n", sign, sprintf_int64(W))
- printf("arbitrary-prec :%s\n", ap_intval)
- printf("LDBL %%0.Lf :%c%020d\n", sign, pnum) # or
garbage if no %Lf
- } else {
- if (ap_isint)
- print "!!!!!!!!!MPFR says it is an integer!!!!!!!!!"
- printf("%s (%s) is not an integer\n", $0, sprintf("%0.34e",
num))
- }
-}
-
-
-function sprintf_int64(d, d0, d1, d2, d3, d4, q, k)
-{
- #
- # Binary to Decimal Conversion in Limited Precision - Douglas B. Jones
- # URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
- #
-
- if (DEBUG) {
- for (k = 0; k < 4; k++) {
- if (d[k] > 65535)
- printf("d[%d] > 65535, this ain't right\n", k)
- }
- print "(16 MSB bits first):", d[3], "|", d[2], "|", d[1], "|",
d[0]
- }
-
- d0 = 656 * d[3] + 7296 * d[2] + 5536 * d[1] + d[0];
-
- q = int(d0 / 10000); # int() may call floorl(), but double version
is good enough
- # in this case. This is only a consideration in
the awk code,
- # not in the C translation.
-
- d0 = d0 - q * 10000; # not using % operator, may not have fmodl()
-
- d1 = q + 7671 * d[3] + 9496 * d[2] + 6 * d[1];
- q = int(d1 / 10000);
- d1 = d1 - q * 10000;
-
- d2 = q + 4749 * d[3] + 42 * d[2];
- q = int(d2 / 10000);
- d2 = d2 - q * 10000;
-
- d3 = q + 281 * d[3];
- q = int(d3 / 10000);
- d3 = d3 - q * 10000;
-
- d4 = q;
- return sprintf("%4.4u%4.4u%4.4u%4.4u%4.4u", \
- d4, d3, d2, d1, d0); # don't need %Lf support here
-}
-
-
-function isinteger(x, D, j, low, high)
-{
- # Assume x >= 0
-
- #
- # XXX: x >= 2^LDBL_MANT_DIG
- # test using C-double is adequate at least in the range
- # 2^LDBL_MANT_DIG <= x <= DBL_MAX; the integers have same
- # representations. Here in awk code, we simply crap out.
- #
-
- if (x >= POW2[LDBL_MANT_DIG]) {
- printf("number %0.34e is too big (> %0.34e), bailing out\n", x,
2^64 - 1)
- exit(1);
- }
-
- D[0] = D[1] = D[2] = D[3] = 0
-
- # binary search
- high = LDBL_MANT_DIG - 1
- while (x >= 2) {
- low = 0
- while (low <= high) {
- mid = int((low + high) / 2)
- if (x < POW2[mid])
- high = mid - 1
- else
- low = mid + 1
- }
-
- if (x < POW2[low]) {
- x -= POW2[low - 1]
-
- #
- # Easier to seperate the 64 bits into 16-bit chunks now
- # then doing bit fiddling later.
- # | D[3] | D[2] | D[1] | D[0] |
- # |<------- x (64 bits) ----->|
- #
-
- if (low <= 16) { D[0] += POW2[low - 1] }
- else if (low <= 32) { D[1] += POW2[low - 17] }
- else if (low <= 48) { D[2] += POW2[low - 33] }
- else { D[3] += POW2[low - 49] }
- }
-
- high = low
- }
-
-#
-# # XXX -- O(n^2) vs. O(n * log(n)) -- how much do we really gain?
-# # Consider extra additions and divisions, but less # of <
comparisons.
-#
-# while (x >= 2) {
-# for (j = 1; j <= LDBL_MANT_DIG; j++) {
-# if (x < POW2[j]) {
-# x -= POW2[j - 1]
-# break
-# }
-# }
-# }
-#
-
- if (x == 0)
- return 1;
- if (x == 1) {
- if (and(D[0], 1)) {
- ######## XXX: MAYBE ADDING A SECOND TIME ??? #######
- print "Opps! there may be a bug in code! D[0] = ", D[0]
> "/dev/stderr"
- exit(1)
- }
-
- D[0]++
- return 1
- }
-
- return 0
-}
-----------------------------------------------------------------------
Summary of changes:
TODO.LDBL | 4 -
configure | 2 +-
configure.ac | 2 +-
misc/bin2dec.awk | 83 +++++++++++++
misc/sprintf128_0Lf.awk | 308 +++++++++++++++++++++++++++++++++++++++++++++++
misc/sprintf64_0Lf.awk | 247 +++++++++++++++++++++++++++++++++++++
misc/sprintf_0Lf.awk | 172 --------------------------
7 files changed, 640 insertions(+), 178 deletions(-)
create mode 100644 misc/bin2dec.awk
create mode 100644 misc/sprintf128_0Lf.awk
create mode 100644 misc/sprintf64_0Lf.awk
delete mode 100644 misc/sprintf_0Lf.awk
hooks/post-receive
--
gawk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gawk-diffs] [SCM] gawk branch, long-double, updated. 88304b52a0dc79b4b33b038acb6f20aaacf01092,
John Haque <=