[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gawk-diffs] [SCM] gawk branch, gawk_mpfr, updated. 40645cb3cb155eb59dd7
From: |
John Haque |
Subject: |
[gawk-diffs] [SCM] gawk branch, gawk_mpfr, updated. 40645cb3cb155eb59dd745af4ae0e06e729c8eb1 |
Date: |
Mon, 19 Mar 2012 09:47:53 +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, gawk_mpfr has been updated
via 40645cb3cb155eb59dd745af4ae0e06e729c8eb1 (commit)
from b5431a4825e325c61f4043e4d25e47d7891c228c (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=40645cb3cb155eb59dd745af4ae0e06e729c8eb1
commit 40645cb3cb155eb59dd745af4ae0e06e729c8eb1
Author: john haque <address@hidden>
Date: Mon Mar 19 04:30:00 2012 -0500
Add arbitrary-precision arithmetic on integers.
diff --git a/README_d/README.mpfr b/README_d/README.mpfr
new file mode 100644
index 0000000..9d815a4
--- /dev/null
+++ b/README_d/README.mpfr
@@ -0,0 +1,10 @@
+Sat Mar 17 07:32:01 CDT 2012
+=============================
+
+The MPFR and GMP versions known to work for Mac OS X on PPC:
+GNU MPFR 3.1.0, GNU MP 4.3.1
+
+Gawk has been compiled and tested using the following combinations
+of MPFR and GMP versions on GNU/Linux:
+GNU MPFR 2.4.2, GNU MP 4.3.2
+GNU MPFR 3.1.0, GNU MP 5.0.3
diff --git a/array.c b/array.c
index 9d2f56f..384d147 100644
--- a/array.c
+++ b/array.c
@@ -678,9 +678,11 @@ value_info(NODE *n)
fprintf(output_fp, "\"%.*s\"", PREC_STR, n->stptr);
if ((n->flags & (NUMBER|NUMCUR)) != 0) {
#ifdef HAVE_MPFR
- if (n->flags & MPFN)
- fprintf(output_fp, "%s",
- mpg_fmt("<%.*R*g>", PREC_NUM, RND_MODE,
n->mpg_numbr));
+ if (is_mpg_float(n))
+ fprintf(output_fp, ":%s",
+ mpg_fmt("%.*R*g", PREC_NUM, RND_MODE,
n->mpg_numbr));
+ else if (is_mpg_integer(n))
+ fprintf(output_fp, ":%s", mpg_fmt("%Zd",
n->mpg_i));
else
#endif
fprintf(output_fp, ":%.*g", PREC_NUM, n->numbr);
@@ -688,9 +690,11 @@ value_info(NODE *n)
fprintf(output_fp, ">");
} else {
#ifdef HAVE_MPFR
- if (n->flags & MPFN)
- fprintf(output_fp, "%s",
- mpg_fmt("<%.*R*g>", PREC_NUM, RND_MODE,
n->mpg_numbr));
+ if (is_mpg_float(n))
+ fprintf(output_fp, "<%s>",
+ mpg_fmt("%.*R*g", PREC_NUM, RND_MODE,
n->mpg_numbr));
+ else if (is_mpg_integer(n))
+ fprintf(output_fp, "<%s>", mpg_fmt("%Zd", n->mpg_i));
else
#endif
fprintf(output_fp, "<%.*g>", PREC_NUM, n->numbr);
@@ -733,7 +737,7 @@ assoc_info(NODE *subs, NODE *val, NODE *ndump, const char
*aname)
indent_level++;
indent(indent_level);
fprintf(output_fp, "I: [%s:", aname);
- if ((subs->flags & (MPFN|INTIND)) == INTIND)
+ if ((subs->flags & (MPFN|MPZN|INTIND)) == INTIND)
fprintf(output_fp, "<%ld>", (long) subs->numbr);
else
value_info(subs);
@@ -940,13 +944,13 @@ do_asorti(int nargs)
/*
- * cmp_string --- compare two strings; logic similar to cmp_nodes() in eval.c
+ * cmp_strings --- compare two strings; logic similar to cmp_nodes() in eval.c
* except the extra case-sensitive comparison when the case-insensitive
* result is a match.
*/
static int
-cmp_string(const NODE *n1, const NODE *n2)
+cmp_strings(const NODE *n1, const NODE *n2)
{
char *s1, *s2;
size_t len1, len2;
@@ -992,33 +996,6 @@ cmp_string(const NODE *n1, const NODE *n2)
return (len1 < len2) ? -1 : 1;
}
-/* cmp_number --- compare two numbers */
-
-static inline int
-cmp_number(const NODE *n1, const NODE *n2)
-{
-#ifdef HAVE_MPFR
- if (n1->flags & MPFN) {
- assert((n2->flags & MPFN) != 0);
-
- /*
- * N.B.: For non-MPFN, gawk returns 1 if either t1 or t2 is NaN.
- * The results of == and < comparisons below are false with
NaN(s).
- */
-
- if (mpfr_nan_p(n1->mpg_numbr) || mpfr_nan_p(n2->mpg_numbr))
- return 1;
- return mpfr_cmp(n1->mpg_numbr, n2->mpg_numbr);
- }
-#endif
- if (n1->numbr == n2->numbr)
- return 0;
- else if (n1->numbr < n2->numbr)
- return -1;
- else
- return 1;
-}
-
/* sort_up_index_string --- qsort comparison function; ascending index
strings. */
static int
@@ -1029,7 +1006,7 @@ sort_up_index_string(const void *p1, const void *p2)
/* Array indices are strings */
t1 = *((const NODE *const *) p1);
t2 = *((const NODE *const *) p2);
- return cmp_string(t1, t2);
+ return cmp_strings(t1, t2);
}
@@ -1062,14 +1039,14 @@ sort_up_index_number(const void *p1, const void *p2)
t1 = *((const NODE *const *) p1);
t2 = *((const NODE *const *) p2);
- ret = cmp_number(t1, t2);
+ ret = cmp_numbers(t1, t2);
if (ret != 0)
return ret;
/* break a tie with the index string itself */
t1 = force_string((NODE *) t1);
t2 = force_string((NODE *) t2);
- return cmp_string(t1, t2);
+ return cmp_strings(t1, t2);
}
/* sort_down_index_number --- qsort comparison function; descending index
numbers */
@@ -1099,7 +1076,7 @@ sort_up_value_string(const void *p1, const void *p2)
return -1; /* t1 (scalar) < t2 (sub-array) */
/* t1 and t2 both have string values */
- return cmp_string(t1, t2);
+ return cmp_strings(t1, t2);
}
@@ -1130,7 +1107,7 @@ sort_up_value_number(const void *p1, const void *p2)
if (t2->type == Node_var_array)
return -1; /* t1 (scalar) < t2 (sub-array) */
- ret = cmp_number(t1, t2);
+ ret = cmp_numbers(t1, t2);
if (ret != 0)
return ret;
@@ -1140,7 +1117,7 @@ sort_up_value_number(const void *p1, const void *p2)
*/
t1 = force_string(t1);
t2 = force_string(t2);
- return cmp_string(t1, t2);
+ return cmp_strings(t1, t2);
}
@@ -1187,7 +1164,7 @@ sort_up_value_type(const void *p1, const void *p2)
(void) force_string(n2);
if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) {
- return cmp_number(n1, n2);
+ return cmp_numbers(n1, n2);
}
/* 3. All numbers are less than all strings. This is aribitrary. */
@@ -1198,7 +1175,7 @@ sort_up_value_type(const void *p1, const void *p2)
}
/* 4. Two strings */
- return cmp_string(n1, n2);
+ return cmp_strings(n1, n2);
}
/* sort_down_value_type --- qsort comparison function; descending value type */
@@ -1244,9 +1221,14 @@ sort_user_func(const void *p1, const void *p2)
/* return value of the comparison function */
r = POP_NUMBER();
#ifdef HAVE_MPFR
- /* mpfr_sgn: Return a positive value if op > 0, zero if op = 0, and a
negative value if op < 0. */
- if (r->flags & MPFN)
+ /*
+ * mpfr_sgn(mpz_sgn): Returns a positive value if op > 0,
+ * zero if op = 0, and a negative value if op < 0.
+ */
+ if (is_mpg_float(r))
ret = mpfr_sgn(r->mpg_numbr);
+ else if (is_mpg_integer(r))
+ ret = mpz_sgn(r->mpg_i);
else
#endif
ret = (r->numbr < 0.0) ? -1 : (r->numbr > 0.0);
diff --git a/awk.h b/awk.h
index fe9eab4..bf49fb6 100644
--- a/awk.h
+++ b/awk.h
@@ -381,14 +381,17 @@ typedef struct exp_node {
} nodep;
struct {
- union {
- AWKNUM fltnum; /* this is here for optimal
packing of
- * the structure on many
machines
- */
#ifdef HAVE_MPFR
+ union {
+ AWKNUM fltnum;
mpfr_t mpnum;
-#endif
+ mpz_t mpi;
} nm;
+#else
+ AWKNUM fltnum; /* this is here for optimal packing of
+ * the structure on many machines
+ */
+#endif
char *sp;
size_t slen;
long sref;
@@ -419,13 +422,14 @@ typedef struct exp_node {
* lazy conversion to string.
*/
# define WSTRCUR 0x0400 /* wide str value is current */
-# define MPFN 0x0800 /* multiple precision
floating-point number */
+# define MPFN 0x0800 /* arbitrary-precision
floating-point number */
+# define MPZN 0x1000 /* arbitrary-precision integer */
/* type = Node_var_array */
-# define ARRAYMAXED 0x1000 /* array is at max size */
-# define HALFHAT 0x2000 /* half-capacity Hashed
Array Tree;
+# define ARRAYMAXED 0x2000 /* array is at max size */
+# define HALFHAT 0x4000 /* half-capacity Hashed
Array Tree;
* See cint_array.c */
-# define XARRAY 0x4000
+# define XARRAY 0x8000
} NODE;
#define vname sub.nodep.name
@@ -464,9 +468,12 @@ typedef struct exp_node {
#define stfmt sub.val.idx
#define wstptr sub.val.wsp
#define wstlen sub.val.wslen
-#define numbr sub.val.nm.fltnum
#ifdef HAVE_MPFR
#define mpg_numbr sub.val.nm.mpnum
+#define mpg_i sub.val.nm.mpi
+#define numbr sub.val.nm.fltnum
+#else
+#define numbr sub.val.fltnum
#endif
/* Node_arrayfor */
@@ -1021,6 +1028,7 @@ extern int (*interpret)(INSTRUCTION *); /* interpreter
routine */
extern NODE *(*make_number)(double); /* double instead of AWKNUM on purpose
*/
extern NODE *(*str2number)(NODE *);
extern NODE *(*format_val)(const char *, int, NODE *);
+extern int (*cmp_numbers)(const NODE *, const NODE *);
typedef int (*Func_pre_exec)(INSTRUCTION **);
typedef void (*Func_post_exec)(INSTRUCTION *);
@@ -1108,8 +1116,8 @@ extern struct lconv loc;
#ifdef HAVE_MPFR
extern mpfr_prec_t PRECISION;
extern mpfr_rnd_t RND_MODE;
-extern mpfr_t MNR;
-extern mpfr_t MFNR;
+extern mpz_t MNR;
+extern mpz_t MFNR;
extern mpz_t mpzval;
extern int do_ieee_fmt; /* emulate IEEE 754 floating-point format */
#endif
@@ -1205,24 +1213,39 @@ extern STACK_ITEM *stack_top;
#ifdef HAVE_MPFR
/* conversion to C types */
#define get_number_ui(n) (((n)->flags & MPFN) ?
mpfr_get_ui((n)->mpg_numbr, RND_MODE) \
+ : ((n)->flags & MPZN) ? mpz_get_ui((n)->mpg_i) \
: (unsigned long) (n)->numbr)
#define get_number_si(n) (((n)->flags & MPFN) ?
mpfr_get_si((n)->mpg_numbr, RND_MODE) \
+ : ((n)->flags & MPZN) ? mpz_get_si((n)->mpg_i) \
: (long) (n)->numbr)
#define get_number_d(n) (((n)->flags & MPFN) ?
mpfr_get_d((n)->mpg_numbr, RND_MODE) \
+ : ((n)->flags & MPZN) ? mpz_get_d((n)->mpg_i) \
: (double) (n)->numbr)
#define get_number_uj(n) (((n)->flags & MPFN) ?
mpfr_get_uj((n)->mpg_numbr, RND_MODE) \
+ : ((n)->flags & MPZN) ? (uintmax_t)
mpz_get_d((n)->mpg_i) \
: (uintmax_t) (n)->numbr)
-#define is_nonzero_num(n) (((n)->flags & MPFN) ? (!
mpfr_zero_p((n)->mpg_numbr)) \
- : ((n)->numbr != 0.0))
+#define iszero(n) (((n)->flags & MPFN) ?
mpfr_zero_p((n)->mpg_numbr) \
+ : ((n)->flags & MPZN) ? (mpz_sgn((n)->mpg_i) ==
0) \
+ : ((n)->numbr == 0.0))
+
#define IEEE_FMT(r, t) do_ieee_fmt && format_ieee(r, t)
+
+#define mpg_float() mpg_node(MPFN)
+#define mpg_integer() mpg_node(MPZN)
+#define is_mpg_float(n) (((n)->flags & MPFN) != 0)
+#define is_mpg_integer(n) (((n)->flags & MPZN) != 0)
+#define is_mpg_number(n) (((n)->flags & (MPZN|MPFN)) != 0)
#else
#define get_number_ui(n) (unsigned long) (n)->numbr
#define get_number_si(n) (long) (n)->numbr
#define get_number_d(n) (double) (n)->numbr
#define get_number_uj(n) (uintmax_t) (n)->numbr
-#define is_nonzero_num(n) ((n)->numbr != 0.0)
+#define is_mpg_number(n) 0
+#define is_mpg_float(n) 0
+#define is_mpg_integer(n) 0
+#define iszero(n) ((n)->numbr == 0.0)
#endif
#define is_identchar(c) (isalnum(c) || (c) == '_')
@@ -1423,7 +1446,8 @@ extern int strncasecmpmbs(const unsigned char *,
extern void PUSH_CODE(INSTRUCTION *cp);
extern INSTRUCTION *POP_CODE(void);
extern void init_interpret(void);
-extern int cmp_nodes(NODE *p1, NODE *p2);
+extern int cmp_nodes(NODE *t1, NODE *t2);
+extern int cmp_awknums(const NODE *t1, const NODE *t2);
extern void set_IGNORECASE(void);
extern void set_OFS(void);
extern void set_ORS(void);
@@ -1524,8 +1548,9 @@ extern long getenv_long(const char *name);
extern void set_PREC(void);
extern void set_RNDMODE(void);
#ifdef HAVE_MPFR
+extern int mpg_cmp(const NODE *t1, const NODE *t2);
extern int format_ieee(mpfr_ptr, int);
-extern void mpg_update_var(NODE *);
+extern NODE *mpg_update_var(NODE *);
extern long mpg_set_var(NODE *);
extern NODE *do_mpfr_and(int);
extern NODE *do_mpfr_atan2(int);
@@ -1544,8 +1569,9 @@ extern NODE *do_mpfr_srand(int);
extern NODE *do_mpfr_strtonum(int);
extern NODE *do_mpfr_xor(int);
extern void init_mpfr(const char *);
-extern NODE *mpg_node();
-const char *mpg_fmt(const char *mesg, ...);
+extern NODE *mpg_node(unsigned int);
+extern const char *mpg_fmt(const char *mesg, ...);
+extern int mpg_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int
base);
#endif
/* msg.c */
extern void gawk_exit(int status);
@@ -1575,7 +1601,6 @@ extern void pp_string_fp(Func_print print_func, FILE *fp,
const char *str,
extern NODE *r_force_number(NODE *n);
extern NODE *r_format_val(const char *format, int index, NODE *s);
extern NODE *r_dupnode(NODE *n);
-extern NODE *r_make_number(AWKNUM x);
extern NODE *r_make_str_node(const char *s, size_t len, int flags);
extern void *more_blocks(int id);
extern void r_unref(NODE *tmp);
diff --git a/awkgram.c b/awkgram.c
index 30b43ce..df5d6b1 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -708,20 +708,20 @@ static const yytype_uint16 yyrline[] =
318, 327, 337, 339, 341, 347, 352, 353, 357, 376,
375, 409, 411, 416, 417, 430, 435, 436, 440, 442,
444, 451, 541, 583, 625, 738, 745, 752, 762, 771,
- 780, 789, 804, 820, 819, 843, 855, 855, 950, 950,
- 975, 998, 1004, 1005, 1011, 1012, 1019, 1024, 1036, 1050,
- 1052, 1060, 1065, 1067, 1075, 1077, 1086, 1087, 1095, 1100,
- 1100, 1111, 1115, 1123, 1124, 1127, 1129, 1134, 1135, 1144,
- 1145, 1150, 1155, 1161, 1163, 1165, 1172, 1173, 1179, 1180,
- 1185, 1187, 1192, 1194, 1196, 1198, 1204, 1211, 1213, 1215,
- 1231, 1241, 1248, 1250, 1255, 1257, 1259, 1267, 1269, 1274,
- 1276, 1281, 1283, 1285, 1335, 1337, 1339, 1341, 1343, 1345,
- 1347, 1349, 1372, 1377, 1382, 1407, 1413, 1415, 1417, 1419,
- 1421, 1423, 1428, 1432, 1464, 1466, 1472, 1478, 1491, 1492,
- 1493, 1498, 1503, 1507, 1511, 1528, 1541, 1546, 1582, 1600,
- 1601, 1607, 1608, 1613, 1615, 1622, 1639, 1656, 1658, 1665,
- 1670, 1678, 1688, 1700, 1709, 1713, 1717, 1721, 1725, 1729,
- 1732, 1734, 1738, 1742, 1746
+ 780, 789, 804, 820, 819, 843, 855, 855, 953, 953,
+ 978, 1001, 1007, 1008, 1014, 1015, 1022, 1027, 1039, 1053,
+ 1055, 1063, 1068, 1070, 1078, 1080, 1089, 1090, 1098, 1103,
+ 1103, 1114, 1118, 1126, 1127, 1130, 1132, 1137, 1138, 1147,
+ 1148, 1153, 1158, 1164, 1166, 1168, 1175, 1176, 1182, 1183,
+ 1188, 1190, 1195, 1197, 1199, 1201, 1207, 1214, 1216, 1218,
+ 1234, 1244, 1251, 1253, 1258, 1260, 1262, 1270, 1272, 1277,
+ 1279, 1284, 1286, 1288, 1338, 1340, 1342, 1344, 1346, 1348,
+ 1350, 1352, 1375, 1380, 1385, 1410, 1416, 1418, 1420, 1422,
+ 1424, 1426, 1431, 1435, 1467, 1469, 1475, 1481, 1494, 1495,
+ 1496, 1501, 1506, 1510, 1514, 1531, 1544, 1549, 1585, 1603,
+ 1604, 1610, 1611, 1616, 1618, 1625, 1642, 1659, 1661, 1668,
+ 1673, 1681, 1691, 1703, 1712, 1716, 1720, 1724, 1728, 1732,
+ 1735, 1737, 1741, 1745, 1749
};
#endif
@@ -2651,16 +2651,16 @@ yyreduce:
} else {
INSTRUCTION *tbreak, *tcont;
- /* [ Op_push_array a ]
- * [ Op_arrayfor_init | ib ]
- * ic:[ Op_arrayfor_incr | ib ]
- * [ Op_var_assign if any ]
- *
- * body
- *
- * [Op_jmp | ic ]
- * ib:[Op_arrayfor_final ]
- */
+ /* [ Op_push_array a ]
+ * [ Op_arrayfor_init | ib ]
+ * ic:[ Op_arrayfor_incr | ib ]
+ * [ Op_var_assign if any ]
+ *
+ * body
+ *
+ * [Op_jmp | ic ]
+ * ib:[Op_arrayfor_final ]
+ */
regular_loop:
ip = (yyvsp[(5) - (8)]);
ip->nexti->opcode = Op_push_array;
@@ -2892,9 +2892,7 @@ regular_loop:
|| ((yyvsp[(3) - (4)])->lasti->opcode ==
Op_field_spec
&& (yyvsp[(3) -
(4)])->nexti->nexti->nexti == (yyvsp[(3) - (4)])->lasti
&& (yyvsp[(3) -
(4)])->nexti->nexti->opcode == Op_push_i
- && (yyvsp[(3) -
(4)])->nexti->nexti->memory->type == Node_val
- && ((yyvsp[(3) -
(4)])->nexti->nexti->memory->flags & MPFN) == 0
- && (yyvsp[(3) -
(4)])->nexti->nexti->memory->numbr == 0.0)
+ && (yyvsp[(3) -
(4)])->nexti->nexti->memory->type == Node_val)
)
) {
static short warned = FALSE;
@@ -2908,11 +2906,16 @@ regular_loop:
*/
if ((yyvsp[(3) - (4)]) != NULL) {
- bcfree((yyvsp[(3) - (4)])->lasti);
/* Op_field_spec */
- unref((yyvsp[(3) -
(4)])->nexti->nexti->memory); /* Node_val */
+ NODE *n = (yyvsp[(3) -
(4)])->nexti->nexti->memory;
+
+ if (! iszero(n))
+ goto regular_print;
+
+ bcfree((yyvsp[(3) - (4)])->lasti);
/* Op_field_spec */
+ unref(n); /*
Node_val */
bcfree((yyvsp[(3) - (4)])->nexti->nexti);
/* Op_push_i */
- bcfree((yyvsp[(3) - (4)])->nexti);
/* Op_list */
- bcfree((yyvsp[(3) - (4)]));
/* Op_list */
+ bcfree((yyvsp[(3) - (4)])->nexti);
/* Op_list */
+ bcfree((yyvsp[(3) - (4)]));
/* Op_list */
} else {
if (do_lint && (rule == BEGIN || rule == END)
&& ! warned) {
warned = TRUE;
@@ -2944,7 +2947,7 @@ regular_loop:
* [$1 | NULL | redir_type | expr_count]
*
*/
-
+regular_print:
if ((yyvsp[(4) - (4)]) == NULL) { /* no
redirection */
if ((yyvsp[(3) - (4)]) == NULL) { /*
printf without arg */
(yyvsp[(1) - (4)])->expr_count = 0;
@@ -2978,14 +2981,14 @@ regular_loop:
case 58:
/* Line 1821 of yacc.c */
-#line 950 "awkgram.y"
+#line 953 "awkgram.y"
{ sub_counter = 0; }
break;
case 59:
/* Line 1821 of yacc.c */
-#line 951 "awkgram.y"
+#line 954 "awkgram.y"
{
char *arr = (yyvsp[(2) - (4)])->lextok;
@@ -3015,7 +3018,7 @@ regular_loop:
case 60:
/* Line 1821 of yacc.c */
-#line 980 "awkgram.y"
+#line 983 "awkgram.y"
{
static short warned = FALSE;
char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3039,35 +3042,35 @@ regular_loop:
case 61:
/* Line 1821 of yacc.c */
-#line 999 "awkgram.y"
+#line 1002 "awkgram.y"
{ (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
break;
case 62:
/* Line 1821 of yacc.c */
-#line 1004 "awkgram.y"
+#line 1007 "awkgram.y"
{ (yyval) = NULL; }
break;
case 63:
/* Line 1821 of yacc.c */
-#line 1006 "awkgram.y"
+#line 1009 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 64:
/* Line 1821 of yacc.c */
-#line 1011 "awkgram.y"
+#line 1014 "awkgram.y"
{ (yyval) = NULL; }
break;
case 65:
/* Line 1821 of yacc.c */
-#line 1013 "awkgram.y"
+#line 1016 "awkgram.y"
{
if ((yyvsp[(1) - (2)]) == NULL)
(yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3079,14 +3082,14 @@ regular_loop:
case 66:
/* Line 1821 of yacc.c */
-#line 1020 "awkgram.y"
+#line 1023 "awkgram.y"
{ (yyval) = NULL; }
break;
case 67:
/* Line 1821 of yacc.c */
-#line 1025 "awkgram.y"
+#line 1028 "awkgram.y"
{
INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
if ((yyvsp[(5) - (5)]) == NULL)
@@ -3103,7 +3106,7 @@ regular_loop:
case 68:
/* Line 1821 of yacc.c */
-#line 1037 "awkgram.y"
+#line 1040 "awkgram.y"
{
INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
if ((yyvsp[(4) - (4)]) == NULL)
@@ -3119,14 +3122,14 @@ regular_loop:
case 69:
/* Line 1821 of yacc.c */
-#line 1051 "awkgram.y"
+#line 1054 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 70:
/* Line 1821 of yacc.c */
-#line 1053 "awkgram.y"
+#line 1056 "awkgram.y"
{
NODE *n = (yyvsp[(2) - (2)])->memory;
(void) force_number(n);
@@ -3139,7 +3142,7 @@ regular_loop:
case 71:
/* Line 1821 of yacc.c */
-#line 1061 "awkgram.y"
+#line 1064 "awkgram.y"
{
bcfree((yyvsp[(1) - (2)]));
(yyval) = (yyvsp[(2) - (2)]);
@@ -3149,14 +3152,14 @@ regular_loop:
case 72:
/* Line 1821 of yacc.c */
-#line 1066 "awkgram.y"
+#line 1069 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 73:
/* Line 1821 of yacc.c */
-#line 1068 "awkgram.y"
+#line 1071 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_push_re;
(yyval) = (yyvsp[(1) - (1)]);
@@ -3166,21 +3169,21 @@ regular_loop:
case 74:
/* Line 1821 of yacc.c */
-#line 1076 "awkgram.y"
+#line 1079 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 75:
/* Line 1821 of yacc.c */
-#line 1078 "awkgram.y"
+#line 1081 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 77:
/* Line 1821 of yacc.c */
-#line 1088 "awkgram.y"
+#line 1091 "awkgram.y"
{
(yyval) = (yyvsp[(2) - (3)]);
}
@@ -3189,7 +3192,7 @@ regular_loop:
case 78:
/* Line 1821 of yacc.c */
-#line 1095 "awkgram.y"
+#line 1098 "awkgram.y"
{
in_print = FALSE;
in_parens = 0;
@@ -3200,14 +3203,14 @@ regular_loop:
case 79:
/* Line 1821 of yacc.c */
-#line 1100 "awkgram.y"
+#line 1103 "awkgram.y"
{ in_print = FALSE; in_parens = 0; }
break;
case 80:
/* Line 1821 of yacc.c */
-#line 1101 "awkgram.y"
+#line 1104 "awkgram.y"
{
if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
&& (yyvsp[(3) - (3)])->lasti->opcode ==
Op_K_getline_redir
@@ -3220,7 +3223,7 @@ regular_loop:
case 81:
/* Line 1821 of yacc.c */
-#line 1112 "awkgram.y"
+#line 1115 "awkgram.y"
{
(yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]),
(yyvsp[(6) - (6)]), NULL, NULL);
}
@@ -3229,7 +3232,7 @@ regular_loop:
case 82:
/* Line 1821 of yacc.c */
-#line 1117 "awkgram.y"
+#line 1120 "awkgram.y"
{
(yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]),
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
}
@@ -3238,14 +3241,14 @@ regular_loop:
case 87:
/* Line 1821 of yacc.c */
-#line 1134 "awkgram.y"
+#line 1137 "awkgram.y"
{ (yyval) = NULL; }
break;
case 88:
/* Line 1821 of yacc.c */
-#line 1136 "awkgram.y"
+#line 1139 "awkgram.y"
{
bcfree((yyvsp[(1) - (2)]));
(yyval) = (yyvsp[(2) - (2)]);
@@ -3255,21 +3258,21 @@ regular_loop:
case 89:
/* Line 1821 of yacc.c */
-#line 1144 "awkgram.y"
+#line 1147 "awkgram.y"
{ (yyval) = NULL; }
break;
case 90:
/* Line 1821 of yacc.c */
-#line 1146 "awkgram.y"
+#line 1149 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]) ; }
break;
case 91:
/* Line 1821 of yacc.c */
-#line 1151 "awkgram.y"
+#line 1154 "awkgram.y"
{
(yyvsp[(1) - (1)])->param_count = 0;
(yyval) = list_create((yyvsp[(1) - (1)]));
@@ -3279,7 +3282,7 @@ regular_loop:
case 92:
/* Line 1821 of yacc.c */
-#line 1156 "awkgram.y"
+#line 1159 "awkgram.y"
{
(yyvsp[(3) - (3)])->param_count = (yyvsp[(1) -
(3)])->lasti->param_count + 1;
(yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@ -3290,63 +3293,63 @@ regular_loop:
case 93:
/* Line 1821 of yacc.c */
-#line 1162 "awkgram.y"
+#line 1165 "awkgram.y"
{ (yyval) = NULL; }
break;
case 94:
/* Line 1821 of yacc.c */
-#line 1164 "awkgram.y"
+#line 1167 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 95:
/* Line 1821 of yacc.c */
-#line 1166 "awkgram.y"
+#line 1169 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (3)]); }
break;
case 96:
/* Line 1821 of yacc.c */
-#line 1172 "awkgram.y"
+#line 1175 "awkgram.y"
{ (yyval) = NULL; }
break;
case 97:
/* Line 1821 of yacc.c */
-#line 1174 "awkgram.y"
+#line 1177 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 98:
/* Line 1821 of yacc.c */
-#line 1179 "awkgram.y"
+#line 1182 "awkgram.y"
{ (yyval) = NULL; }
break;
case 99:
/* Line 1821 of yacc.c */
-#line 1181 "awkgram.y"
+#line 1184 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 100:
/* Line 1821 of yacc.c */
-#line 1186 "awkgram.y"
+#line 1189 "awkgram.y"
{ (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
break;
case 101:
/* Line 1821 of yacc.c */
-#line 1188 "awkgram.y"
+#line 1191 "awkgram.y"
{
(yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) -
(3)]));
yyerrok;
@@ -3356,35 +3359,35 @@ regular_loop:
case 102:
/* Line 1821 of yacc.c */
-#line 1193 "awkgram.y"
+#line 1196 "awkgram.y"
{ (yyval) = NULL; }
break;
case 103:
/* Line 1821 of yacc.c */
-#line 1195 "awkgram.y"
+#line 1198 "awkgram.y"
{ (yyval) = NULL; }
break;
case 104:
/* Line 1821 of yacc.c */
-#line 1197 "awkgram.y"
+#line 1200 "awkgram.y"
{ (yyval) = NULL; }
break;
case 105:
/* Line 1821 of yacc.c */
-#line 1199 "awkgram.y"
+#line 1202 "awkgram.y"
{ (yyval) = NULL; }
break;
case 106:
/* Line 1821 of yacc.c */
-#line 1205 "awkgram.y"
+#line 1208 "awkgram.y"
{
if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode ==
Op_match_rec)
lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3396,21 +3399,21 @@ regular_loop:
case 107:
/* Line 1821 of yacc.c */
-#line 1212 "awkgram.y"
+#line 1215 "awkgram.y"
{ (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2)
- (3)])); }
break;
case 108:
/* Line 1821 of yacc.c */
-#line 1214 "awkgram.y"
+#line 1217 "awkgram.y"
{ (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2)
- (3)])); }
break;
case 109:
/* Line 1821 of yacc.c */
-#line 1216 "awkgram.y"
+#line 1219 "awkgram.y"
{
if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3431,7 +3434,7 @@ regular_loop:
case 110:
/* Line 1821 of yacc.c */
-#line 1232 "awkgram.y"
+#line 1235 "awkgram.y"
{
if (do_lint_old)
warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3446,7 +3449,7 @@ regular_loop:
case 111:
/* Line 1821 of yacc.c */
-#line 1242 "awkgram.y"
+#line 1245 "awkgram.y"
{
if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode ==
Op_match_rec)
lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3458,35 +3461,35 @@ regular_loop:
case 112:
/* Line 1821 of yacc.c */
-#line 1249 "awkgram.y"
+#line 1252 "awkgram.y"
{ (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]),
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
break;
case 113:
/* Line 1821 of yacc.c */
-#line 1251 "awkgram.y"
+#line 1254 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 114:
/* Line 1821 of yacc.c */
-#line 1256 "awkgram.y"
+#line 1259 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 115:
/* Line 1821 of yacc.c */
-#line 1258 "awkgram.y"
+#line 1261 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 116:
/* Line 1821 of yacc.c */
-#line 1260 "awkgram.y"
+#line 1263 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
(yyval) = (yyvsp[(2) - (2)]);
@@ -3496,49 +3499,49 @@ regular_loop:
case 117:
/* Line 1821 of yacc.c */
-#line 1268 "awkgram.y"
+#line 1271 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 118:
/* Line 1821 of yacc.c */
-#line 1270 "awkgram.y"
+#line 1273 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 119:
/* Line 1821 of yacc.c */
-#line 1275 "awkgram.y"
+#line 1278 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 120:
/* Line 1821 of yacc.c */
-#line 1277 "awkgram.y"
+#line 1280 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 121:
/* Line 1821 of yacc.c */
-#line 1282 "awkgram.y"
+#line 1285 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 122:
/* Line 1821 of yacc.c */
-#line 1284 "awkgram.y"
+#line 1287 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 123:
/* Line 1821 of yacc.c */
-#line 1286 "awkgram.y"
+#line 1289 "awkgram.y"
{
int count = 2;
int is_simple_var = FALSE;
@@ -3590,49 +3593,49 @@ regular_loop:
case 125:
/* Line 1821 of yacc.c */
-#line 1338 "awkgram.y"
+#line 1341 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 126:
/* Line 1821 of yacc.c */
-#line 1340 "awkgram.y"
+#line 1343 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 127:
/* Line 1821 of yacc.c */
-#line 1342 "awkgram.y"
+#line 1345 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 128:
/* Line 1821 of yacc.c */
-#line 1344 "awkgram.y"
+#line 1347 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 129:
/* Line 1821 of yacc.c */
-#line 1346 "awkgram.y"
+#line 1349 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 130:
/* Line 1821 of yacc.c */
-#line 1348 "awkgram.y"
+#line 1351 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 131:
/* Line 1821 of yacc.c */
-#line 1350 "awkgram.y"
+#line 1353 "awkgram.y"
{
/*
* In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3660,7 +3663,7 @@ regular_loop:
case 132:
/* Line 1821 of yacc.c */
-#line 1373 "awkgram.y"
+#line 1376 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_postincrement;
(yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) -
(2)]));
@@ -3670,7 +3673,7 @@ regular_loop:
case 133:
/* Line 1821 of yacc.c */
-#line 1378 "awkgram.y"
+#line 1381 "awkgram.y"
{
(yyvsp[(2) - (2)])->opcode = Op_postdecrement;
(yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) -
(2)]));
@@ -3680,7 +3683,7 @@ regular_loop:
case 134:
/* Line 1821 of yacc.c */
-#line 1383 "awkgram.y"
+#line 1386 "awkgram.y"
{
if (do_lint_old) {
warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3705,7 +3708,7 @@ regular_loop:
case 135:
/* Line 1821 of yacc.c */
-#line 1408 "awkgram.y"
+#line 1411 "awkgram.y"
{
(yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]),
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
bcfree((yyvsp[(2) - (4)]));
@@ -3715,49 +3718,49 @@ regular_loop:
case 136:
/* Line 1821 of yacc.c */
-#line 1414 "awkgram.y"
+#line 1417 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 137:
/* Line 1821 of yacc.c */
-#line 1416 "awkgram.y"
+#line 1419 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 138:
/* Line 1821 of yacc.c */
-#line 1418 "awkgram.y"
+#line 1421 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 139:
/* Line 1821 of yacc.c */
-#line 1420 "awkgram.y"
+#line 1423 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 140:
/* Line 1821 of yacc.c */
-#line 1422 "awkgram.y"
+#line 1425 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 141:
/* Line 1821 of yacc.c */
-#line 1424 "awkgram.y"
+#line 1427 "awkgram.y"
{ (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) -
(3)])); }
break;
case 142:
/* Line 1821 of yacc.c */
-#line 1429 "awkgram.y"
+#line 1432 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3766,7 +3769,7 @@ regular_loop:
case 143:
/* Line 1821 of yacc.c */
-#line 1433 "awkgram.y"
+#line 1436 "awkgram.y"
{
if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
(yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@ -3777,7 +3780,7 @@ regular_loop:
} else {
if (do_optimize > 1 && (yyvsp[(2) - (2)])->nexti ==
(yyvsp[(2) - (2)])->lasti
&& (yyvsp[(2) - (2)])->nexti->opcode ==
Op_push_i
- && ((yyvsp[(2) -
(2)])->nexti->memory->flags & MPFN) == 0
+ && ((yyvsp[(2) -
(2)])->nexti->memory->flags & (MPFN|MPZN)) == 0
) {
NODE *n = (yyvsp[(2) - (2)])->nexti->memory;
if ((n->flags & (STRCUR|STRING)) != 0) {
@@ -3803,14 +3806,14 @@ regular_loop:
case 144:
/* Line 1821 of yacc.c */
-#line 1465 "awkgram.y"
+#line 1468 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (3)]); }
break;
case 145:
/* Line 1821 of yacc.c */
-#line 1467 "awkgram.y"
+#line 1470 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3821,7 +3824,7 @@ regular_loop:
case 146:
/* Line 1821 of yacc.c */
-#line 1473 "awkgram.y"
+#line 1476 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3832,7 +3835,7 @@ regular_loop:
case 147:
/* Line 1821 of yacc.c */
-#line 1479 "awkgram.y"
+#line 1482 "awkgram.y"
{
static short warned1 = FALSE;
@@ -3850,7 +3853,7 @@ regular_loop:
case 150:
/* Line 1821 of yacc.c */
-#line 1494 "awkgram.y"
+#line 1497 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_preincrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) -
(2)]));
@@ -3860,7 +3863,7 @@ regular_loop:
case 151:
/* Line 1821 of yacc.c */
-#line 1499 "awkgram.y"
+#line 1502 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_predecrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) -
(2)]));
@@ -3870,7 +3873,7 @@ regular_loop:
case 152:
/* Line 1821 of yacc.c */
-#line 1504 "awkgram.y"
+#line 1507 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3879,7 +3882,7 @@ regular_loop:
case 153:
/* Line 1821 of yacc.c */
-#line 1508 "awkgram.y"
+#line 1511 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3888,7 +3891,7 @@ regular_loop:
case 154:
/* Line 1821 of yacc.c */
-#line 1512 "awkgram.y"
+#line 1515 "awkgram.y"
{
if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
&& ((yyvsp[(2) - (2)])->lasti->memory->flags &
(STRCUR|STRING)) == 0
@@ -3910,7 +3913,7 @@ regular_loop:
case 155:
/* Line 1821 of yacc.c */
-#line 1529 "awkgram.y"
+#line 1532 "awkgram.y"
{
/*
* was: $$ = $2
@@ -3925,7 +3928,7 @@ regular_loop:
case 156:
/* Line 1821 of yacc.c */
-#line 1542 "awkgram.y"
+#line 1545 "awkgram.y"
{
func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
(yyval) = (yyvsp[(1) - (1)]);
@@ -3935,7 +3938,7 @@ regular_loop:
case 157:
/* Line 1821 of yacc.c */
-#line 1547 "awkgram.y"
+#line 1550 "awkgram.y"
{
/* indirect function call */
INSTRUCTION *f, *t;
@@ -3973,7 +3976,7 @@ regular_loop:
case 158:
/* Line 1821 of yacc.c */
-#line 1583 "awkgram.y"
+#line 1586 "awkgram.y"
{
param_sanity((yyvsp[(3) - (4)]));
(yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3992,42 +3995,42 @@ regular_loop:
case 159:
/* Line 1821 of yacc.c */
-#line 1600 "awkgram.y"
+#line 1603 "awkgram.y"
{ (yyval) = NULL; }
break;
case 160:
/* Line 1821 of yacc.c */
-#line 1602 "awkgram.y"
+#line 1605 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 161:
/* Line 1821 of yacc.c */
-#line 1607 "awkgram.y"
+#line 1610 "awkgram.y"
{ (yyval) = NULL; }
break;
case 162:
/* Line 1821 of yacc.c */
-#line 1609 "awkgram.y"
+#line 1612 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 163:
/* Line 1821 of yacc.c */
-#line 1614 "awkgram.y"
+#line 1617 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 164:
/* Line 1821 of yacc.c */
-#line 1616 "awkgram.y"
+#line 1619 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -4036,7 +4039,7 @@ regular_loop:
case 165:
/* Line 1821 of yacc.c */
-#line 1623 "awkgram.y"
+#line 1626 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated
expressions */
@@ -4055,7 +4058,7 @@ regular_loop:
case 166:
/* Line 1821 of yacc.c */
-#line 1640 "awkgram.y"
+#line 1643 "awkgram.y"
{
INSTRUCTION *t = (yyvsp[(2) - (3)]);
if ((yyvsp[(2) - (3)]) == NULL) {
@@ -4074,14 +4077,14 @@ regular_loop:
case 167:
/* Line 1821 of yacc.c */
-#line 1657 "awkgram.y"
+#line 1660 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 168:
/* Line 1821 of yacc.c */
-#line 1659 "awkgram.y"
+#line 1662 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -4090,14 +4093,14 @@ regular_loop:
case 169:
/* Line 1821 of yacc.c */
-#line 1666 "awkgram.y"
+#line 1669 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 170:
/* Line 1821 of yacc.c */
-#line 1671 "awkgram.y"
+#line 1674 "awkgram.y"
{
char *var_name = (yyvsp[(1) - (1)])->lextok;
@@ -4110,7 +4113,7 @@ regular_loop:
case 171:
/* Line 1821 of yacc.c */
-#line 1679 "awkgram.y"
+#line 1682 "awkgram.y"
{
char *arr = (yyvsp[(1) - (2)])->lextok;
(yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) -
(2)])->source_line, arr, Node_var_new);
@@ -4122,7 +4125,7 @@ regular_loop:
case 172:
/* Line 1821 of yacc.c */
-#line 1689 "awkgram.y"
+#line 1692 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
if (ip->opcode == Op_push
@@ -4139,7 +4142,7 @@ regular_loop:
case 173:
/* Line 1821 of yacc.c */
-#line 1701 "awkgram.y"
+#line 1704 "awkgram.y"
{
(yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
if ((yyvsp[(3) - (3)]) != NULL)
@@ -4150,7 +4153,7 @@ regular_loop:
case 174:
/* Line 1821 of yacc.c */
-#line 1710 "awkgram.y"
+#line 1713 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postincrement;
}
@@ -4159,7 +4162,7 @@ regular_loop:
case 175:
/* Line 1821 of yacc.c */
-#line 1714 "awkgram.y"
+#line 1717 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postdecrement;
}
@@ -4168,49 +4171,49 @@ regular_loop:
case 176:
/* Line 1821 of yacc.c */
-#line 1717 "awkgram.y"
+#line 1720 "awkgram.y"
{ (yyval) = NULL; }
break;
case 178:
/* Line 1821 of yacc.c */
-#line 1725 "awkgram.y"
+#line 1728 "awkgram.y"
{ yyerrok; }
break;
case 179:
/* Line 1821 of yacc.c */
-#line 1729 "awkgram.y"
+#line 1732 "awkgram.y"
{ yyerrok; }
break;
case 182:
/* Line 1821 of yacc.c */
-#line 1738 "awkgram.y"
+#line 1741 "awkgram.y"
{ yyerrok; }
break;
case 183:
/* Line 1821 of yacc.c */
-#line 1742 "awkgram.y"
+#line 1745 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
break;
case 184:
/* Line 1821 of yacc.c */
-#line 1746 "awkgram.y"
+#line 1749 "awkgram.y"
{ yyerrok; }
break;
/* Line 1821 of yacc.c */
-#line 4226 "awkgram.c"
+#line 4229 "awkgram.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -4441,7 +4444,7 @@ yyreturn:
/* Line 2067 of yacc.c */
-#line 1748 "awkgram.y"
+#line 1751 "awkgram.y"
struct token {
@@ -4460,7 +4463,7 @@ struct token {
# define CONTINUE 0x2000 /* continue allowed inside */
NODE *(*ptr)(int); /* function that implements this keyword */
- NODE *(*ptr2)(int); /* alternate MPFR function implementing this
keyword */
+ NODE *(*ptr2)(int); /* alternate arbitrary-precision function */
};
#if 'a' == 0x81 /* it's EBCDIC */
@@ -4603,10 +4606,12 @@ void
negate_num(NODE *n)
{
#ifdef HAVE_MPFR
- if (n->flags & MPFN) {
+ if (is_mpg_float(n)) {
int tval;
- tval = mpfr_setsign(n->mpg_numbr, n->mpg_numbr, TRUE, RND_MODE);
+ tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, RND_MODE);
IEEE_FMT(n->mpg_numbr, tval);
+ } else if (is_mpg_integer(n)) {
+ mpz_neg(n->mpg_i, n->mpg_i);
} else
#endif
n->numbr = -n->numbr;
@@ -6081,12 +6086,18 @@ retry:
#ifdef HAVE_MPFR
if (do_mpfr) {
NODE *r;
- int tval;
- r = mpg_node();
- tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base,
RND_MODE);
- errno = 0;
- IEEE_FMT(r->mpg_numbr, tval);
+ if (! seen_point && ! seen_e) {
+ r = mpg_integer();
+ mpg_strtoui(r->mpg_i, tokstart,
strlen(tokstart), NULL, base);
+ errno = 0;
+ } else {
+ int tval;
+ r = mpg_float();
+ tval = mpfr_strtofr(r->mpg_numbr, tokstart,
NULL, base, RND_MODE);
+ errno = 0;
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
yylval->memory = r;
return lasttok = YNUMBER;
}
@@ -6593,8 +6604,10 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
print_func(fp, "\n");
} else if (n->flags & NUMBER) {
#ifdef HAVE_MPFR
- if (n->flags & MPFN)
+ if (is_mpg_float(n))
print_func(fp, "%s\n", mpg_fmt("%.17R*g", RND_MODE,
n->mpg_numbr));
+ else if (is_mpg_integer(n))
+ print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
else
#endif
print_func(fp, "%.17g\n", n->numbr);
@@ -6603,8 +6616,10 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
print_func(fp, "\n");
} else if (n->flags & NUMCUR) {
#ifdef HAVE_MPFR
- if (n->flags & MPFN)
+ if (is_mpg_float(n))
print_func(fp, "%s\n", mpg_fmt("%.17R*g", RND_MODE,
n->mpg_numbr));
+ else if (is_mpg_integer(n))
+ print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
else
#endif
print_func(fp, "%.17g\n", n->numbr);
@@ -7155,8 +7170,8 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION
*op)
ip1 = s1->nexti;
if (do_optimize > 1
&& ip1 == s1->lasti && ip1->opcode == Op_push_i
- && (ip1->memory->flags & (MPFN|STRCUR|STRING))
== 0
- && (ip2->memory->flags & (MPFN|STRCUR|STRING))
== 0
+ && (ip1->memory->flags &
(MPFN|MPZN|STRCUR|STRING)) == 0
+ && (ip2->memory->flags &
(MPFN|MPZN|STRCUR|STRING)) == 0
) {
NODE *n1 = ip1->memory, *n2 = ip2->memory;
res = force_number(n1)->numbr;
diff --git a/awkgram.y b/awkgram.y
index 5187a69..04d2e08 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -673,16 +673,16 @@ statement
} else {
INSTRUCTION *tbreak, *tcont;
- /* [ Op_push_array a ]
- * [ Op_arrayfor_init | ib ]
- * ic:[ Op_arrayfor_incr | ib ]
- * [ Op_var_assign if any ]
- *
- * body
- *
- * [Op_jmp | ic ]
- * ib:[Op_arrayfor_final ]
- */
+ /* [ Op_push_array a ]
+ * [ Op_arrayfor_init | ib ]
+ * ic:[ Op_arrayfor_incr | ib ]
+ * [ Op_var_assign if any ]
+ *
+ * body
+ *
+ * [Op_jmp | ic ]
+ * ib:[Op_arrayfor_final ]
+ */
regular_loop:
ip = $5;
ip->nexti->opcode = Op_push_array;
@@ -865,9 +865,7 @@ simple_stmt
|| ($3->lasti->opcode == Op_field_spec
&& $3->nexti->nexti->nexti == $3->lasti
&& $3->nexti->nexti->opcode == Op_push_i
- && $3->nexti->nexti->memory->type ==
Node_val
- && ($3->nexti->nexti->memory->flags &
MPFN) == 0
- && $3->nexti->nexti->memory->numbr ==
0.0)
+ && $3->nexti->nexti->memory->type ==
Node_val)
)
) {
static short warned = FALSE;
@@ -881,11 +879,16 @@ simple_stmt
*/
if ($3 != NULL) {
- bcfree($3->lasti);
/* Op_field_spec */
- unref($3->nexti->nexti->memory); /*
Node_val */
+ NODE *n = $3->nexti->nexti->memory;
+
+ if (! iszero(n))
+ goto regular_print;
+
+ bcfree($3->lasti); /*
Op_field_spec */
+ unref(n); /*
Node_val */
bcfree($3->nexti->nexti); /*
Op_push_i */
- bcfree($3->nexti);
/* Op_list */
- bcfree($3);
/* Op_list */
+ bcfree($3->nexti); /*
Op_list */
+ bcfree($3); /*
Op_list */
} else {
if (do_lint && (rule == BEGIN || rule == END)
&& ! warned) {
warned = TRUE;
@@ -917,7 +920,7 @@ simple_stmt
* [$1 | NULL | redir_type | expr_count]
*
*/
-
+regular_print:
if ($4 == NULL) { /* no redirection */
if ($3 == NULL) { /* printf without arg */
$1->expr_count = 0;
@@ -1440,7 +1443,7 @@ non_post_simp_exp
} else {
if (do_optimize > 1 && $2->nexti == $2->lasti
&& $2->nexti->opcode == Op_push_i
- && ($2->nexti->memory->flags & MPFN) == 0
+ && ($2->nexti->memory->flags &
(MPFN|MPZN)) == 0
) {
NODE *n = $2->nexti->memory;
if ((n->flags & (STRCUR|STRING)) != 0) {
@@ -1763,7 +1766,7 @@ struct token {
# define CONTINUE 0x2000 /* continue allowed inside */
NODE *(*ptr)(int); /* function that implements this keyword */
- NODE *(*ptr2)(int); /* alternate MPFR function implementing this
keyword */
+ NODE *(*ptr2)(int); /* alternate arbitrary-precision function */
};
#if 'a' == 0x81 /* it's EBCDIC */
@@ -1906,10 +1909,12 @@ void
negate_num(NODE *n)
{
#ifdef HAVE_MPFR
- if (n->flags & MPFN) {
+ if (is_mpg_float(n)) {
int tval;
- tval = mpfr_setsign(n->mpg_numbr, n->mpg_numbr, TRUE, RND_MODE);
+ tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, RND_MODE);
IEEE_FMT(n->mpg_numbr, tval);
+ } else if (is_mpg_integer(n)) {
+ mpz_neg(n->mpg_i, n->mpg_i);
} else
#endif
n->numbr = -n->numbr;
@@ -3384,12 +3389,18 @@ retry:
#ifdef HAVE_MPFR
if (do_mpfr) {
NODE *r;
- int tval;
- r = mpg_node();
- tval = mpfr_strtofr(r->mpg_numbr, tokstart, NULL, base,
RND_MODE);
- errno = 0;
- IEEE_FMT(r->mpg_numbr, tval);
+ if (! seen_point && ! seen_e) {
+ r = mpg_integer();
+ mpg_strtoui(r->mpg_i, tokstart,
strlen(tokstart), NULL, base);
+ errno = 0;
+ } else {
+ int tval;
+ r = mpg_float();
+ tval = mpfr_strtofr(r->mpg_numbr, tokstart,
NULL, base, RND_MODE);
+ errno = 0;
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
yylval->memory = r;
return lasttok = YNUMBER;
}
@@ -3896,8 +3907,10 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
print_func(fp, "\n");
} else if (n->flags & NUMBER) {
#ifdef HAVE_MPFR
- if (n->flags & MPFN)
+ if (is_mpg_float(n))
print_func(fp, "%s\n", mpg_fmt("%.17R*g", RND_MODE,
n->mpg_numbr));
+ else if (is_mpg_integer(n))
+ print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
else
#endif
print_func(fp, "%.17g\n", n->numbr);
@@ -3906,8 +3919,10 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
print_func(fp, "\n");
} else if (n->flags & NUMCUR) {
#ifdef HAVE_MPFR
- if (n->flags & MPFN)
+ if (is_mpg_float(n))
print_func(fp, "%s\n", mpg_fmt("%.17R*g", RND_MODE,
n->mpg_numbr));
+ else if (is_mpg_integer(n))
+ print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
else
#endif
print_func(fp, "%.17g\n", n->numbr);
@@ -4458,8 +4473,8 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION
*op)
ip1 = s1->nexti;
if (do_optimize > 1
&& ip1 == s1->lasti && ip1->opcode == Op_push_i
- && (ip1->memory->flags & (MPFN|STRCUR|STRING))
== 0
- && (ip2->memory->flags & (MPFN|STRCUR|STRING))
== 0
+ && (ip1->memory->flags &
(MPFN|MPZN|STRCUR|STRING)) == 0
+ && (ip2->memory->flags &
(MPFN|MPZN|STRCUR|STRING)) == 0
) {
NODE *n1 = ip1->memory, *n2 = ip2->memory;
res = force_number(n1)->numbr;
diff --git a/builtin.c b/builtin.c
index f91a2f9..5a63977 100644
--- a/builtin.c
+++ b/builtin.c
@@ -546,6 +546,42 @@ do_log(int nargs)
}
+#ifdef HAVE_MPFR
+
+/*
+ * mpz2mpfr --- convert an arbitrary-precision integer to a float
+ * without any loss of precision. The returned value is only
+ * good for temporary use.
+ */
+
+
+static mpfr_ptr
+mpz2mpfr(mpz_ptr zi)
+{
+ size_t prec;
+ static mpfr_t mpfrval;
+ static int inited = FALSE;
+ int tval;
+
+ /* estimate minimum precision for exact conversion */
+ prec = mpz_sizeinbase(zi, 2); /* most significant 1 bit position
starting at 1 */
+ prec -= (size_t) mpz_scan1(zi, 0); /* least significant 1 bit
index starting at 0 */
+ if (prec < MPFR_PREC_MIN)
+ prec = MPFR_PREC_MIN;
+ else if (prec > MPFR_PREC_MAX)
+ prec = MPFR_PREC_MAX;
+
+ if (! inited) {
+ mpfr_init2(mpfrval, prec);
+ inited = TRUE;
+ } else
+ mpfr_set_prec(mpfrval, prec);
+ tval = mpfr_set_z(mpfrval, zi, RND_MODE);
+ IEEE_FMT(mpfrval, tval);
+ return mpfrval;
+}
+#endif
+
/*
* format_tree() formats arguments of sprintf,
* and accordingly to a fmt_string providing a format like in
@@ -603,7 +639,7 @@ format_tree(
size_t cur_arg = 0;
NODE *r = NULL;
- int i;
+ int i, nc;
int toofew = FALSE;
char *obuf, *obufout;
size_t osiz, ofre;
@@ -644,8 +680,11 @@ format_tree(
char *chp;
size_t copy_count, char_count;
#ifdef HAVE_MPFR
- enum { MPFR_INT_WITH_PREC = 1, MPFR_INT_WITHOUT_PREC, MPFR_FLOAT }
mpfr_fmt_type;
+ mpz_ptr zi;
+ mpfr_ptr mf;
#endif
+ enum { MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type;
+
static const char sp[] = " ";
static const char zero_string[] = "0";
static const char lchbuf[] = "0123456789abcdef";
@@ -732,10 +771,16 @@ format_tree(
fw = 0;
prec = 0;
argnum = 0;
+ base = 0;
have_prec = FALSE;
signchar = FALSE;
zero_flag = FALSE;
quote_flag = FALSE;
+#ifdef HAVE_MPFR
+ mf = NULL;
+ zi = NULL;
+#endif
+ fmt_type = 0;
lj = alt = big_flag = bigbig_flag = small_flag = FALSE;
fill = sp;
@@ -1062,8 +1107,10 @@ out2:
parse_next_arg();
(void) force_number(arg);
#ifdef HAVE_MPFR
- if (arg->flags & MPFN)
- goto mpfr_int;
+ if (is_mpg_float(arg))
+ goto mpf0;
+ else if (is_mpg_integer(arg))
+ goto mpz0;
else
#endif
tmpval = arg->numbr;
@@ -1180,25 +1227,60 @@ out2:
parse_next_arg();
(void) force_number(arg);
#ifdef HAVE_MPFR
- if (arg->flags & MPFN) {
- mpfr_ptr mt;
-mpfr_int:
- mt = arg->mpg_numbr;
- if (! mpfr_number_p(mt)) {
+ if (is_mpg_integer(arg)) {
+mpz0:
+ zi = arg->mpg_i;
+
+ if (cs1 != 'd' && cs1 != 'i') {
+ if (mpz_sgn(zi) <= 0) {
+ /*
+ * Negative value or 0 requires
special handling.
+ * Unlike MPFR, GMP does not
allow conversion
+ * to (u)intmax_t. So we first
convert GMP type to
+ * a MPFR type.
+ */
+ mf = mpz2mpfr(zi);
+ goto mpf1;
+ }
+ signchar = FALSE; /* Don't print
'+' */
+ }
+
+ /* See comments above about when to fill with
zeros */
+ zero_flag = (! lj
+ && ((zero_flag && !
have_prec)
+ || (fw == 0 &&
have_prec)));
+
+ fmt_type = have_prec ? MP_INT_WITH_PREC :
MP_INT_WITHOUT_PREC;
+ goto fmt0;
+
+ } else if (is_mpg_float(arg)) {
+mpf0:
+ mf = arg->mpg_numbr;
+ if (! mpfr_number_p(mf)) {
/* inf or NaN */
cs1 = 'g';
- goto format_float;
+ fmt_type = MP_FLOAT;
+ goto fmt1;
}
if (cs1 != 'd' && cs1 != 'i') {
- if (mpfr_sgn(mt) < 0) {
- if (! mpfr_fits_intmax_p(mt,
RND_MODE)) {
+mpf1:
+ /*
+ * The output of printf("%#.0x", 0) is
0 instead of 0x, hence <= in
+ * the comparison below.
+ */
+ if (mpfr_sgn(mf) <= 0) {
+ if (! mpfr_fits_intmax_p(mf,
RND_MODE)) {
/* -ve number is too
large */
cs1 = 'g';
- goto format_float;
+ fmt_type = MP_FLOAT;
+ goto fmt1;
}
- uval = (uintmax_t)
mpfr_get_sj(mt, RND_MODE);
- goto format_fixed_int;
+
+ tmpval = uval = (uintmax_t)
mpfr_get_sj(mf, RND_MODE);
+ if (! alt && have_prec && prec
== 0 && tmpval == 0)
+ goto pr_tail; /*
printf("%.0x", 0) is no characters */
+ goto int0;
}
signchar = FALSE; /* Don't print
'+' */
}
@@ -1207,10 +1289,11 @@ mpfr_int:
zero_flag = (! lj
&& ((zero_flag && !
have_prec)
|| (fw == 0 &&
have_prec)));
-
- (void) mpfr_get_z(mpzval, mt, MPFR_RNDZ);
/* convert to GMP int */
- mpfr_fmt_type = have_prec ? MPFR_INT_WITH_PREC
: MPFR_INT_WITHOUT_PREC;
- goto format_int;
+
+ (void) mpfr_get_z(mpzval, mf, MPFR_RNDZ);
/* convert to GMP integer */
+ fmt_type = have_prec ? MP_INT_WITH_PREC :
MP_INT_WITHOUT_PREC;
+ zi = mpzval;
+ goto fmt0;
} else
#endif
tmpval = arg->numbr;
@@ -1239,7 +1322,7 @@ mpfr_int:
if ((AWKNUM)uval != double_to_int(tmpval))
goto out_of_range;
}
- format_fixed_int:
+ int0:
/*
* When to fill with zeroes is of course not simple.
* First: No zero fill if left-justifying.
@@ -1322,7 +1405,7 @@ mpfr_int:
lintwarn(_("[s]printf: value %g is out of range
for `%%%c' format"),
(double) tmpval, cs1);
cs1 = 'g';
- goto format_float;
+ goto fmt1;
case 'F':
#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
@@ -1337,16 +1420,24 @@ mpfr_int:
need_format = FALSE;
parse_next_arg();
(void) force_number(arg);
- format_float:
- if ((arg->flags & MPFN) == 0)
+
+ if (! is_mpg_number(arg))
tmpval = arg->numbr;
#ifdef HAVE_MPFR
- else
- mpfr_fmt_type = MPFR_FLOAT;
+ else if (is_mpg_float(arg)) {
+ mf = arg->mpg_numbr;
+ fmt_type = MP_FLOAT;
+ } else {
+ /* arbitrary-precision integer, convert to MPFR
float */
+ assert(mf == NULL);
+ mf = mpz2mpfr(arg->mpg_i);
+ fmt_type = MP_FLOAT;
+ }
#endif
+ fmt1:
if (! have_prec)
prec = DEFAULT_G_PRECISION;
- format_int:
+ fmt0:
chksize(fw + prec + 11); /* 11 == slop */
cp = cpbuf;
*cp++ = '%';
@@ -1361,62 +1452,49 @@ mpfr_int:
if (quote_flag)
*cp++ = '\'';
-#ifdef HAVE_MPFR
- if (arg->flags & MPFN) {
- if (mpfr_fmt_type == MPFR_INT_WITH_PREC) {
- strcpy(cp, "*.*Z");
- cp += 4;
- } else if (mpfr_fmt_type ==
MPFR_INT_WITHOUT_PREC) {
- strcpy(cp, "*Z");
- cp += 2;
- } else {
- strcpy(cp, "*.*R*");
- cp += 5;
- }
- } else
-#endif
- {
- strcpy(cp, "*.*");
- cp += 3;
- }
-
- *cp++ = cs1;
- *cp = '\0';
#if defined(LC_NUMERIC)
if (quote_flag && ! use_lc_numeric)
setlocale(LC_NUMERIC, "");
#endif
- {
- int n;
+
+ switch (fmt_type) {
+ case MP_INT_WITH_PREC:
#ifdef HAVE_MPFR
- if (arg->flags & MPFN) {
- if (mpfr_fmt_type ==
MPFR_INT_WITH_PREC) {
- while ((n =
mpfr_snprintf(obufout, ofre, cpbuf,
- (int) fw, (int)
prec, mpzval)) >= ofre)
- chksize(n)
- } else if (mpfr_fmt_type ==
MPFR_INT_WITHOUT_PREC) {
- while ((n =
mpfr_snprintf(obufout, ofre, cpbuf,
- (int) fw, mpzval))
>= ofre)
- chksize(n)
- } else {
- while ((n =
mpfr_snprintf(obufout, ofre, cpbuf,
- (int) fw, (int)
prec, RND_MODE,
- arg->mpg_numbr))
>= ofre)
- chksize(n)
- }
- } else
+ sprintf(cp, "*.*Z%c", cs1);
+ while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
+ (int) fw, (int) prec, zi)) >= ofre)
+ chksize(nc)
#endif
- {
- while ((n = snprintf(obufout, ofre,
cpbuf,
- (int) fw, (int) prec,
- (double) tmpval)) >= ofre)
- chksize(n)
- }
+ break;
+ case MP_INT_WITHOUT_PREC:
+#ifdef HAVE_MPFR
+ sprintf(cp, "*Z%c", cs1);
+ while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
+ (int) fw, zi)) >= ofre)
+ chksize(nc)
+#endif
+ break;
+ case MP_FLOAT:
+#ifdef HAVE_MPFR
+ sprintf(cp, "*.*R*%c", cs1);
+ while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
+ (int) fw, (int) prec, RND_MODE,
mf)) >= ofre)
+ chksize(nc)
+#endif
+ break;
+ default:
+ sprintf(cp, "*.*%c", cs1);
+ while ((nc = snprintf(obufout, ofre, cpbuf,
+ (int) fw, (int) prec,
+ (double) tmpval)) >= ofre)
+ chksize(nc)
}
+
#if defined(LC_NUMERIC)
if (quote_flag && ! use_lc_numeric)
setlocale(LC_NUMERIC, "C");
#endif
+
len = strlen(obufout);
ofre -= len;
obufout += len;
diff --git a/command.c b/command.c
index 81c601d..1117556 100644
--- a/command.c
+++ b/command.c
@@ -3260,8 +3260,17 @@ err:
errno = 0;
#ifdef HAVE_MPFR
if (do_mpfr) {
- r = mpg_node();
- (void) mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr,
0, RND_MODE);
+ int tval;
+ r = mpg_float();
+ tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr,
0, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ if (mpfr_integer_p(r->mpg_numbr)) {
+ /* integral value, convert to a GMP type. */
+ NODE *tmp = r;
+ r = mpg_integer();
+ mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
+ unref(tmp);
+ }
} else
#endif
r = make_number(strtod(tokstart, & lexptr));
diff --git a/command.y b/command.y
index e36497a..cb5707c 100644
--- a/command.y
+++ b/command.y
@@ -1246,8 +1246,17 @@ err:
errno = 0;
#ifdef HAVE_MPFR
if (do_mpfr) {
- r = mpg_node();
- (void) mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr,
0, RND_MODE);
+ int tval;
+ r = mpg_float();
+ tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr,
0, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ if (mpfr_integer_p(r->mpg_numbr)) {
+ /* integral value, convert to a GMP type. */
+ NODE *tmp = r;
+ r = mpg_integer();
+ mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
+ unref(tmp);
+ }
} else
#endif
r = make_number(strtod(tokstart, & lexptr));
diff --git a/debug.c b/debug.c
index 331c7d3..03fbf47 100644
--- a/debug.c
+++ b/debug.c
@@ -1591,7 +1591,7 @@ condition_triggered(struct condition *cndn)
return FALSE; /* not triggered */
force_number(r);
- di = is_nonzero_num(r);
+ di = ! iszero(r);
DEREF(r);
return di;
}
@@ -3659,6 +3659,8 @@ print_memory(NODE *m, NODE *func, Func_print print_func,
FILE *fp)
#ifdef HAVE_MPFR
if (m->flags & MPFN)
print_func(fp, "%s", mpg_fmt("%R*g",
RND_MODE, m->mpg_numbr));
+ else if (m->flags & MPZN)
+ print_func(fp, "%s", mpg_fmt("%Zd",
m->mpg_i));
else
#endif
print_func(fp, "%g", m->numbr);
@@ -3668,6 +3670,8 @@ print_memory(NODE *m, NODE *func, Func_print print_func,
FILE *fp)
#ifdef HAVE_MPFR
if (m->flags & MPFN)
print_func(fp, "%s", mpg_fmt("%R*g",
RND_MODE, m->mpg_numbr));
+ else if (m->flags & MPZN)
+ print_func(fp, "%s", mpg_fmt("%Zd",
m->mpg_i));
else
#endif
print_func(fp, "%g", m->numbr);
diff --git a/eval.c b/eval.c
index 5757a15..2305bbb 100644
--- a/eval.c
+++ b/eval.c
@@ -440,6 +440,7 @@ flags2str(int flagval)
{ INTIND, "INTIND" },
{ WSTRCUR, "WSTRCUR" },
{ MPFN, "MPFN" },
+ { MPZN, "MPZN" },
{ ARRAYMAXED, "ARRAYMAXED" },
{ HALFHAT, "HALFHAT" },
{ XARRAY, "XARRAY" },
@@ -566,6 +567,7 @@ posix_compare(NODE *s1, NODE *s2)
return ret;
}
+
/* cmp_nodes --- compare two nodes, returning negative, 0, positive */
int
@@ -587,33 +589,11 @@ cmp_nodes(NODE *t1, NODE *t2)
if (t2->flags & INTIND)
t2 = force_string(t2);
- if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) {
-#ifdef HAVE_MPFR
- if (t1->flags & MPFN) {
- assert((t2->flags & MPFN) != 0);
-
- /*
- * N.B.: For non-MPFN, gawk returns 1 if either t1 or
t2 is NaN.
- * The results of == and < comparisons below are false
with NaN(s).
- */
-
- if (mpfr_nan_p(t1->mpg_numbr) ||
mpfr_nan_p(t2->mpg_numbr))
- return 1;
- return mpfr_cmp(t1->mpg_numbr, t2->mpg_numbr);
- }
-#endif
- if (t1->numbr == t2->numbr)
- ret = 0;
- /* don't subtract, in case one or both are infinite */
- else if (t1->numbr < t2->numbr)
- ret = -1;
- else
- ret = 1;
- return ret;
- }
+ if ((t1->flags & NUMBER) && (t2->flags & NUMBER))
+ return cmp_numbers(t1, t2);
- t1 = force_string(t1);
- t2 = force_string(t2);
+ (void) force_string(t1);
+ (void) force_string(t2);
len1 = t1->stlen;
len2 = t2->stlen;
ldiff = len1 - len2;
@@ -732,10 +712,10 @@ set_IGNORECASE()
IGNORECASE = (n->stlen > 0);
} else {
(void) force_number(n);
- IGNORECASE = is_nonzero_num(n);
+ IGNORECASE = ! iszero(n);
}
} else if ((n->flags & (NUMCUR|NUMBER)) != 0)
- IGNORECASE = is_nonzero_num(n);
+ IGNORECASE = ! iszero(n);
else
IGNORECASE = FALSE; /* shouldn't happen */
@@ -965,7 +945,7 @@ set_LINT()
}
} else {
(void) force_number(n);
- if (is_nonzero_num(n))
+ if (! iszero(n))
do_flags |= DO_LINT_ALL;
else
do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
@@ -973,7 +953,7 @@ set_LINT()
}
} else if ((n->flags & (NUMCUR|NUMBER)) != 0) {
(void) force_number(n);
- if (is_nonzero_num(n))
+ if (! iszero(n))
do_flags |= DO_LINT_ALL;
else
do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID);
@@ -1038,8 +1018,8 @@ void
update_NR()
{
#ifdef HAVE_MPFR
- if ((NR_node->var_value->flags & MPFN) != 0)
- mpg_update_var(NR_node);
+ if (is_mpg_number(NR_node->var_value))
+ (void) mpg_update_var(NR_node);
else
#endif
if (NR_node->var_value->numbr != NR) {
@@ -1070,8 +1050,8 @@ void
update_FNR()
{
#ifdef HAVE_MPFR
- if ((FNR_node->var_value->flags & MPFN) != 0)
- mpg_update_var(FNR_node);
+ if (is_mpg_number(FNR_node->var_value))
+ (void) mpg_update_var(FNR_node);
else
#endif
if (FNR_node->var_value->numbr != FNR) {
@@ -1508,15 +1488,15 @@ eval_condition(NODE *t)
force_number(t);
if ((t->flags & NUMBER) != 0)
- return is_nonzero_num(t);
+ return ! iszero(t);
return (t->stlen != 0);
}
-/* cmp_scalar -- compare two nodes on the stack */
+/* cmp_scalars -- compare two nodes on the stack */
static inline int
-cmp_scalar()
+cmp_scalars()
{
NODE *t1, *t2;
int di;
@@ -1764,9 +1744,9 @@ init_interpret()
frame_ptr->vname = NULL;
/* initialize TRUE and FALSE nodes */
- node_Boolean[FALSE] = make_number(0);
+ node_Boolean[FALSE] = make_number(0.0);
node_Boolean[TRUE] = make_number(1.0);
- if ((node_Boolean[FALSE]->flags & MPFN) == 0) {
+ if (! is_mpg_number(node_Boolean[FALSE])) {
node_Boolean[FALSE]->flags |= NUMINT;
node_Boolean[TRUE]->flags |= NUMINT;
}
diff --git a/field.c b/field.c
index d496a57..26ece84 100644
--- a/field.c
+++ b/field.c
@@ -203,11 +203,14 @@ rebuild_record()
*n = *Null_field;
n->stlen = r->stlen;
if ((r->flags & (NUMCUR|NUMBER)) != 0) {
- n->flags |= (r->flags &
(NUMCUR|NUMBER));
+ n->flags |= (r->flags &
(MPFN|MPZN|NUMCUR|NUMBER));
#ifdef HAVE_MPFR
- if (r->flags & MPFN) {
+ if (is_mpg_float(r)) {
mpfr_init(n->mpg_numbr);
mpfr_set(n->mpg_numbr,
r->mpg_numbr, RND_MODE);
+ } else if (is_mpg_integer(r)) {
+ mpz_init(n->mpg_i);
+ mpz_set(n->mpg_i, r->mpg_i);
} else
#endif
n->numbr = r->numbr;
diff --git a/interpret.h b/interpret.h
index 2f38fbe..009e6e1 100644
--- a/interpret.h
+++ b/interpret.h
@@ -346,37 +346,37 @@ top:
break;
case Op_equal:
- r = node_Boolean[cmp_scalar() == 0];
+ r = node_Boolean[cmp_scalars() == 0];
UPREF(r);
REPLACE(r);
break;
case Op_notequal:
- r = node_Boolean[cmp_scalar() != 0];
+ r = node_Boolean[cmp_scalars() != 0];
UPREF(r);
REPLACE(r);
break;
case Op_less:
- r = node_Boolean[cmp_scalar() < 0];
+ r = node_Boolean[cmp_scalars() < 0];
UPREF(r);
REPLACE(r);
break;
case Op_greater:
- r = node_Boolean[cmp_scalar() > 0];
+ r = node_Boolean[cmp_scalars() > 0];
UPREF(r);
REPLACE(r);
break;
case Op_leq:
- r = node_Boolean[cmp_scalar() <= 0];
+ r = node_Boolean[cmp_scalars() <= 0];
UPREF(r);
REPLACE(r);
break;
case Op_geq:
- r = node_Boolean[cmp_scalar() >= 0];
+ r = node_Boolean[cmp_scalars() >= 0];
UPREF(r);
REPLACE(r);
break;
diff --git a/io.c b/io.c
index c7ae06e..78cf70a 100644
--- a/io.c
+++ b/io.c
@@ -135,7 +135,7 @@
#ifdef HAVE_MPFR
/* increment NR or FNR */
#define INCREMENT_R(X) (do_mpfr && X == (LONG_MAX - 1)) ? \
- (mpfr_add_ui(M##X, M##X, 1, RND_MODE), X = 0) :
X++
+ (mpz_add_ui(M##X, M##X, 1), X = 0) : X++
#else
#define INCREMENT_R(X) X++
#endif
@@ -400,8 +400,8 @@ nextfile(IOBUF **curfile, int skipping)
unref(FILENAME_node->var_value);
FILENAME_node->var_value = dupnode(arg);
#ifdef HAVE_MPFR
- if (FNR_node->var_value->flags & MPFN)
- mpfr_set_d(MFNR, 0.0, RND_MODE);
+ if (is_mpg_number(FNR_node->var_value))
+ mpz_set_ui(MFNR, 0);
#endif
FNR = 0;
iop = *curfile = iop_alloc(fd, fname, &mybuf, FALSE);
@@ -448,13 +448,14 @@ nextfile(IOBUF **curfile, int skipping)
void
set_FNR()
{
- (void) force_number(FNR_node->var_value);
+ NODE *n = FNR_node->var_value;
+ (void) force_number(n);
#ifdef HAVE_MPFR
- if ((FNR_node->var_value->flags & MPFN) != 0)
+ if (is_mpg_number(n))
FNR = mpg_set_var(FNR_node);
else
#endif
- FNR = FNR_node->var_value->numbr;
+ FNR = get_number_si(n);
}
/* set_NR --- update internal NR from awk variable */
@@ -462,13 +463,14 @@ set_FNR()
void
set_NR()
{
- (void) force_number(NR_node->var_value);
+ NODE *n = NR_node->var_value;
+ (void) force_number(n);
#ifdef HAVE_MPFR
- if ((NR_node->var_value->flags & MPFN) != 0)
+ if (is_mpg_number(n))
NR = mpg_set_var(NR_node);
else
#endif
- NR = NR_node->var_value->numbr;
+ NR = get_number_si(n);
}
/* inrec --- This reads in a record from the input file */
@@ -3278,7 +3280,7 @@ pty_vs_pipe(const char *command)
if (val->flags & MAYBE_NUM)
(void) force_number(val);
if (val->flags & NUMBER)
- return is_nonzero_num(val);
+ return ! iszero(val);
else
return (val->stlen != 0);
}
diff --git a/main.c b/main.c
index 558c91f..3edb0a9 100644
--- a/main.c
+++ b/main.c
@@ -587,9 +587,8 @@ out:
Nnull_string = make_string("", 0);
#ifdef HAVE_MPFR
if (do_mpfr) {
- mpfr_init(Nnull_string->mpg_numbr);
- mpfr_set_d(Nnull_string->mpg_numbr, 0.0, RND_MODE);
- Nnull_string->flags = (MALLOC|STRCUR|STRING|MPFN|NUMCUR|NUMBER);
+ mpz_init(Nnull_string->mpg_i);
+ Nnull_string->flags = (MALLOC|STRCUR|STRING|MPZN|NUMCUR|NUMBER);
} else
#endif
{
@@ -1079,6 +1078,13 @@ load_procinfo()
update_PROCINFO_str("version", VERSION);
update_PROCINFO_str("strftime", def_strftime_format);
+#ifdef HAVE_MPFR
+ sprintf(name, "GNU MPFR %s", mpfr_get_version());
+ update_PROCINFO_str("mpfr_version", name);
+ sprintf(name, "GNU MP %s", gmp_version);
+ update_PROCINFO_str("gmp_version", name);
+#endif
+
#ifdef GETPGRP_VOID
#define getpgrp_arg() /* nothing */
#else
@@ -1355,7 +1361,11 @@ nostalgia()
static void
version()
{
- printf("%s\n", version_string);
+ printf("%s", version_string);
+#ifdef HAVE_MPFR
+ printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
+#endif
+ printf("\n");
/*
* Per GNU coding standards, print copyright info,
* then exit successfully, do nothing else.
diff --git a/mpfr.c b/mpfr.c
index f1bf02c..aaf65c2 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -1,5 +1,5 @@
/*
- * mpfr.c - routines for MPFR number support in gawk.
+ * mpfr.c - routines for arbitrary-precision number support in gawk.
*/
/*
@@ -27,30 +27,53 @@
#ifdef HAVE_MPFR
-#if !defined(__GNU_MP_VERSION) || __GNU_MP_VERSION < 5
-typedef unsigned long int mp_bitcnt_t;
-#endif
-
#if !defined(MPFR_VERSION_MAJOR) || MPFR_VERSION_MAJOR < 3
typedef mp_exp_t mpfr_exp_t;
#endif
extern NODE **fmt_list; /* declared in eval.c */
-mpz_t mpzval; /* GMP integer type; used as temporary in many places */
-mpfr_t MNR;
-mpfr_t MFNR;
+mpz_t mpzval; /* GMP integer type, used as temporary in few places */
+mpz_t MNR;
+mpz_t MFNR;
int do_ieee_fmt; /* IEEE-754 floating-point emulation */
static mpfr_rnd_t get_rnd_mode(const char rmode);
-static NODE *get_bit_ops(NODE **p1, NODE **p2, const char *op);
static NODE *mpg_force_number(NODE *n);
static NODE *mpg_make_number(double);
static NODE *mpg_format_val(const char *format, int index, NODE *s);
static int mpg_interpret(INSTRUCTION **cp);
+
static mpfr_exp_t min_exp = MPFR_EMIN_DEFAULT;
static mpfr_exp_t max_exp = MPFR_EMAX_DEFAULT;
+/* temporaries used in bit ops */
+static NODE *_tz1;
+static NODE *_tz2;
+static mpz_t _mpz1;
+static mpz_t _mpz2;
+static mpz_ptr mpz1;
+static mpz_ptr mpz2;
+
+static NODE *get_bit_ops(const char *op);
+#define free_bit_ops() (DEREF(_tz1), DEREF(_tz2))
+
+/* temporary MPFR floats used to hold converted GMP integer operands */
+static mpfr_t _mpf_t1;
+static mpfr_t _mpf_t2;
+
+/*
+ * PRECISION_MIN is the precision used to initialize _mpf_t1 and _mpf_t2.
+ * 64 bits should be enough for exact conversion of most integers to floats.
+ */
+
+#define PRECISION_MIN 64
+
+/* mf = { _mpf_t1, _mpf_t2 } */
+static inline mpfr_ptr mpg_tofloat(mpfr_ptr mf, mpz_ptr mz);
+/* T = {t1, t2} */
+#define MP_FLOAT(T) is_mpg_integer(T) ? mpg_tofloat(_mpf_##T, (T)->mpg_i) :
(T)->mpg_numbr
+
/* init_mpfr --- set up MPFR related variables */
@@ -63,29 +86,42 @@ init_mpfr(const char *rmode)
make_number = mpg_make_number;
str2number = mpg_force_number;
format_val = mpg_format_val;
- mpz_init(mpzval);
- mpfr_init(MNR);
- mpfr_set_d(MNR, 0.0, RND_MODE);
- mpfr_init(MFNR);
- mpfr_set_d(MFNR, 0.0, RND_MODE);
+ cmp_numbers = mpg_cmp;
+
+ mpz_init(MNR);
+ mpz_init(MFNR);
do_ieee_fmt = FALSE;
+
+ mpz_init(_mpz1);
+ mpz_init(_mpz2);
+ mpfr_init2(_mpf_t1, PRECISION_MIN);
+ mpfr_init2(_mpf_t2, PRECISION_MIN);
+ mpz_init(mpzval);
+
register_exec_hook(mpg_interpret, 0);
}
-/* mpg_node --- allocate a node to store a MPFR number */
+/* mpg_node --- allocate a node to store MPFR float or GMP integer */
NODE *
-mpg_node()
+mpg_node(unsigned int tp)
{
NODE *r;
getnode(r);
r->type = Node_val;
- /* Initialize, set precision to the default precision, and value to NaN
*/
- mpfr_init(r->mpg_numbr);
-
+ if (tp == MPFN) {
+ /* Initialize, set precision to the default precision, and
value to NaN */
+ mpfr_init(r->mpg_numbr);
+ r->flags = MPFN;
+ } else {
+ /* Initialize and set value to 0 */
+ mpz_init(r->mpg_i);
+ r->flags = MPZN;
+ }
+
r->valref = 1;
- r->flags = MALLOC|MPFN|NUMBER|NUMCUR;
+ r->flags |= MALLOC|NUMBER|NUMCUR;
r->stptr = NULL;
r->stlen = 0;
#if MBS_SUPPORT
@@ -95,78 +131,238 @@ mpg_node()
return r;
}
-/* mpg_make_number --- make a MPFR number node and initialize with a double */
+/*
+ * mpg_make_number --- make a arbitrary-precision number node
+ * and initialize with a C double
+ */
static NODE *
mpg_make_number(double x)
{
NODE *r;
- int tval;
+ double ival;
- r = mpg_node();
- tval = mpfr_set_d(r->mpg_numbr, x, RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ if ((ival = double_to_int(x)) != x) {
+ int tval;
+ r = mpg_float();
+ tval = mpfr_set_d(r->mpg_numbr, x, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ } else {
+ r = mpg_integer();
+ mpz_set_d(r->mpg_i, ival);
+ }
return r;
}
-/* mpg_force_number --- force a value to be a MPFR number */
+/* mpg_strtoui --- assign arbitrary-precision integral value from a string */
-static NODE *
-mpg_force_number(NODE *n)
+int
+mpg_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base)
{
- char *cp, *cpend, *ptr;
- char save;
- int base = 10;
- unsigned int newflags = 0;
- int tval;
+ char *s = str;
+ char *start;
+ int ret = -1;
- if ((n->flags & (MPFN|NUMCUR)) == (MPFN|NUMCUR))
- return n;
+ /*
+ * mpz_set_str does not like leading 0x or 0X for hex (or 0 for octal)
+ * with a non-zero base argument.
+ */
+ if (base == 16 && len >= 2 && *s == '0' && (s[1] == 'x' || s[1] ==
'X')) {
+ s += 2; len -= 2;
+ } else if (base == 8 && len >= 1 && *s == '0') {
+ s++; len--;
+ }
+ start = s;
+
+ while (len > 0) {
+ switch (*s) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ break;
+ case '8':
+ case '9':
+ if (base == 8)
+ goto done;
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ if (base == 16)
+ break;
+ default:
+ goto done;
+ }
+ s++; len--;
+ }
+done:
+ if (s > start) {
+ char save = *s;
+ *s = '\0';
+ ret = mpz_set_str(zi, start, base);
+ *s = save;
+ }
+ if (end != NULL)
+ *end = s;
+ return ret;
+}
- if (n->flags & MAYBE_NUM) {
- n->flags &= ~MAYBE_NUM;
- newflags = NUMBER;
+
+/* mpg_maybe_float --- test if a string may contain arbitrary-precision float
*/
+
+static int
+mpg_maybe_float(const char *str, int use_locale)
+{
+ int dec_point = '.';
+ const char *s = str;
+
+#if defined(HAVE_LOCALE_H)
+ /*
+ * loc.decimal_point may not have been initialized yet,
+ * so double check it before using it.
+ */
+ if (use_locale && loc.decimal_point != NULL && loc.decimal_point[0] !=
'\0')
+ dec_point = loc.decimal_point[0]; /* XXX --- assumes one
char */
+#endif
+
+ if (strlen(s) >= 3
+ && ( ( (s[0] == 'i' || s[0] == 'I')
+ && (s[1] == 'n' || s[1] == 'N')
+ && (s[2] == 'f' || s[2] == 'F'))
+ || ( (s[0] == 'n' || s[0] == 'N')
+ && (s[1] == 'a' || s[1] == 'A')
+ && (s[2] == 'n' || s[2] == 'N'))))
+ return TRUE;
+
+ for (; *s != '\0'; s++) {
+ if (*s == dec_point || *s == 'e' || *s == 'E')
+ return TRUE;
}
- if ((n->flags & MPFN) == 0) {
- n->flags |= MPFN;
- mpfr_init(n->mpg_numbr);
+ return FALSE;
+}
+
+
+/* mpg_zero --- initialize with arbitrary-precision integer(GMP) and set value
to zero */
+
+static inline void
+mpg_zero(NODE *n)
+{
+ if (is_mpg_float(n)) {
+ mpfr_clear(n->mpg_numbr);
+ n->flags &= ~MPFN;
}
- mpfr_set_d(n->mpg_numbr, 0.0, RND_MODE);
+ if (! is_mpg_integer(n)) {
+ mpz_init(n->mpg_i); /* this also sets its value to 0 */
+ n->flags |= MPZN;
+ } else
+ mpz_set_si(n->mpg_i, 0);
+}
- if (n->stlen == 0)
- return n;
+
+/* force_mpnum --- force a value to be a GMP integer or MPFR float */
+
+static int
+force_mpnum(NODE *n, int do_nondec, int use_locale)
+{
+ char *cp, *cpend, *ptr, *cp1;
+ char save;
+ int tval, base = 10;
+
+ if (n->stlen == 0) {
+ mpg_zero(n);
+ return FALSE;
+ }
cp = n->stptr;
cpend = n->stptr + n->stlen;
while (cp < cpend && isspace((unsigned char) *cp))
cp++;
- if (cp == cpend) /* only spaces */
- return n;
-
+ if (cp == cpend) { /* only spaces */
+ mpg_zero(n);
+ return FALSE;
+ }
+
save = *cpend;
*cpend = '\0';
- if (do_non_decimal_data && ! do_traditional)
- base = get_numbase(cp, TRUE);
+ if (*cp == '+' || *cp == '-')
+ cp1 = cp + 1;
+ else
+ cp1 = cp;
+
+ if (do_nondec)
+ base = get_numbase(cp1, use_locale);
+
+ if (! mpg_maybe_float(cp1, use_locale)) {
+ mpg_zero(n);
+ errno = 0;
+ mpg_strtoui(n->mpg_i, cp1, cpend - cp1, & ptr, base);
+ if (*cp == '-')
+ mpz_neg(n->mpg_i, n->mpg_i);
+ goto done;
+ }
+
+ if (is_mpg_integer(n)) {
+ mpz_clear(n->mpg_i);
+ n->flags &= ~MPZN;
+ }
+
+ if (! is_mpg_float(n)) {
+ mpfr_init(n->mpg_numbr);
+ n->flags |= MPFN;
+ }
errno = 0;
tval = mpfr_strtofr(n->mpg_numbr, cp, & ptr, base, RND_MODE);
IEEE_FMT(n->mpg_numbr, tval);
-
+done:
/* trailing space is OK for NUMBER */
while (isspace((unsigned char) *ptr))
ptr++;
*cpend = save;
- if (errno == 0 && ptr == cpend) {
+ if (errno == 0 && ptr == cpend)
+ return TRUE;
+ errno = 0;
+ return FALSE;
+}
+
+/* mpg_force_number --- force a value to be a multiple-precision number */
+
+static NODE *
+mpg_force_number(NODE *n)
+{
+ unsigned int newflags = 0;
+
+ if (is_mpg_number(n) && (n->flags & NUMCUR))
+ return n;
+
+ if (n->flags & MAYBE_NUM) {
+ n->flags &= ~MAYBE_NUM;
+ newflags = NUMBER;
+ }
+
+ if (force_mpnum(n, (do_non_decimal_data && ! do_traditional), TRUE)) {
n->flags |= newflags;
n->flags |= NUMCUR;
}
- errno = 0;
return n;
}
-
/* mpg_format_val --- format a numeric value based on format */
static NODE *
@@ -179,7 +375,7 @@ mpg_format_val(const char *format, int index, NODE *s)
dummy[1] = s;
oflags = s->flags;
- if (mpfr_integer_p(s->mpg_numbr)) {
+ if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) {
/* integral value, use %d */
r = format_tree("%d", 2, dummy, 2);
s->stfmt = -1;
@@ -200,80 +396,107 @@ mpg_format_val(const char *format, int index, NODE *s)
return s;
}
+/* mpg_cmp --- compare two numbers */
+
+int
+mpg_cmp(const NODE *t1, const NODE *t2)
+{
+ /*
+ * For the purposes of sorting, NaN is considered greater than
+ * any other value, and all NaN values are considered equivalent and
equal.
+ */
+
+ if (is_mpg_float(t1)) {
+ if (is_mpg_float(t2)) {
+ if (mpfr_nan_p(t1->mpg_numbr))
+ return ! mpfr_nan_p(t2->mpg_numbr);
+ if (mpfr_nan_p(t2->mpg_numbr))
+ return -1;
+ return mpfr_cmp(t1->mpg_numbr, t2->mpg_numbr);
+ }
+ if (mpfr_nan_p(t1->mpg_numbr))
+ return 1;
+ return mpfr_cmp_z(t1->mpg_numbr, t2->mpg_i);
+ } else if (is_mpg_float(t2)) {
+ int ret;
+ if (mpfr_nan_p(t2->mpg_numbr))
+ return -1;
+ ret = mpfr_cmp_z(t2->mpg_numbr, t1->mpg_i);
+ return ret > 0 ? -1 : (ret < 0);
+ } else if (is_mpg_integer(t1)) {
+ return mpz_cmp(t1->mpg_i, t2->mpg_i);
+ }
+
+ /* t1 and t2 are AWKNUMs */
+ return cmp_awknums(t1, t2);
+}
+
/*
* mpg_update_var --- update NR or FNR.
- * NR_node->var_value(mpfr_t) = MNR(mpfr_t) * LONG_MAX + NR(long)
+ * NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long)
*/
-void
+NODE *
mpg_update_var(NODE *n)
{
NODE *val = n->var_value;
- long nl;
- mpfr_ptr nm;
+ long nr;
+ mpz_ptr nq;
if (n == NR_node) {
- nl = NR;
- nm = MNR;
+ nr = NR;
+ nq = MNR;
} else if (n == FNR_node) {
- nl = FNR;
- nm = MFNR;
+ nr = FNR;
+ nq = MFNR;
} else
cant_happen();
- if (mpfr_zero_p(nm)) {
- double d;
-
- /* Efficiency hack for NR < LONG_MAX */
- d = mpfr_get_d(val->mpg_numbr, RND_MODE);
- if (d != nl) {
+ if (mpz_sgn(nq) == 0) {
+ /* Efficiency hack similar to that for AWKNUM */
+ if (is_mpg_float(val) || mpz_get_si(val->mpg_i) != nr) {
unref(n->var_value);
- n->var_value = make_number(nl);
+ val = n->var_value = mpg_integer();
+ mpz_set_si(val->mpg_i, nr);
}
} else {
unref(n->var_value);
- val = n->var_value = mpg_node();
- mpfr_mul_si(val->mpg_numbr, nm, LONG_MAX, RND_MODE);
- mpfr_add_si(val->mpg_numbr, val->mpg_numbr, nl, RND_MODE);
+ val = n->var_value = mpg_integer();
+ mpz_set_si(val->mpg_i, nr);
+ mpz_addmul_ui(val->mpg_i, nq, LONG_MAX); /* val->mpg_i
+= nq * LONG_MAX */
}
+ return val;
}
-
/* mpg_set_var --- set NR or FNR */
long
mpg_set_var(NODE *n)
{
- long l;
- mpfr_ptr nm;
- mpfr_ptr p = n->var_value->mpg_numbr;
+ long nr;
+ mpz_ptr nq, r;
+ NODE *val = n->var_value;
int neg = FALSE;
if (n == NR_node)
- nm = MNR;
+ nq = MNR;
else if (n == FNR_node)
- nm = MFNR;
+ nq = MFNR;
else
cant_happen();
- mpfr_get_z(mpzval, p, MPFR_RNDZ);
- if (mpfr_signbit(p)) {
- /* It is a negative number ! */
- neg = TRUE;
- mpz_neg(mpzval, mpzval);
- }
- l = mpz_fdiv_q_ui(mpzval, mpzval, LONG_MAX);
- if (neg) {
- mpz_neg(mpzval, mpzval);
- l = -l;
+ if (is_mpg_integer(val))
+ r = val->mpg_i;
+ else {
+ /* convert float to integer */
+ mpfr_get_z(mpzval, val->mpg_numbr, MPFR_RNDZ);
+ r = mpzval;
}
-
- mpfr_set_z(nm, mpzval, RND_MODE); /* quotient (MNR) */
- return l; /* remainder (NR) */
+ nr = mpz_fdiv_q_ui(nq, r, LONG_MAX); /* nq (MNR or MFNR) is quotient
*/
+ return nr; /* remainder (NR or FNR) */
}
-
/* set_PREC --- update MPFR PRECISION related variables when PREC assigned to
*/
void
@@ -358,20 +581,20 @@ get_rnd_mode(const char rmode)
switch (rmode) {
case 'N':
case 'n':
- return MPFR_RNDN; /* round to nearest */
+ return MPFR_RNDN; /* round to nearest (IEEE-754
roundTiesToEven) */
case 'Z':
case 'z':
- return MPFR_RNDZ; /* round toward zero */
+ return MPFR_RNDZ; /* round toward zero (IEEE-754
roundTowardZero) */
case 'U':
case 'u':
- return MPFR_RNDU; /* round toward plus infinity */
+ return MPFR_RNDU; /* round toward plus infinity (IEEE-754
roundTowardPositive) */
case 'D':
case 'd':
- return MPFR_RNDD; /* round toward minus infinity */
+ return MPFR_RNDD; /* round toward minus infinity
(IEEE-754 roundTowardNegative) */
#if defined(MPFR_VERSION_MAJOR) && MPFR_VERSION_MAJOR > 2
case 'A':
case 'a':
- return MPFR_RNDA; /* round away from zero */
+ return MPFR_RNDA; /* round away from zero (IEEE-754
roundTiesToAway) */
#endif
default:
break;
@@ -407,12 +630,12 @@ format_ieee(mpfr_ptr x, int tval)
/*
* The MPFR doc says that it's our responsibility to make sure all
numbers
* including those previously created are in range after we've changed
the
- * exponent range. Most MPFR operations and functions requires
+ * exponent range. Most MPFR operations and functions require
* the input arguments to have exponents within the current exponent
range.
* Any argument outside the range results in a MPFR assertion failure
* like this:
*
- * $] gawk -M 'BEGIN { x=1.0e-10000; print x+0; PREC="double"; print
x+0}'
+ * $ gawk -M 'BEGIN { x=1.0e-10000; print x+0; PREC="double"; print
x+0}'
* 1e-10000
* init2.c:52: MPFR assertion failed ....
*
@@ -423,7 +646,7 @@ format_ieee(mpfr_ptr x, int tval)
*
* When gawk starts, the exponent range is the MPFR default
* [MPFR_EMIN_DEFAULT, MPFR_EMAX_DEFAULT]. Any number that gawk
- * creates must have exponent in this range (excluding infinities, NANs
and zeros).
+ * creates must have exponent in this range (excluding infinities, NaNs
and zeros).
* Each MPFR operation or function is performed with this default
exponent
* range.
*
@@ -444,86 +667,13 @@ format_ieee(mpfr_ptr x, int tval)
}
-/* get_bit_ops --- get the numeric operands of a binary function */
-
-static NODE *
-get_bit_ops(NODE **p1, NODE **p2, const char *op)
-{
- NODE *t1, *t2;
- mpfr_ptr left, right;
-
- *p2 = t2 = POP_SCALAR();
- *p1 = t1 = POP_SCALAR();
-
- if (do_lint) {
- if ((t1->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("%s: received non-numeric first argument"),
op);
- if ((t2->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("%s: received non-numeric second argument"),
op);
- }
-
- left = force_number(t1)->mpg_numbr;
- right = force_number(t2)->mpg_numbr;
-
- if (! mpfr_number_p(left)) {
- /* [+-]inf or NaN */
- DEREF(t2);
- return t1;
- }
-
- if (! mpfr_number_p(right)) {
- /* [+-]inf or NaN */
- DEREF(t1);
- return t2;
- }
-
- if (do_lint) {
- if (mpfr_signbit(left) || mpfr_signbit(right))
- lintwarn("%s",
- mpg_fmt(_("%s(%Rg, %Rg): negative values will give strange
results"),
- op, left, right)
- );
- if (! mpfr_integer_p(left) || ! mpfr_integer_p(right))
- lintwarn("%s",
- mpg_fmt(_("%s(%Rg, %Rg): fractional values will be truncated"),
- op, left, right)
- );
- }
- return NULL;
-}
-
-
-/* do_mpfr_and --- perform an & operation */
-
-NODE *
-do_mpfr_and(int nargs)
-{
- NODE *t1, *t2, *res;
- mpz_t z;
-
- if ((res = get_bit_ops(& t1, & t2, "and")) != NULL)
- return res;
-
- mpz_init(z);
- mpfr_get_z(mpzval, t1->mpg_numbr, MPFR_RNDZ); /* float to integer
conversion */
- mpfr_get_z(z, t2->mpg_numbr, MPFR_RNDZ); /* Same */
- mpz_and(z, mpzval, z);
-
- res = mpg_node();
- mpfr_set_z(res->mpg_numbr, z, RND_MODE); /* integer to float
conversion */
- mpz_clear(z);
-
- DEREF(t1);
- DEREF(t2);
- return res;
-}
-
/* do_mpfr_atan2 --- do the atan2 function */
NODE *
do_mpfr_atan2(int nargs)
{
NODE *t1, *t2, *res;
+ mpfr_ptr p1, p2;
int tval;
t2 = POP_SCALAR();
@@ -538,9 +688,11 @@ do_mpfr_atan2(int nargs)
force_number(t1);
force_number(t2);
- res = mpg_node();
+ p1 = MP_FLOAT(t1);
+ p2 = MP_FLOAT(t2);
+ res = mpg_float();
/* See MPFR documentation for handling of special values like +inf as
an argument */
- tval = mpfr_atan2(res->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr,
RND_MODE);
+ tval = mpfr_atan2(res->mpg_numbr, p1, p2, RND_MODE);
IEEE_FMT(res->mpg_numbr, tval);
DEREF(t1);
@@ -549,53 +701,19 @@ do_mpfr_atan2(int nargs)
}
-/* do_mpfr_compl --- perform a ~ operation */
-
-NODE *
-do_mpfr_compl(int nargs)
-{
- NODE *tmp, *r;
- mpfr_ptr p;
-
- tmp = POP_SCALAR();
- if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
- lintwarn(_("compl: received non-numeric argument"));
-
- p = force_number(tmp)->mpg_numbr;
- if (! mpfr_number_p(p)) {
- /* [+-]inf or NaN */
- return tmp;
- }
-
- if (do_lint) {
- if (mpfr_signbit(p))
- lintwarn("%s",
- mpg_fmt(_("compl(%Rg): negative value will give strange
results"), p)
- );
- if (! mpfr_integer_p(p))
- lintwarn("%s",
- mpg_fmt(_("comp(%Rg): fractional value will be truncated"), p)
- );
- }
- mpfr_get_z(mpzval, p, MPFR_RNDZ);
- mpz_com(mpzval, mpzval);
- r = mpg_node();
- mpfr_set_z(r->mpg_numbr, mpzval, RND_MODE);
- DEREF(tmp);
- return r;
-}
-
-#define SPEC_MATH(X) \
-NODE *tmp, *res; \
-int tval; \
-tmp = POP_SCALAR(); \
-if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) \
- lintwarn(_("%s: received non-numeric argument"), #X); \
-force_number(tmp); \
-res = mpg_node(); \
-tval = mpfr_##X(res->mpg_numbr, tmp->mpg_numbr, RND_MODE); \
-IEEE_FMT(res->mpg_numbr, tval); \
-DEREF(tmp); \
+#define SPEC_MATH(X) \
+NODE *t1, *res; \
+mpfr_ptr p1; \
+int tval; \
+t1 = POP_SCALAR(); \
+if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0) \
+ lintwarn(_("%s: received non-numeric argument"), #X); \
+force_number(t1); \
+p1 = MP_FLOAT(t1); \
+res = mpg_float(); \
+tval = mpfr_##X(res->mpg_numbr, p1, RND_MODE); \
+IEEE_FMT(res->mpg_numbr, tval); \
+DEREF(t1); \
return res
@@ -650,89 +768,251 @@ do_mpfr_int(int nargs)
if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
lintwarn(_("int: received non-numeric argument"));
force_number(tmp);
- if (! mpfr_number_p(tmp->mpg_numbr)) {
- /* [+-]inf or NaN */
- return tmp;
+
+ if (is_mpg_integer(tmp)) {
+ r = mpg_integer();
+ mpz_set(r->mpg_i, tmp->mpg_i);
+ } else {
+ if (! mpfr_number_p(tmp->mpg_numbr)) {
+ /* [+-]inf or NaN */
+ return tmp;
+ }
+
+ r = mpg_integer();
+ mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
}
- mpfr_get_z(mpzval, tmp->mpg_numbr, MPFR_RNDZ);
- r = mpg_node();
- mpfr_set_z(r->mpg_numbr, mpzval, RND_MODE);
+
DEREF(tmp);
return r;
}
-
-/* do_mpfr_lshift --- perform a << operation */
+/* do_mpfr_compl --- perform a ~ operation */
NODE *
-do_mpfr_lshift(int nargs)
+do_mpfr_compl(int nargs)
{
- NODE *t1, *t2, *res;
- mp_bitcnt_t shift;
+ NODE *tmp, *r;
+ mpz_ptr zptr;
- if ((res = get_bit_ops(& t1, & t2, "lshift")) != NULL)
- return res;
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("compl: received non-numeric argument"));
- mpfr_get_z(mpzval, t1->mpg_numbr, MPFR_RNDZ); /* mpfr_t (float) =>
mpz_t (integer) conversion */
- shift = mpfr_get_ui(t2->mpg_numbr, MPFR_RNDZ); /* mpfr_t (float) =>
unsigned long conversion */
- mpz_mul_2exp(mpzval, mpzval, shift); /* mpzval = mpzval *
2^shift */
+ force_number(tmp);
+ if (is_mpg_float(tmp)) {
+ mpfr_ptr p = tmp->mpg_numbr;
- res = mpg_node();
- mpfr_set_z(res->mpg_numbr, mpzval, RND_MODE); /* integer to float
conversion */
- DEREF(t1);
- DEREF(t2);
- return res;
+ if (! mpfr_number_p(p)) {
+ /* [+-]inf or NaN */
+ return tmp;
+ }
+ if (do_lint) {
+ if (mpfr_sgn(p) < 0)
+ lintwarn("%s",
+ mpg_fmt(_("compl(%Rg): negative value will give strange
results"), p)
+ );
+ if (! mpfr_integer_p(p))
+ lintwarn("%s",
+ mpg_fmt(_("comp(%Rg): fractional value will be
truncated"), p)
+ );
+ }
+
+ mpfr_get_z(mpzval, p, MPFR_RNDZ); /* float to integer
conversion */
+ zptr = mpzval;
+ } else {
+ /* (tmp->flags & MPZN) != 0 */
+ zptr = tmp->mpg_i;
+ if (do_lint) {
+ if (mpz_sgn(zptr) < 0)
+ lintwarn("%s",
+ mpg_fmt(_("cmpl(%Zd): negative values will give strange
results"), zptr)
+ );
+ }
+ }
+
+ r = mpg_integer();
+ mpz_com(r->mpg_i, zptr);
+ DEREF(tmp);
+ return r;
}
-/* do_mpfr_or --- perform an | operation */
+/*
+ * get_bit_ops --- get the numeric operands of a binary function.
+ * Returns a copy of the operand if either is inf or nan. Otherwise
+ * each operand is converted to an integer if necessary, and
+ * the results are placed in the variables mpz1 and mpz2.
+ */
-NODE *
-do_mpfr_or(int nargs)
+static NODE *
+get_bit_ops(const char *op)
{
- NODE *t1, *t2, *res;
- mpz_t z;
+ _tz2 = POP_SCALAR();
+ _tz1 = POP_SCALAR();
- if ((res = get_bit_ops(& t1, & t2, "or")) != NULL)
- return res;
+ if (do_lint) {
+ if ((_tz1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("%s: received non-numeric first argument"),
op);
+ if ((_tz2->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("%s: received non-numeric second argument"),
op);
+ }
- mpz_init(z);
- mpfr_get_z(mpzval, t1->mpg_numbr, MPFR_RNDZ);
- mpfr_get_z(z, t2->mpg_numbr, MPFR_RNDZ);
- mpz_ior(z, mpzval, z);
+ force_number(_tz1);
+ force_number(_tz2);
+
+ if (is_mpg_float(_tz1)) {
+ mpfr_ptr left = _tz1->mpg_numbr;
+ if (! mpfr_number_p(left)) {
+ /* inf or NaN */
+ NODE *res;
+ res = mpg_float();
+ mpfr_set(res->mpg_numbr, _tz1->mpg_numbr, RND_MODE);
+ return res;
+ }
- res = mpg_node();
- mpfr_set_z(res->mpg_numbr, z, RND_MODE);
- mpz_clear(z);
+ if (do_lint) {
+ if (mpfr_sgn(left) < 0)
+ lintwarn("%s",
+ mpg_fmt(_("%s(%Rg, ..): negative values will give
strange results"),
+ op, left)
+ );
+ if (! mpfr_integer_p(left))
+ lintwarn("%s",
+ mpg_fmt(_("%s(%Rg, ..): fractional values will be
truncated"),
+ op, left)
+ );
+ }
+
+ mpfr_get_z(_mpz1, left, MPFR_RNDZ); /* float to integer
conversion */
+ mpz1 = _mpz1;
+ } else {
+ /* (_tz1->flags & MPZN) != 0 */
+ mpz1 = _tz1->mpg_i;
+ if (do_lint) {
+ if (mpz_sgn(mpz1) < 0)
+ lintwarn("%s",
+ mpg_fmt(_("%s(%Zd, ..): negative values will give
strange results"),
+ op, mpz1)
+ );
+ }
+ }
- DEREF(t1);
- DEREF(t2);
- return res;
+ if (is_mpg_float(_tz2)) {
+ mpfr_ptr right = _tz2->mpg_numbr;
+ if (! mpfr_number_p(right)) {
+ /* inf or NaN */
+ NODE *res;
+ res = mpg_float();
+ mpfr_set(res->mpg_numbr, _tz2->mpg_numbr, RND_MODE);
+ return res;
+ }
+
+ if (do_lint) {
+ if (mpfr_sgn(right) < 0)
+ lintwarn("%s",
+ mpg_fmt(_("%s(.., %Rg): negative values will give
strange results"),
+ op, right)
+ );
+ if (! mpfr_integer_p(right))
+ lintwarn("%s",
+ mpg_fmt(_("%s(.., %Rg): fractional values will be
truncated"),
+ op, right)
+ );
+ }
+
+ mpfr_get_z(_mpz2, right, MPFR_RNDZ); /* float to integer
conversion */
+ mpz2 = _mpz2;
+ } else {
+ /* (_tz2->flags & MPZN) != 0 */
+ mpz2 = _tz2->mpg_i;
+ if (do_lint) {
+ if (mpz_sgn(mpz2) < 0)
+ lintwarn("%s",
+ mpg_fmt(_("%s(.., %Zd): negative values will give
strange results"),
+ op, mpz2)
+ );
+ }
+ }
+
+ return NULL;
}
+/* do_mpfr_lshift --- perform a << operation */
+
+NODE *
+do_mpfr_lshift(int nargs)
+{
+ NODE *res;
+ unsigned long shift;
+
+ if ((res = get_bit_ops("lshift")) == NULL) {
+
+ /*
+ * mpz_get_ui: If op is too big to fit an unsigned long then
just
+ * the least significant bits that do fit are returned.
+ * The sign of op is ignored, only the absolute value is used.
+ */
+
+ shift = mpz_get_ui(mpz2); /* GMP integer => unsigned long
conversion */
+ res = mpg_integer();
+ mpz_mul_2exp(res->mpg_i, mpz1, shift); /* res = mpz1 *
2^shift */
+ }
+ free_bit_ops();
+ return res;
+}
/* do_mpfr_rshift --- perform a >> operation */
NODE *
do_mpfr_rhift(int nargs)
{
- NODE *t1, *t2, *res;
- mp_bitcnt_t shift;
+ NODE *res;
+ unsigned long shift;
+
+ if ((res = get_bit_ops("rshift")) == NULL) {
+ /*
+ * mpz_get_ui: If op is too big to fit an unsigned long then
just
+ * the least significant bits that do fit are returned.
+ * The sign of op is ignored, only the absolute value is used.
+ */
+
+ shift = mpz_get_ui(mpz2); /* GMP integer => unsigned long
conversion */
+ res = mpg_integer();
+ mpz_fdiv_q_2exp(res->mpg_i, mpz1, shift); /* res = mpz1 /
2^shift, round towards âinf */
+ }
+ free_bit_ops();
+ return res;
+}
- if ((res = get_bit_ops(& t1, & t2, "rshift")) != NULL)
- return res;
+/* do_mpfr_and --- perform an & operation */
- mpfr_get_z(mpzval, t1->mpg_numbr, MPFR_RNDZ); /* mpfr_t (float) =>
mpz_t (integer) conversion */
- shift = mpfr_get_ui(t2->mpg_numbr, MPFR_RNDZ); /* mpfr_t (float) =>
unsigned long conversion */
- mpz_fdiv_q_2exp(mpzval, mpzval, shift); /* mpzval = mpzval /
2^shift, round towards âinf */
+NODE *
+do_mpfr_and(int nargs)
+{
+ NODE *res;
- res = mpg_node();
- mpfr_set_z(res->mpg_numbr, mpzval, RND_MODE); /* integer to float
conversion */
- DEREF(t1);
- DEREF(t2);
+ if ((res = get_bit_ops("and")) == NULL) {
+ res = mpg_integer();
+ mpz_and(res->mpg_i, mpz1, mpz2);
+ }
+ free_bit_ops();
return res;
}
+/* do_mpfr_or --- perform an | operation */
+
+NODE *
+do_mpfr_or(int nargs)
+{
+ NODE *res;
+
+ if ((res = get_bit_ops("or")) == NULL) {
+ res = mpg_integer();
+ mpz_ior(res->mpg_i, mpz1, mpz2);
+ }
+ free_bit_ops();
+ return res;
+}
/* do_mpfr_strtonum --- the strtonum function */
@@ -740,48 +1020,44 @@ NODE *
do_mpfr_strtonum(int nargs)
{
NODE *tmp, *r;
- int base, tval;
tmp = POP_SCALAR();
- r = mpg_node();
- if ((tmp->flags & (NUMBER|NUMCUR)) != 0)
- tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, RND_MODE);
- else if ((base = get_numbase(tmp->stptr, use_lc_numeric)) != 10) {
- tval = mpfr_strtofr(r->mpg_numbr, tmp->stptr, NULL, base,
RND_MODE);
- errno = 0;
+ if ((tmp->flags & (NUMBER|NUMCUR)) == 0) {
+ r = mpg_integer(); /* will be changed to MPFR float if
necessary in force_mpnum() */
+ r->stptr = tmp->stptr;
+ r->stlen = tmp->stlen;
+ force_mpnum(r, TRUE, use_lc_numeric);
+ r->stptr = NULL;
+ r->stlen = 0;
} else {
(void) force_number(tmp);
- tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, RND_MODE);
+ if (is_mpg_float(tmp)) {
+ int tval;
+ r = mpg_float();
+ tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ } else {
+ r = mpg_integer();
+ mpz_set(r->mpg_i, tmp->mpg_i);
+ }
}
- IEEE_FMT(r->mpg_numbr, tval);
DEREF(tmp);
return r;
}
-
/* do_mpfr_xor --- perform an ^ operation */
NODE *
do_mpfr_xor(int nargs)
{
- NODE *t1, *t2, *res;
- mpz_t z;
-
- if ((res = get_bit_ops(& t1, & t2, "xor")) != NULL)
- return res;
-
- mpz_init(z);
- mpfr_get_z(mpzval, t1->mpg_numbr, MPFR_RNDZ);
- mpfr_get_z(z, t2->mpg_numbr, MPFR_RNDZ);
- mpz_xor(z, mpzval, z);
-
- res = mpg_node();
- mpfr_set_z(res->mpg_numbr, z, RND_MODE);
- mpz_clear(z);
+ NODE *res;
- DEREF(t1);
- DEREF(t2);
+ if ((res = get_bit_ops("xor")) == NULL) {
+ res = mpg_integer();
+ mpz_xor(res->mpg_i, mpz1, mpz2);
+ }
+ free_bit_ops();
return res;
}
@@ -799,15 +1075,24 @@ do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
int tval;
if (firstrand) {
+#if 0
/* Choose the default algorithm */
gmp_randinit_default(state);
+#endif
+ /*
+ * Choose a specific (Mersenne Twister) algorithm in case the
default
+ * changes in the future.
+ */
+
+ gmp_randinit_mt(state);
+
mpz_init(seed);
- mpz_set_ui(seed, 1L);
+ mpz_set_ui(seed, 1);
/* seed state */
gmp_randseed(state, seed);
firstrand = FALSE;
}
- res = mpg_node();
+ res = mpg_float();
tval = mpfr_urandomb(res->mpg_numbr, state);
IEEE_FMT(res->mpg_numbr, tval);
return res;
@@ -820,20 +1105,27 @@ NODE *
do_mpfr_srand(int nargs)
{
NODE *res;
- int tval;
if (firstrand) {
+#if 0
/* Choose the default algorithm */
gmp_randinit_default(state);
+#endif
+ /*
+ * Choose a specific algorithm (Mersenne Twister) in case
default
+ * changes in the future.
+ */
+
+ gmp_randinit_mt(state);
+
mpz_init(seed);
- mpz_set_ui(seed, 1L);
+ mpz_set_ui(seed, 1);
/* No need to seed state, will change it below */
firstrand = FALSE;
}
- res = mpg_node();
- tval = mpfr_set_z(res->mpg_numbr, seed, RND_MODE); /* previous
seed */
- IEEE_FMT(res->mpg_numbr, tval);
+ res = mpg_integer();
+ mpz_set(res->mpg_i, seed); /* previous seed */
if (nargs == 0)
mpz_set_ui(seed, (unsigned long) time((time_t *) 0));
@@ -843,7 +1135,10 @@ do_mpfr_srand(int nargs)
if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
lintwarn(_("srand: received non-numeric argument"));
force_number(tmp);
- mpfr_get_z(seed, tmp->mpg_numbr, MPFR_RNDZ);
+ if (is_mpg_float(tmp))
+ mpfr_get_z(seed, tmp->mpg_numbr, MPFR_RNDZ);
+ else /* MP integer */
+ mpz_set(seed, tmp->mpg_i);
DEREF(tmp);
}
@@ -852,8 +1147,209 @@ do_mpfr_srand(int nargs)
}
/*
+ * mpg_tofloat --- convert an arbitrary-precision integer operand to
+ * a float without loss of precision. It is assumed that the
+ * MPFR variable has already been initialized.
+ */
+
+static inline mpfr_ptr
+mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
+{
+ size_t prec;
+
+ /*
+ * When implicitely converting a GMP integer operand to a MPFR float,
use
+ * a precision sufficiently large to hold the converted value exactly.
+ *
+ * $ ./gawk -M 'BEGIN { print 13 % 2 }'
+ * 1
+ * If the user-specified precision is used to convert the integer 13 to
a
+ * float, one will get:
+ * $ ./gawk -M 'BEGIN { PREC=2; print 13 % 2.0 }'
+ * 0
+ */
+
+ prec = mpz_sizeinbase(mz, 2); /* most significant 1 bit position
starting at 1 */
+ if (prec > PRECISION_MIN) {
+ prec -= (size_t) mpz_scan1(mz, 0); /* least significant 1
bit index starting at 0 */
+ if (prec > MPFR_PREC_MAX)
+ prec = MPFR_PREC_MAX;
+ if (prec > PRECISION_MIN)
+ mpfr_set_prec(mf, prec);
+ }
+
+ mpfr_set_z(mf, mz, RND_MODE);
+ return mf;
+}
+
+
+/* mpg_add --- add arbitrary-precision numbers */
+
+static NODE *
+mpg_add(NODE *t1, NODE *t2)
+{
+ NODE *r;
+ int tval;
+
+ if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
+ r = mpg_integer();
+ mpz_add(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ } else {
+ r = mpg_float();
+ if (is_mpg_integer(t2))
+ tval = mpfr_add_z(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_i, RND_MODE);
+ else if (is_mpg_integer(t1))
+ tval = mpfr_add_z(r->mpg_numbr, t2->mpg_numbr,
t1->mpg_i, RND_MODE);
+ else
+ tval = mpfr_add(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_numbr, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
+ return r;
+}
+
+/* mpg_sub --- subtract arbitrary-precision numbers */
+
+static NODE *
+mpg_sub(NODE *t1, NODE *t2)
+{
+ NODE *r;
+ int tval;
+
+ if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
+ r = mpg_integer();
+ mpz_sub(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ } else {
+ r = mpg_float();
+ if (is_mpg_integer(t2))
+ tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_i, RND_MODE);
+ else if (is_mpg_integer(t1)) {
+#if (!defined(MPFR_VERSION) || (MPFR_VERSION < MPFR_VERSION_NUM(3,1,0)))
+ NODE *tmp = t1;
+ t1 = t2;
+ t2 = tmp;
+ tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_i, RND_MODE);
+ tval = mpfr_neg(r->mpg_numbr, r->mpg_numbr, RND_MODE);
+ t2 = t1;
+ t1 = tmp;
+#else
+ tval = mpfr_z_sub(r->mpg_numbr, t1->mpg_i,
t2->mpg_numbr, RND_MODE);
+#endif
+ } else
+ tval = mpfr_sub(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_numbr, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
+ return r;
+}
+
+/* mpg_mul --- multiply arbitrary-precision numbers */
+
+static NODE *
+mpg_mul(NODE *t1, NODE *t2)
+{
+ NODE *r;
+ int tval;
+
+ if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
+ r = mpg_integer();
+ mpz_mul(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ } else {
+ r = mpg_float();
+ if (is_mpg_integer(t2))
+ tval = mpfr_mul_z(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_i, RND_MODE);
+ else if (is_mpg_integer(t1))
+ tval = mpfr_mul_z(r->mpg_numbr, t2->mpg_numbr,
t1->mpg_i, RND_MODE);
+ else
+ tval = mpfr_mul(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_numbr, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
+ return r;
+}
+
+
+/* mpg_pow --- exponentiation involving arbitrary-precision numbers */
+
+static NODE *
+mpg_pow(NODE *t1, NODE *t2)
+{
+ NODE *r;
+ int tval;
+
+ if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
+ if (mpz_sgn(t2->mpg_i) >= 0 && mpz_fits_ulong_p(t2->mpg_i)) {
+ r = mpg_integer();
+ mpz_pow_ui(r->mpg_i, t1->mpg_i, mpz_get_ui(t2->mpg_i));
+ } else {
+ mpfr_ptr p1, p2;
+ p1 = MP_FLOAT(t1);
+ p2 = MP_FLOAT(t2);
+ r = mpg_float();
+ tval = mpfr_pow(r->mpg_numbr, p1, p2, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
+ } else {
+ r = mpg_float();
+ if (is_mpg_integer(t2))
+ tval = mpfr_pow_z(r->mpg_numbr, t1->mpg_numbr,
t2->mpg_i, RND_MODE);
+ else {
+ mpfr_ptr p1;
+ p1 = MP_FLOAT(t1);
+ tval = mpfr_pow(r->mpg_numbr, p1, t2->mpg_numbr,
RND_MODE);
+ }
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
+ return r;
+}
+
+/* mpg_div --- arbitrary-precision division */
+
+static NODE *
+mpg_div(NODE *t1, NODE *t2)
+{
+ NODE *r;
+ int tval;
+
+ if (is_mpg_integer(t1) && is_mpg_integer(t2)
+ && (mpz_sgn(t2->mpg_i) != 0) /* not dividing by 0 */
+ && mpz_divisible_p(t1->mpg_i, t2->mpg_i)
+ ) {
+ r = mpg_integer();
+ mpz_divexact(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ } else {
+ mpfr_ptr p1, p2;
+ p1 = MP_FLOAT(t1);
+ p2 = MP_FLOAT(t2);
+ r = mpg_float();
+ tval = mpfr_div(r->mpg_numbr, p1, p2, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
+ return r;
+}
+
+/* mpg_mod --- modulus operation with arbitrary-precision numbers */
+
+static NODE *
+mpg_mod(NODE *t1, NODE *t2)
+{
+ NODE *r;
+ int tval;
+
+ if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
+ r = mpg_integer();
+ mpz_mod(r->mpg_i, t1->mpg_i, t2->mpg_i);
+ } else {
+ mpfr_ptr p1, p2;
+ p1 = MP_FLOAT(t1);
+ p2 = MP_FLOAT(t2);
+ r = mpg_float();
+ tval = mpfr_fmod(r->mpg_numbr, p1, p2, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ }
+ return r;
+}
+
+/*
* mpg_interpret --- pre-exec hook in the interpreter. Handles
- * arithmetic operations with MPFR numbers.
+ * arithmetic operations with MPFR/GMP numbers.
*/
static int
@@ -864,9 +1360,7 @@ mpg_interpret(INSTRUCTION **cp)
NODE *r = NULL;
NODE *t1, *t2;
NODE **lhs;
- AWKNUM x;
- mpfr_ptr p1, p2;
- int tval;
+ int tval; /* the ternary value returned by a MPFR function */
switch ((op = pc->opcode)) {
case Op_plus_i:
@@ -876,9 +1370,7 @@ mpg_interpret(INSTRUCTION **cp)
t2 = POP_NUMBER();
plus:
t1 = TOP_NUMBER();
- r = mpg_node();
- tval = mpfr_add(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr,
RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ r = mpg_add(t1, t2);
DEREF(t1);
if (op == Op_plus)
DEREF(t2);
@@ -892,9 +1384,7 @@ plus:
t2 = POP_NUMBER();
minus:
t1 = TOP_NUMBER();
- r = mpg_node();
- tval = mpfr_sub(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr,
RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ r = mpg_sub(t1, t2);
DEREF(t1);
if (op == Op_minus)
DEREF(t2);
@@ -908,9 +1398,7 @@ minus:
t2 = POP_NUMBER();
times:
t1 = TOP_NUMBER();
- r = mpg_node();
- tval = mpfr_mul(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr,
RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ r = mpg_mul(t1, t2);
DEREF(t1);
if (op == Op_times)
DEREF(t2);
@@ -924,9 +1412,7 @@ times:
t2 = POP_NUMBER();
exp:
t1 = TOP_NUMBER();
- r = mpg_node();
- tval = mpfr_pow(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr,
RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ r = mpg_pow(t1, t2);
DEREF(t1);
if (op == Op_exp)
DEREF(t2);
@@ -940,9 +1426,7 @@ exp:
t2 = POP_NUMBER();
quotient:
t1 = TOP_NUMBER();
- r = mpg_node();
- tval = mpfr_div(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr,
RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ r = mpg_div(t1, t2);
DEREF(t1);
if (op == Op_quotient)
DEREF(t2);
@@ -956,9 +1440,7 @@ quotient:
t2 = POP_NUMBER();
mod:
t1 = TOP_NUMBER();
- r = mpg_node();
- tval = mpfr_fmod(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr,
RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
+ r = mpg_mod(t1, t2);
DEREF(t1);
if (op == Op_mod)
DEREF(t2);
@@ -967,56 +1449,84 @@ mod:
case Op_preincrement:
case Op_predecrement:
- x = op == Op_preincrement ? 1.0 : -1.0;
lhs = TOP_ADDRESS();
t1 = *lhs;
force_number(t1);
-#if 0
- /*
- * The optimizations for fixed precision do not always
- * work the same way in arbitrary precision. With this
optimization on,
- * gawk -M 'BEGIN { PREC=53; i=2^53; PREC=113; ++i; print i}'
- * prints 2^53 instead of 2^53+1.
- */
+ if (is_mpg_integer(t1)) {
+ if (t1->valref == 1 && t1->flags ==
(MALLOC|MPZN|NUMCUR|NUMBER))
+ /* Efficiency hack. Big speed-up (> 30%) in a tight
loop */
+ r = t1;
+ else
+ r = *lhs = mpg_integer();
+ if (op == Op_preincrement)
+ mpz_add_ui(r->mpg_i, t1->mpg_i, 1);
+ else
+ mpz_sub_ui(r->mpg_i, t1->mpg_i, 1);
+ } else {
- if (t1->valref == 1 && t1->flags ==
(MALLOC|MPFN|NUMCUR|NUMBER)) {
- /* optimization */
- tval = mpfr_add_d(t1->mpg_numbr, t1->mpg_numbr, x,
RND_MODE);
- IEEE_FMT(t1->mpg_numbr, tval);
- r = t1;
+ /*
+ * An optimization like the one above is not going to
work
+ * for a floating-point number. With it,
+ * gawk -M 'BEGIN { PREC=53; i=2^53+0.0; PREC=113;
++i; print i}'
+ * will output 2^53 instead of 2^53+1.
+ */
+
+ r = *lhs = mpg_float();
+ tval = mpfr_add_si(r->mpg_numbr, t1->mpg_numbr,
+ op == Op_preincrement ? 1 : -1,
+ RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
}
-#endif
- r = *lhs = mpg_node();
- tval = mpfr_add_d(r->mpg_numbr, t1->mpg_numbr, x, RND_MODE);
- IEEE_FMT(r->mpg_numbr, tval);
- unref(t1);
+ if (r != t1)
+ unref(t1);
UPREF(r);
REPLACE(r);
break;
case Op_postincrement:
case Op_postdecrement:
- x = op == Op_postincrement ? 1.0 : -1.0;
lhs = TOP_ADDRESS();
t1 = *lhs;
force_number(t1);
- r = mpg_node();
- tval = mpfr_set(r->mpg_numbr, t1->mpg_numbr, RND_MODE); /* r =
t1 */
- IEEE_FMT(r->mpg_numbr, tval);
- t2 = *lhs = mpg_node();
- tval = mpfr_add_d(t2->mpg_numbr, t1->mpg_numbr, x, RND_MODE);
- IEEE_FMT(t2->mpg_numbr, tval);
- unref(t1);
+
+ if (is_mpg_integer(t1)) {
+ r = mpg_integer();
+ mpz_set(r->mpg_i, t1->mpg_i);
+ if (t1->valref == 1 && t1->flags ==
(MALLOC|MPZN|NUMCUR|NUMBER))
+ /* Efficiency hack. Big speed-up (> 30%) in a tight
loop */
+ t2 = t1;
+ else
+ t2 = *lhs = mpg_integer();
+ if (op == Op_postincrement)
+ mpz_add_ui(t2->mpg_i, t1->mpg_i, 1);
+ else
+ mpz_sub_ui(t2->mpg_i, t1->mpg_i, 1);
+ } else {
+ r = mpg_float();
+ tval = mpfr_set(r->mpg_numbr, t1->mpg_numbr, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ t2 = *lhs = mpg_float();
+ tval = mpfr_add_si(t2->mpg_numbr, t1->mpg_numbr,
+ op == Op_postincrement ? 1 : -1,
+ RND_MODE);
+ IEEE_FMT(t2->mpg_numbr, tval);
+ }
+ if (t2 != t1)
+ unref(t1);
REPLACE(r);
break;
case Op_unary_minus:
t1 = TOP_NUMBER();
- r = mpg_node();
- mpfr_set(r->mpg_numbr, t1->mpg_numbr, RND_MODE); /* r =
t1 */
- tval = mpfr_neg(r->mpg_numbr, r->mpg_numbr, RND_MODE); /*
change sign */
- IEEE_FMT(r->mpg_numbr, tval);
+ if (is_mpg_float(t1)) {
+ r = mpg_float();
+ tval = mpfr_neg(r->mpg_numbr, t1->mpg_numbr, RND_MODE);
+ IEEE_FMT(r->mpg_numbr, tval);
+ } else {
+ r = mpg_integer();
+ mpz_neg(r->mpg_i, t1->mpg_i);
+ }
DEREF(t1);
REPLACE(r);
break;
@@ -1029,41 +1539,35 @@ mod:
case Op_assign_exp:
lhs = POP_ADDRESS();
t1 = *lhs;
- p1 = force_number(t1)->mpg_numbr;
-
+ force_number(t1);
t2 = TOP_NUMBER();
- p2 = t2->mpg_numbr;
- r = mpg_node();
switch (op) {
case Op_assign_plus:
- tval = mpfr_add(r->mpg_numbr, p1, p2, RND_MODE);
+ r = mpg_add(t1, t2);
break;
case Op_assign_minus:
- tval = mpfr_sub(r->mpg_numbr, p1, p2, RND_MODE);
+ r = mpg_sub(t1, t2);
break;
case Op_assign_times:
- tval = mpfr_mul(r->mpg_numbr, p1, p2, RND_MODE);
+ r = mpg_mul(t1, t2);
break;
case Op_assign_quotient:
- tval = mpfr_div(r->mpg_numbr, p1, p2, RND_MODE);
+ r = mpg_div(t1, t2);
break;
case Op_assign_mod:
- tval = mpfr_fmod(r->mpg_numbr, p1, p2, RND_MODE);
+ r = mpg_mod(t1, t2);
break;
case Op_assign_exp:
- tval = mpfr_pow(r->mpg_numbr, p1, p2, RND_MODE);
+ r = mpg_pow(t1, t2);
break;
default:
cant_happen();
}
- IEEE_FMT(r->mpg_numbr, tval);
-
DEREF(t2);
unref(*lhs);
*lhs = r;
-
UPREF(r);
REPLACE(r);
break;
diff --git a/msg.c b/msg.c
index e651c8c..7881818 100644
--- a/msg.c
+++ b/msg.c
@@ -64,15 +64,16 @@ err(const char *s, const char *emsg, va_list argp)
}
#ifdef HAVE_MPFR
- if (FNR_node && (FNR_node->var_value->flags & MPFN) != 0) {
- mpg_update_var(FNR_node);
- mpfr_get_z(mpzval, FNR_node->var_value->mpg_numbr, MPFR_RNDZ);
- if (mpz_sgn(mpzval) > 0) {
+ if (FNR_node && is_mpg_number(FNR_node->var_value)) {
+ NODE *val;
+ val = mpg_update_var(FNR_node);
+ assert((val->flags & MPZN) != 0);
+ if (mpz_sgn(val->mpg_i) > 0) {
file = FILENAME_node->var_value->stptr;
(void) putc('(', stderr);
if (file)
(void) fprintf(stderr, "FILENAME=%s ", file);
- (void) mpfr_fprintf(stderr, "FNR=%Zd) ", mpzval);
+ (void) mpfr_fprintf(stderr, "FNR=%Zd) ", val->mpg_i);
}
} else
#endif
diff --git a/node.c b/node.c
index 27ed791..8dbe68a 100644
--- a/node.c
+++ b/node.c
@@ -26,14 +26,17 @@
#include "awk.h"
#include "math.h"
+#include "floatmagic.h" /* definition of isnan */
static int is_ieee_magic_val(const char *val);
+static NODE *r_make_number(double x);
static AWKNUM get_ieee_magic_val(const char *val);
extern NODE **fmt_list; /* declared in eval.c */
NODE *(*make_number)(double) = r_make_number;
NODE *(*str2number)(NODE *) = r_force_number;
NODE *(*format_val)(const char *, int, NODE *) = r_format_val;
+int (*cmp_numbers)(const NODE *, const NODE *) = cmp_awknums;
/* force_number --- force a value to be numeric */
@@ -321,9 +324,9 @@ r_dupnode(NODE *n)
return r;
}
-/* make_number --- allocate a node with defined number */
+/* r_make_number --- allocate a node with defined number */
-NODE *
+static NODE *
r_make_number(double x)
{
NODE *r;
@@ -341,6 +344,32 @@ r_make_number(double x)
return r;
}
+/* cmp_awknums --- compare two AWKNUMs */
+
+int
+cmp_awknums(const NODE *t1, const NODE *t2)
+{
+ /*
+ * This routine is also used to sort numeric array indices or values.
+ * For the purposes of sorting, NaN is considered greater than
+ * any other value, and all NaN values are considered equivalent and
equal.
+ * This isn't in compliance with IEEE standard, but compliance w.r.t.
NaN
+ * comparison at the awk level is a different issue, and needs to be
dealt
+ * with in the interpreter for each opcode seperately.
+ */
+
+ if (isnan(t1->numbr))
+ return ! isnan(t2->numbr);
+ if (isnan(t2->numbr))
+ return -1;
+ /* don't subtract, in case one or both are infinite */
+ if (t1->numbr == t2->numbr)
+ return 0;
+ if (t1->numbr < t2->numbr)
+ return -1;
+ return 1;
+}
+
/* r_make_str_node --- make a string node */
@@ -443,8 +472,10 @@ r_unref(NODE *tmp)
#endif
#ifdef HAVE_MPFR
- if ((tmp->flags & MPFN) != 0)
+ if (is_mpg_float(tmp))
mpfr_clear(tmp->mpg_numbr);
+ else if (is_mpg_integer(tmp))
+ mpz_clear(tmp->mpg_i);
#endif
free_wstr(tmp);
diff --git a/profile.c b/profile.c
index 48f90c6..7d5c07b 100644
--- a/profile.c
+++ b/profile.c
@@ -1209,8 +1209,10 @@ pp_number(NODE *n)
emalloc(str, char *, PP_PRECISION + 10, "pp_number");
#ifdef HAVE_MPFR
- if (n->flags & MPFN)
+ if (is_mpg_float(n))
mpfr_sprintf(str, "%0.*R*g", PP_PRECISION, RND_MODE,
n->mpg_numbr);
+ else if (is_mpg_integer(n))
+ mpfr_sprintf(str, "%Zd", n->mpg_i);
else
#endif
sprintf(str, "%0.*g", PP_PRECISION, n->numbr);
diff --git a/str_array.c b/str_array.c
index 6895f58..1b3a33f 100644
--- a/str_array.c
+++ b/str_array.c
@@ -150,7 +150,7 @@ str_lookup(NODE *symbol, NODE *subs)
* never be used.
*/
- if ((subs->flags & (MPFN|NUMCUR)) == NUMCUR) {
+ if ((subs->flags & (MPFN|MPZN|NUMCUR)) == NUMCUR) {
tmp->numbr = subs->numbr;
tmp->flags |= NUMCUR;
}
diff --git a/test/Gentests b/test/Gentests
index 640c3a0..ae56b8c 100755
--- a/test/Gentests
+++ b/test/Gentests
@@ -100,9 +100,12 @@ function generate(x, s)
printf "address@hidden address@hidden"
printf "address@hidden(srcdir) $(AWK) -f address@hidden %s >_$@ 2>&1 ||
echo EXIT CODE: $$? >>address@hidden", s
+
if (x in mpfr) {
delete mpfr[x]
- printf "address@hidden($(CMP) $(srcdir)/address@hidden _$@ ||
$(CMP) $(srcdir)/address@hidden _$@) && rm -f address@hidden"
+ printf "address@hidden test -z \"$$AWKFLAGS\" ; then $(CMP)
$(srcdir)/address@hidden _$@ && rm -f _$@ ; else \\\n"
+ printf "\t$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ;
\\\n"
+ printf "\tfi\n\n"
} else {
printf "address@hidden(CMP) $(srcdir)/address@hidden _$@ && rm
-f address@hidden"
}
diff --git a/test/Makefile.am b/test/Makefile.am
index bc174fb..da3faea 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -846,7 +846,7 @@ INET_TESTS = inetdayu inetdayt inetechu inetecht
MACHINE_TESTS = double1 double2 fmtspcl intformat
-MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange
+MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange mpfrsort mpfrbigint
LOCALE_CHARSET_TESTS = \
asort asorti fmttest fnarydel fnparydl lc_num1 mbfw1 \
@@ -1112,7 +1112,9 @@ fmtspcl.ok: fmtspcl.tok Makefile
fmtspcl: fmtspcl.ok
@echo $@
@$(AWK) -f $(srcdir)/fmtspcl.awk --lint >_$@ 2>&1 || echo EXIT CODE:
$$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
+ fi
reint::
@echo $@
@@ -1455,6 +1457,13 @@ rri1::
AWKPATH=$(srcdir) $(AWK) -f address@hidden < $(srcdir)/address@hidden
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+rand:
+ @echo $@
+ @AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ ($(CMP) $(srcdir)/address@hidden _$@ || $(CMP) $(srcdir)/address@hidden
_$@) && rm -f _$@ ; \
+ fi
+
mpfrieee:
@echo $@
@$(AWK) -M -vPREC=double -f $(srcdir)/address@hidden > _$@ 2>&1
@@ -1475,6 +1484,16 @@ mpfrnr:
@$(AWK) -M -vPREC=113 -f $(srcdir)/address@hidden
$(srcdir)/address@hidden > _$@
@-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+mpfrsort:
+ @echo $@
+ @$(AWK) -M -vPREC=53 -f $(srcdir)/address@hidden > _$@ 2>&1
+ @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
+mpfrbigint:
+ @echo $@
+ @$(AWK) -M -f $(srcdir)/address@hidden > _$@ 2>&1
+ @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
# Targets generated for other tests:
include Maketests
diff --git a/test/Makefile.in b/test/Makefile.in
index 7a88e83..4eb9590 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -1029,7 +1029,7 @@ GAWK_EXT_TESTS = \
EXTRA_TESTS = inftest regtest
INET_TESTS = inetdayu inetdayt inetechu inetecht
MACHINE_TESTS = double1 double2 fmtspcl intformat
-MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange
+MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange mpfrsort mpfrbigint
LOCALE_CHARSET_TESTS = \
asort asorti fmttest fnarydel fnparydl lc_num1 mbfw1 \
mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc
@@ -1463,7 +1463,9 @@ fmtspcl.ok: fmtspcl.tok Makefile
fmtspcl: fmtspcl.ok
@echo $@
@$(AWK) -f $(srcdir)/fmtspcl.awk --lint >_$@ 2>&1 || echo EXIT CODE:
$$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
+ fi
reint::
@echo $@
@@ -1806,6 +1808,13 @@ rri1::
AWKPATH=$(srcdir) $(AWK) -f address@hidden < $(srcdir)/address@hidden
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+rand:
+ @echo $@
+ @AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ ($(CMP) $(srcdir)/address@hidden _$@ || $(CMP) $(srcdir)/address@hidden
_$@) && rm -f _$@ ; \
+ fi
+
mpfrieee:
@echo $@
@$(AWK) -M -vPREC=double -f $(srcdir)/address@hidden > _$@ 2>&1
@@ -1825,6 +1834,16 @@ mpfrnr:
@echo $@
@$(AWK) -M -vPREC=113 -f $(srcdir)/address@hidden
$(srcdir)/address@hidden > _$@
@-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
+mpfrsort:
+ @echo $@
+ @$(AWK) -M -vPREC=53 -f $(srcdir)/address@hidden > _$@ 2>&1
+ @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+
+mpfrbigint:
+ @echo $@
+ @$(AWK) -M -f $(srcdir)/address@hidden > _$@ 2>&1
+ @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
Gt-dummy:
# file Maketests, generated from Makefile.am by the Gentests program
addcomma:
@@ -2467,11 +2486,6 @@ prtoeval:
@AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
@-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
-rand:
- @echo $@
- @AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
-
range1:
@echo $@
@AWKPATH=$(srcdir) $(AWK) -f address@hidden < $(srcdir)/address@hidden
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -2995,12 +3009,16 @@ fmttest:
fnarydel:
@echo $@
@AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
+ fi
fnparydl:
@echo $@
@AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
+ fi
rebt8b2:
@echo $@
diff --git a/test/Maketests b/test/Maketests
index e7577de..4bc06e5 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -640,11 +640,6 @@ prtoeval:
@AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
@-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
-rand:
- @echo $@
- @AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
-
range1:
@echo $@
@AWKPATH=$(srcdir) $(AWK) -f address@hidden < $(srcdir)/address@hidden
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@@ -1168,12 +1163,16 @@ fmttest:
fnarydel:
@echo $@
@AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
+ fi
fnparydl:
@echo $@
@AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT
CODE: $$? >>_$@
- @-($(CMP) $(srcdir)/address@hidden _$@ || $(CMP)
$(srcdir)/address@hidden _$@) && rm -f _$@
+ @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ &&
rm -f _$@ ; else \
+ $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
+ fi
rebt8b2:
@echo $@
diff --git a/test/mpfrbigint.awk b/test/mpfrbigint.awk
new file mode 100644
index 0000000..bfdd871
--- /dev/null
+++ b/test/mpfrbigint.awk
@@ -0,0 +1,11 @@
+BEGIN {
+ x = 5^4^3^2
+ print "# of digits =", length(x)
+ print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20)
+
+ PREC = 1 + 3.321928095 * length(x); # 1 + digits * log2(10)
+ print "floating-point computation with precision =", PREC
+ y = 5.0^4.0^3.0^2.0
+ print "# of digits =", length(y)
+ print substr(y, 1, 20), "...", substr(y, length(y) - 19, 20)
+}
diff --git a/test/mpfrbigint.ok b/test/mpfrbigint.ok
new file mode 100644
index 0000000..670d4e0
--- /dev/null
+++ b/test/mpfrbigint.ok
@@ -0,0 +1,5 @@
+# of digits = 183231
+62060698786608744707 ... 92256259918212890625
+floating-point computation with precision = 608681
+# of digits = 183231
+62060698786608744707 ... 92256259918212890625
diff --git a/test/mpfrsort.awk b/test/mpfrsort.awk
new file mode 100644
index 0000000..6f7fa65
--- /dev/null
+++ b/test/mpfrsort.awk
@@ -0,0 +1,8 @@
+BEGIN {
+# s = "1.0 +nan 0.0 -1 +inf -0.0 1 nan 1.0 -nan -inf 2.0"
+ s = "1.0 +nan 0.0 -1 +inf -0.0 1 1.0 -nan -inf 2.0"
+ split(s, a)
+ PROCINFO["sorted_in"] = "@val_num_asc"
+ for (i in a)
+ print a[i]
+}
diff --git a/test/mpfrsort.ok b/test/mpfrsort.ok
new file mode 100644
index 0000000..77a51ec
--- /dev/null
+++ b/test/mpfrsort.ok
@@ -0,0 +1,11 @@
+-inf
+-1
+-0.0
+0.0
+1
+1.0
+1.0
+2.0
++inf
++nan
+-nan
diff --git a/test/rand-mpfr1.ok b/test/rand-mpfr1.ok
new file mode 100644
index 0000000..448f403
--- /dev/null
+++ b/test/rand-mpfr1.ok
@@ -0,0 +1 @@
+ 25 42 47 49 80 5 4 92 59 96 8 63 92 28 41 37 80 51 48
-----------------------------------------------------------------------
Summary of changes:
README_d/README.mpfr | 10 +
array.c | 74 ++--
awk.h | 65 ++-
awkgram.c | 341 +++++++-------
awkgram.y | 77 ++--
builtin.c | 220 ++++++---
command.c | 13 +-
command.y | 13 +-
debug.c | 6 +-
eval.c | 58 +--
field.c | 7 +-
interpret.h | 12 +-
io.c | 22 +-
main.c | 18 +-
mpfr.c | 1246 +++++++++++++++++++++++++++++++++++---------------
msg.c | 11 +-
node.c | 37 ++-
profile.c | 4 +-
str_array.c | 2 +-
test/Gentests | 5 +-
test/Makefile.am | 23 +-
test/Makefile.in | 36 ++-
test/Maketests | 13 +-
test/mpfrbigint.awk | 11 +
test/mpfrbigint.ok | 5 +
test/mpfrsort.awk | 8 +
test/mpfrsort.ok | 11 +
test/rand-mpfr1.ok | 1 +
28 files changed, 1552 insertions(+), 797 deletions(-)
create mode 100644 README_d/README.mpfr
create mode 100644 test/mpfrbigint.awk
create mode 100644 test/mpfrbigint.ok
create mode 100644 test/mpfrsort.awk
create mode 100644 test/mpfrsort.ok
create mode 100644 test/rand-mpfr1.ok
hooks/post-receive
--
gawk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gawk-diffs] [SCM] gawk branch, gawk_mpfr, updated. 40645cb3cb155eb59dd745af4ae0e06e729c8eb1,
John Haque <=