Blame src/get_x.c

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