/* mpc_get_str -- Convert a complex number into a string.
Copyright (C) INRIA, 2009
This file is part of the MPC Library.
The MPC Library 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 2.1 of the License, or (at your
option) any later version.
The MPC Library 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 the MPC Library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA. */
#include <stdio.h> /* for sprintf, fprintf */
#include <ctype.h>
#include <string.h>
#include "mpc-impl.h"
/* Needs <locale.h> */
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
/* 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_RE (op), MPC_RND_RE (rnd));
imag_str = get_pretty_str (base, n, MPC_IM (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;
}