Home | History | Annotate | Line # | Download | only in src
get_x.c revision 1.1.1.2
      1      1.1  mrg /* mpc_get_dc, mpc_get_ldc -- Transform mpc number into C complex number
      2      1.1  mrg    mpc_get_str -- Convert a complex number into a string.
      3      1.1  mrg 
      4  1.1.1.2  mrg Copyright (C) 2009, 2010, 2011, 2020 INRIA
      5      1.1  mrg 
      6      1.1  mrg This file is part of GNU MPC.
      7      1.1  mrg 
      8      1.1  mrg GNU MPC is free software; you can redistribute it and/or modify it under
      9      1.1  mrg the terms of the GNU Lesser General Public License as published by the
     10      1.1  mrg Free Software Foundation; either version 3 of the License, or (at your
     11      1.1  mrg option) any later version.
     12      1.1  mrg 
     13      1.1  mrg GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
     14      1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
     15      1.1  mrg FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
     16      1.1  mrg more details.
     17      1.1  mrg 
     18      1.1  mrg You should have received a copy of the GNU Lesser General Public License
     19      1.1  mrg along with this program. If not, see http://www.gnu.org/licenses/ .
     20      1.1  mrg */
     21      1.1  mrg 
     22      1.1  mrg #include "config.h"
     23      1.1  mrg 
     24      1.1  mrg #ifdef HAVE_COMPLEX_H
     25      1.1  mrg #include <complex.h>
     26      1.1  mrg #endif
     27      1.1  mrg 
     28      1.1  mrg #ifdef HAVE_LOCALE_H
     29      1.1  mrg #include <locale.h>
     30      1.1  mrg #endif
     31      1.1  mrg 
     32      1.1  mrg #include <stdio.h> /* for sprintf, fprintf */
     33      1.1  mrg #include <ctype.h>
     34      1.1  mrg #include <string.h>
     35      1.1  mrg #include "mpc-impl.h"
     36      1.1  mrg 
     37      1.1  mrg #ifdef HAVE_COMPLEX_H
     38      1.1  mrg double _Complex
     39      1.1  mrg mpc_get_dc (mpc_srcptr op, mpc_rnd_t rnd) {
     40      1.1  mrg    return I * mpfr_get_d (mpc_imagref (op), MPC_RND_IM (rnd))
     41      1.1  mrg           + mpfr_get_d (mpc_realref (op), MPC_RND_RE (rnd));
     42      1.1  mrg }
     43      1.1  mrg 
     44      1.1  mrg long double _Complex
     45      1.1  mrg mpc_get_ldc (mpc_srcptr op, mpc_rnd_t rnd) {
     46      1.1  mrg    return I * mpfr_get_ld (mpc_imagref (op), MPC_RND_IM (rnd))
     47      1.1  mrg           + mpfr_get_ld (mpc_realref (op), MPC_RND_RE (rnd));
     48      1.1  mrg }
     49      1.1  mrg #endif
     50      1.1  mrg 
     51      1.1  mrg 
     52      1.1  mrg /* Code for mpc_get_str. The output format is "(real imag)", the decimal point
     53      1.1  mrg    of the locale is used. */
     54      1.1  mrg 
     55      1.1  mrg /* mpfr_prec_t can be either int or long int */
     56  1.1.1.2  mrg #if (_MPFR_EXP_FORMAT == 2)
     57      1.1  mrg #define MPC_EXP_FORMAT_SPEC "i"
     58  1.1.1.2  mrg #elif (_MPFR_EXP_FORMAT == 3)
     59      1.1  mrg #define MPC_EXP_FORMAT_SPEC "li"
     60      1.1  mrg #else
     61  1.1.1.2  mrg #error "value of _MPFR_EXP_FORMAT not supported"
     62      1.1  mrg #endif
     63      1.1  mrg 
     64      1.1  mrg static char *
     65      1.1  mrg pretty_zero (mpfr_srcptr zero)
     66      1.1  mrg {
     67      1.1  mrg   char *pretty;
     68      1.1  mrg 
     69      1.1  mrg   pretty = mpc_alloc_str (3);
     70      1.1  mrg 
     71      1.1  mrg   pretty[0] = mpfr_signbit (zero) ? '-' : '+';
     72      1.1  mrg   pretty[1] = '0';
     73      1.1  mrg   pretty[2] = '\0';
     74      1.1  mrg 
     75      1.1  mrg   return pretty;
     76      1.1  mrg }
     77      1.1  mrg 
     78      1.1  mrg static char *
     79  1.1.1.2  mrg prettify (const char *str, const mpfr_exp_t expo, int base, int special)
     80      1.1  mrg {
     81      1.1  mrg   size_t sz;
     82      1.1  mrg   char *pretty;
     83      1.1  mrg   char *p;
     84      1.1  mrg   const char *s;
     85  1.1.1.2  mrg   mpfr_exp_t x;
     86      1.1  mrg   int sign;
     87      1.1  mrg 
     88      1.1  mrg   sz = strlen (str) + 1; /* + terminal '\0' */
     89      1.1  mrg 
     90      1.1  mrg   if (special)
     91      1.1  mrg     {
     92      1.1  mrg       /* special number: nan or inf */
     93      1.1  mrg       pretty = mpc_alloc_str (sz);
     94      1.1  mrg       strcpy (pretty, str);
     95      1.1  mrg 
     96      1.1  mrg       return pretty;
     97      1.1  mrg     }
     98      1.1  mrg 
     99      1.1  mrg   /* regular number */
    100      1.1  mrg 
    101      1.1  mrg   sign = (str[0] == '-' || str[0] == '+');
    102      1.1  mrg 
    103      1.1  mrg   x = expo - 1; /* expo is the exponent value with decimal point BEFORE
    104  1.1.1.2  mrg                    the first digit, we want decimal point AFTER the first
    105      1.1  mrg                    digit */
    106      1.1  mrg   if (base == 16)
    107  1.1.1.2  mrg     x *= 4; /* the output exponent is a binary exponent */
    108      1.1  mrg 
    109      1.1  mrg   ++sz; /* + decimal point */
    110      1.1  mrg 
    111      1.1  mrg   if (x != 0)
    112      1.1  mrg     {
    113      1.1  mrg       /* augment sz with the size needed for an exponent written in base
    114      1.1  mrg          ten */
    115  1.1.1.2  mrg       mpfr_exp_t xx;
    116      1.1  mrg 
    117      1.1  mrg       sz += 3; /* + exponent char + sign + 1 digit */
    118      1.1  mrg 
    119      1.1  mrg       if (x < 0)
    120      1.1  mrg         {
    121      1.1  mrg           /* avoid overflow when changing sign (assuming that, for the
    122  1.1.1.2  mrg              mpfr_exp_t type, (max value) is greater than (- min value / 10)) */
    123      1.1  mrg           if (x < -10)
    124      1.1  mrg             {
    125      1.1  mrg               xx = - (x / 10);
    126      1.1  mrg               sz++;
    127      1.1  mrg             }
    128      1.1  mrg           else
    129      1.1  mrg             xx = -x;
    130      1.1  mrg         }
    131      1.1  mrg       else
    132      1.1  mrg         xx = x;
    133      1.1  mrg 
    134      1.1  mrg       /* compute sz += floor(log(expo)/log(10)) without using libm
    135      1.1  mrg          functions */
    136      1.1  mrg       while (xx > 9)
    137      1.1  mrg         {
    138      1.1  mrg           sz++;
    139      1.1  mrg           xx /= 10;
    140      1.1  mrg         }
    141      1.1  mrg     }
    142      1.1  mrg 
    143      1.1  mrg   pretty = mpc_alloc_str (sz);
    144      1.1  mrg   p = pretty;
    145      1.1  mrg 
    146      1.1  mrg   /* 1. optional sign plus first digit */
    147      1.1  mrg   s = str;
    148      1.1  mrg   *p++ = *s++;
    149      1.1  mrg   if (sign)
    150      1.1  mrg     *p++ = *s++;
    151      1.1  mrg 
    152      1.1  mrg   /* 2. decimal point */
    153      1.1  mrg #ifdef HAVE_LOCALECONV
    154      1.1  mrg   *p++ = *localeconv ()->decimal_point;
    155      1.1  mrg #else
    156      1.1  mrg   *p++ = '.';
    157      1.1  mrg #endif
    158      1.1  mrg   *p = '\0';
    159      1.1  mrg 
    160      1.1  mrg   /* 3. other significant digits */
    161      1.1  mrg   strcat (pretty, s);
    162      1.1  mrg 
    163      1.1  mrg   /* 4. exponent (in base ten) */
    164      1.1  mrg   if (x == 0)
    165      1.1  mrg     return pretty;
    166      1.1  mrg 
    167      1.1  mrg   p = pretty + strlen (str) + 1;
    168      1.1  mrg 
    169      1.1  mrg   switch (base)
    170      1.1  mrg     {
    171      1.1  mrg     case 10:
    172      1.1  mrg       *p++ = 'e';
    173      1.1  mrg       break;
    174      1.1  mrg     case 2:
    175      1.1  mrg     case 16:
    176      1.1  mrg       *p++ = 'p';
    177      1.1  mrg       break;
    178      1.1  mrg     default:
    179      1.1  mrg       *p++ = '@';
    180      1.1  mrg     }
    181      1.1  mrg 
    182      1.1  mrg   *p = '\0';
    183      1.1  mrg 
    184      1.1  mrg   sprintf (p, "%+"MPC_EXP_FORMAT_SPEC, x);
    185      1.1  mrg 
    186      1.1  mrg   return pretty;
    187      1.1  mrg }
    188      1.1  mrg 
    189      1.1  mrg static char *
    190      1.1  mrg get_pretty_str (const int base, const size_t n, mpfr_srcptr x, mpfr_rnd_t rnd)
    191      1.1  mrg {
    192  1.1.1.2  mrg   mpfr_exp_t expo;
    193      1.1  mrg   char *ugly;
    194      1.1  mrg   char *pretty;
    195      1.1  mrg 
    196      1.1  mrg   if (mpfr_zero_p (x))
    197      1.1  mrg     return pretty_zero (x);
    198      1.1  mrg 
    199      1.1  mrg   ugly = mpfr_get_str (NULL, &expo, base, n, x, rnd);
    200      1.1  mrg   MPC_ASSERT (ugly != NULL);
    201      1.1  mrg   pretty = prettify (ugly, expo, base, !mpfr_number_p (x));
    202      1.1  mrg   mpfr_free_str (ugly);
    203      1.1  mrg 
    204      1.1  mrg   return pretty;
    205      1.1  mrg }
    206      1.1  mrg 
    207      1.1  mrg char *
    208      1.1  mrg mpc_get_str (int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd)
    209      1.1  mrg {
    210      1.1  mrg   size_t needed_size;
    211      1.1  mrg   char *real_str;
    212      1.1  mrg   char *imag_str;
    213      1.1  mrg   char *complex_str = NULL;
    214      1.1  mrg 
    215      1.1  mrg   if (base < 2 || base > 36)
    216      1.1  mrg     return NULL;
    217      1.1  mrg 
    218      1.1  mrg   real_str = get_pretty_str (base, n, mpc_realref (op), MPC_RND_RE (rnd));
    219      1.1  mrg   imag_str = get_pretty_str (base, n, mpc_imagref (op), MPC_RND_IM (rnd));
    220      1.1  mrg 
    221      1.1  mrg   needed_size = strlen (real_str) + strlen (imag_str) + 4;
    222      1.1  mrg 
    223      1.1  mrg   complex_str = mpc_alloc_str (needed_size);
    224      1.1  mrg MPC_ASSERT (complex_str != NULL);
    225      1.1  mrg 
    226      1.1  mrg   strcpy (complex_str, "(");
    227      1.1  mrg   strcat (complex_str, real_str);
    228      1.1  mrg   strcat (complex_str, " ");
    229      1.1  mrg   strcat (complex_str, imag_str);
    230      1.1  mrg   strcat (complex_str, ")");
    231      1.1  mrg 
    232      1.1  mrg   mpc_free_str (real_str);
    233      1.1  mrg   mpc_free_str (imag_str);
    234      1.1  mrg 
    235      1.1  mrg   return complex_str;
    236      1.1  mrg }
    237