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