summaryrefslogtreecommitdiff
path: root/mpc/src/get_x.c
diff options
context:
space:
mode:
Diffstat (limited to 'mpc/src/get_x.c')
-rw-r--r--mpc/src/get_x.c236
1 files changed, 236 insertions, 0 deletions
diff --git a/mpc/src/get_x.c b/mpc/src/get_x.c
new file mode 100644
index 0000000000..31610ac61d
--- /dev/null
+++ b/mpc/src/get_x.c
@@ -0,0 +1,236 @@
+/* mpc_get_dc, mpc_get_ldc -- Transform mpc number into C complex number
+ mpc_get_str -- Convert a complex number into a string.
+
+Copyright (C) 2009, 2010, 2011 INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+
+#ifdef HAVE_COMPLEX_H
+#include <complex.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include <stdio.h> /* for sprintf, fprintf */
+#include <ctype.h>
+#include <string.h>
+#include "mpc-impl.h"
+
+#ifdef HAVE_COMPLEX_H
+double _Complex
+mpc_get_dc (mpc_srcptr op, mpc_rnd_t rnd) {
+ return I * mpfr_get_d (mpc_imagref (op), MPC_RND_IM (rnd))
+ + mpfr_get_d (mpc_realref (op), MPC_RND_RE (rnd));
+}
+
+long double _Complex
+mpc_get_ldc (mpc_srcptr op, mpc_rnd_t rnd) {
+ return I * mpfr_get_ld (mpc_imagref (op), MPC_RND_IM (rnd))
+ + mpfr_get_ld (mpc_realref (op), MPC_RND_RE (rnd));
+}
+#endif
+
+
+/* Code for mpc_get_str. The output format is "(real imag)", the decimal point
+ of the locale is used. */
+
+/* mpfr_prec_t can be either int or long int */
+#if (__GMP_MP_SIZE_T_INT == 1)
+#define MPC_EXP_FORMAT_SPEC "i"
+#elif (__GMP_MP_SIZE_T_INT == 0)
+#define MPC_EXP_FORMAT_SPEC "li"
+#else
+#error "mpfr_exp_t size not supported"
+#endif
+
+static char *
+pretty_zero (mpfr_srcptr zero)
+{
+ char *pretty;
+
+ pretty = mpc_alloc_str (3);
+
+ pretty[0] = mpfr_signbit (zero) ? '-' : '+';
+ pretty[1] = '0';
+ pretty[2] = '\0';
+
+ return pretty;
+}
+
+static char *
+prettify (const char *str, const mp_exp_t expo, int base, int special)
+{
+ size_t sz;
+ char *pretty;
+ char *p;
+ const char *s;
+ mp_exp_t x;
+ int sign;
+
+ sz = strlen (str) + 1; /* + terminal '\0' */
+
+ if (special)
+ {
+ /* special number: nan or inf */
+ pretty = mpc_alloc_str (sz);
+ strcpy (pretty, str);
+
+ return pretty;
+ }
+
+ /* regular number */
+
+ sign = (str[0] == '-' || str[0] == '+');
+
+ x = expo - 1; /* expo is the exponent value with decimal point BEFORE
+ the first digit, we wants decimal point AFTER the first
+ digit */
+ if (base == 16)
+ x <<= 2; /* the output exponent is a binary exponent */
+
+ ++sz; /* + decimal point */
+
+ if (x != 0)
+ {
+ /* augment sz with the size needed for an exponent written in base
+ ten */
+ mp_exp_t xx;
+
+ sz += 3; /* + exponent char + sign + 1 digit */
+
+ if (x < 0)
+ {
+ /* avoid overflow when changing sign (assuming that, for the
+ mp_exp_t type, (max value) is greater than (- min value / 10)) */
+ if (x < -10)
+ {
+ xx = - (x / 10);
+ sz++;
+ }
+ else
+ xx = -x;
+ }
+ else
+ xx = x;
+
+ /* compute sz += floor(log(expo)/log(10)) without using libm
+ functions */
+ while (xx > 9)
+ {
+ sz++;
+ xx /= 10;
+ }
+ }
+
+ pretty = mpc_alloc_str (sz);
+ p = pretty;
+
+ /* 1. optional sign plus first digit */
+ s = str;
+ *p++ = *s++;
+ if (sign)
+ *p++ = *s++;
+
+ /* 2. decimal point */
+#ifdef HAVE_LOCALECONV
+ *p++ = *localeconv ()->decimal_point;
+#else
+ *p++ = '.';
+#endif
+ *p = '\0';
+
+ /* 3. other significant digits */
+ strcat (pretty, s);
+
+ /* 4. exponent (in base ten) */
+ if (x == 0)
+ return pretty;
+
+ p = pretty + strlen (str) + 1;
+
+ switch (base)
+ {
+ case 10:
+ *p++ = 'e';
+ break;
+ case 2:
+ case 16:
+ *p++ = 'p';
+ break;
+ default:
+ *p++ = '@';
+ }
+
+ *p = '\0';
+
+ sprintf (p, "%+"MPC_EXP_FORMAT_SPEC, x);
+
+ return pretty;
+}
+
+static char *
+get_pretty_str (const int base, const size_t n, mpfr_srcptr x, mpfr_rnd_t rnd)
+{
+ mp_exp_t expo;
+ char *ugly;
+ char *pretty;
+
+ if (mpfr_zero_p (x))
+ return pretty_zero (x);
+
+ ugly = mpfr_get_str (NULL, &expo, base, n, x, rnd);
+ MPC_ASSERT (ugly != NULL);
+ pretty = prettify (ugly, expo, base, !mpfr_number_p (x));
+ mpfr_free_str (ugly);
+
+ return pretty;
+}
+
+char *
+mpc_get_str (int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd)
+{
+ size_t needed_size;
+ char *real_str;
+ char *imag_str;
+ char *complex_str = NULL;
+
+ if (base < 2 || base > 36)
+ return NULL;
+
+ real_str = get_pretty_str (base, n, mpc_realref (op), MPC_RND_RE (rnd));
+ imag_str = get_pretty_str (base, n, mpc_imagref (op), MPC_RND_IM (rnd));
+
+ needed_size = strlen (real_str) + strlen (imag_str) + 4;
+
+ complex_str = mpc_alloc_str (needed_size);
+MPC_ASSERT (complex_str != NULL);
+
+ strcpy (complex_str, "(");
+ strcat (complex_str, real_str);
+ strcat (complex_str, " ");
+ strcat (complex_str, imag_str);
+ strcat (complex_str, ")");
+
+ mpc_free_str (real_str);
+ mpc_free_str (imag_str);
+
+ return complex_str;
+}