aboutsummaryrefslogtreecommitdiffstats
path: root/mpfr.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpfr.c')
-rw-r--r--mpfr.c254
1 files changed, 169 insertions, 85 deletions
diff --git a/mpfr.c b/mpfr.c
index 0875bc60..18fe7444 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -47,14 +47,6 @@ set_RNDMODE()
extern NODE **fmt_list; /* declared in eval.c */
-#define POP_TWO_SCALARS(s1, s2) \
-s2 = POP_SCALAR(); \
-s1 = POP(); \
-do { if (s1->type == Node_var_array) { \
-DEREF(s2); \
-fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \
-}} while (FALSE)
-
mpz_t mpzval; /* GMP integer type; used as temporary in many places */
mpfr_t MNR;
mpfr_t MFNR;
@@ -92,7 +84,10 @@ mpfr_node()
NODE *r;
getnode(r);
r->type = Node_val;
+
+ /* Initialize, set precision to the default precision, and value to NaN */
mpfr_init(r->mpfr_numbr);
+
r->valref = 1;
r->flags = MALLOC|MPFN|NUMBER|NUMCUR;
r->stptr = NULL;
@@ -170,6 +165,7 @@ mpfr_force_number(NODE *n)
return n;
}
+
/* mpfr_format_val --- format a numeric value based on format */
static NODE *
@@ -267,6 +263,7 @@ mpfr_set_var(NODE *n)
mpfr_get_z(mpzval, p, MPFR_RNDZ);
if (mpfr_signbit(p)) {
+ /* It is a negative number ! */
neg = TRUE;
mpz_neg(mpzval, mpzval);
}
@@ -456,25 +453,63 @@ do_mpfr_atan2(int nargs)
NODE *
do_mpfr_compl(int nargs)
{
- NODE *tmp;
+ 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)->mpfr_numbr;
+ if (! mpfr_number_p(p)) {
+ /* [+-]inf or NaN */
+ return tmp;
+ }
+
+ if (do_lint) {
+ if (mpfr_signbit(p))
+ lintwarn("%s",
+ mpfr_fmt(_("compl(%Rg): negative value will give strange results"), p)
+ );
+ if (! mpfr_integer_p(p))
+ lintwarn("%s",
+ mpfr_fmt(_("comp(%Rg): fractional value will be truncated"), p)
+ );
+ }
+ mpfr_get_z(mpzval, p, MPFR_RNDZ);
+ mpz_com(mpzval, mpzval);
+ r = mpfr_node();
+ mpfr_set_z(r->mpfr_numbr, mpzval, RND_MODE);
DEREF(tmp);
- return dupnode(Nnull_string);
+ return r;
}
-/* do_cos --- do the cos function */
+#define SPEC_MATH(X) \
+NODE *tmp, *res; \
+tmp = POP_SCALAR(); \
+if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) \
+ lintwarn(_("%s: received non-numeric argument"), #X); \
+force_number(tmp); \
+res = mpfr_node(); \
+mpfr_##X(res->mpfr_numbr, tmp->mpfr_numbr, RND_MODE); \
+DEREF(tmp); \
+return res
+
+
+/* do_sin --- do the sin function */
NODE *
-do_mpfr_cos(int nargs)
+do_mpfr_sin(int nargs)
{
- NODE *tmp;
+ SPEC_MATH(sin);
+}
- tmp = POP_SCALAR();
+/* do_cos --- do the cos function */
- DEREF(tmp);
- return dupnode(Nnull_string);
+NODE *
+do_mpfr_cos(int nargs)
+{
+ SPEC_MATH(cos);
}
/* do_exp --- exponential function */
@@ -482,38 +517,46 @@ do_mpfr_cos(int nargs)
NODE *
do_mpfr_exp(int nargs)
{
- NODE *tmp;
-
- tmp = POP_SCALAR();
-
- DEREF(tmp);
- return dupnode(Nnull_string);
+ SPEC_MATH(exp);
}
-/* do_int --- convert double to int for awk */
+/* do_log --- the log function */
NODE *
-do_mpfr_int(int nargs)
+do_mpfr_log(int nargs)
{
- NODE *tmp;
+ SPEC_MATH(log);
+}
- tmp = POP_SCALAR();
+/* do_sqrt --- do the sqrt function */
- DEREF(tmp);
- return dupnode(Nnull_string);
+NODE *
+do_mpfr_sqrt(int nargs)
+{
+ SPEC_MATH(sqrt);
}
-/* do_log --- the log function */
+
+/* do_int --- convert double to int for awk */
NODE *
-do_mpfr_log(int nargs)
+do_mpfr_int(int nargs)
{
- NODE *tmp;
+ NODE *tmp, *r;
tmp = POP_SCALAR();
-
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("int: received non-numeric argument"));
+ force_number(tmp);
+ if (! mpfr_number_p(tmp->mpfr_numbr)) {
+ /* [+-]inf or NaN */
+ return tmp;
+ }
+ mpfr_get_z(mpzval, tmp->mpfr_numbr, MPFR_RNDZ);
+ r = mpfr_node();
+ mpfr_set_z(r->mpfr_numbr, mpzval, RND_MODE);
DEREF(tmp);
- return dupnode(Nnull_string);
+ return r;
}
@@ -554,21 +597,24 @@ do_mpfr_lshift(int nargs)
NODE *
do_mpfr_or(int nargs)
{
- NODE *s1, *s2;
+ NODE *t1, *t2, *res;
+ mpz_t z;
- POP_TWO_SCALARS(s1, s2);
+ if ((res = get_bit_ops(& t1, & t2, "or")) != NULL)
+ return res;
- DEREF(s1);
- DEREF(s2);
- return dupnode(Nnull_string);
-}
+ mpz_init(z);
+ mpfr_get_z(mpzval, t1->mpfr_numbr, MPFR_RNDZ);
+ mpfr_get_z(z, t2->mpfr_numbr, MPFR_RNDZ);
+ mpz_ior(z, mpzval, z);
-/* do_rand --- do the rand function */
+ res = mpfr_node();
+ mpfr_set_z(res->mpfr_numbr, z, RND_MODE);
+ mpz_clear(z);
-NODE *
-do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
-{
- return dupnode(Nnull_string);
+ DEREF(t1);
+ DEREF(t2);
+ return res;
}
@@ -613,82 +659,120 @@ do_mpfr_rhift(int nargs)
res = mpfr_node();
mpfr_set_z(res->mpfr_numbr, mpzval, RND_MODE); /* integer to float conversion */
-
DEREF(t1);
DEREF(t2);
return res;
}
-/* do_sin --- do the sin function */
+/* do_strtonum --- the strtonum function */
NODE *
-do_mpfr_sin(int nargs)
+do_mpfr_strtonum(int nargs)
{
- NODE *tmp;
+ NODE *tmp, *r;
+ int base;
tmp = POP_SCALAR();
+ r = mpfr_node();
+ if ((tmp->flags & (NUMBER|NUMCUR)) != 0)
+ mpfr_set(r->mpfr_numbr, tmp->mpfr_numbr, RND_MODE);
+ else if ((base = get_numbase(tmp->stptr, use_lc_numeric)) != 10) {
+ mpfr_strtofr(r->mpfr_numbr, tmp->stptr, NULL, base, RND_MODE);
+ errno = 0;
+ } else {
+ (void) force_number(tmp);
+ mpfr_set(r->mpfr_numbr, tmp->mpfr_numbr, RND_MODE);
+ }
DEREF(tmp);
- return dupnode(Nnull_string);
+ return r;
}
-/* do_sqrt --- do the sqrt function */
+
+/* do_xor --- perform an ^ operation */
NODE *
-do_mpfr_sqrt(int nargs)
+do_mpfr_xor(int nargs)
{
- NODE *tmp;
-
- tmp = POP_SCALAR();
-
- DEREF(tmp);
- return dupnode(Nnull_string);
-}
+ NODE *t1, *t2, *res;
+ mpz_t z;
-/* do_srand --- seed the random number generator */
+ if ((res = get_bit_ops(& t1, & t2, "xor")) != NULL)
+ return res;
-NODE *
-do_mpfr_srand(int nargs)
-{
- NODE *tmp;
+ mpz_init(z);
+ mpfr_get_z(mpzval, t1->mpfr_numbr, MPFR_RNDZ);
+ mpfr_get_z(z, t2->mpfr_numbr, MPFR_RNDZ);
+ mpz_xor(z, mpzval, z);
- if (nargs == 0)
- ;
- else {
- tmp = POP_SCALAR();
- DEREF(tmp);
- }
+ res = mpfr_node();
+ mpfr_set_z(res->mpfr_numbr, z, RND_MODE);
+ mpz_clear(z);
- return dupnode(Nnull_string);
+ DEREF(t1);
+ DEREF(t2);
+ return res;
}
-/* do_strtonum --- the strtonum function */
+static int firstrand = TRUE;
+static gmp_randstate_t state;
+static mpz_t seed; /* current seed */
+
+/* do_rand --- do the rand function */
NODE *
-do_mpfr_strtonum(int nargs)
+do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
{
- NODE *tmp;
-
- tmp = POP_SCALAR();
- DEREF(tmp);
-
- return dupnode(Nnull_string);
+ NODE *res;
+
+ if (firstrand) {
+ /* Choose the default algorithm */
+ gmp_randinit_default(state);
+ mpz_init(seed);
+ mpz_set_ui(seed, 1L);
+ /* seed state */
+ gmp_randseed(state, seed);
+ firstrand = FALSE;
+ }
+ res = mpfr_node();
+ mpfr_urandomb(res->mpfr_numbr, state);
+ return res;
}
-/* do_xor --- perform an ^ operation */
+/* do_srand --- seed the random number generator */
NODE *
-do_mpfr_xor(int nargs)
+do_mpfr_srand(int nargs)
{
- NODE *s1, *s2;
+ NODE *tmp, *res;
+
+ if (firstrand) {
+ /* Choose the default algorithm */
+ gmp_randinit_default(state);
+ mpz_init(seed);
+ mpz_set_ui(seed, 1L);
+ /* No need to seed state, will change it below */
+ firstrand = FALSE;
+ }
- POP_TWO_SCALARS(s1, s2);
+ res = mpfr_node();
+ mpfr_set_z(res->mpfr_numbr, seed, RND_MODE); /* previous seed */
+
+ if (nargs == 0)
+ mpz_set_ui(seed, (unsigned long) time((time_t *) 0));
+ else {
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("srand: received non-numeric argument"));
+ force_number(tmp);
+ mpfr_get_z(seed, tmp->mpfr_numbr, MPFR_RNDZ);
+ DEREF(tmp);
+ }
- DEREF(s1);
- DEREF(s2);
- return dupnode(Nnull_string);
+ gmp_randseed(state, seed);
+ return res;
}