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, 2020, 2022 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 #include <locale.h> 29 #include <stdio.h> /* for sprintf, fprintf */ 30 #include <ctype.h> 31 #include <string.h> 32 #include "mpc-impl.h" 33 34 #ifdef HAVE_COMPLEX_H 35 double _Complex 36 mpc_get_dc (mpc_srcptr op, mpc_rnd_t rnd) { 37 return I * mpfr_get_d (mpc_imagref (op), MPC_RND_IM (rnd)) 38 + mpfr_get_d (mpc_realref (op), MPC_RND_RE (rnd)); 39 } 40 41 long double _Complex 42 mpc_get_ldc (mpc_srcptr op, mpc_rnd_t rnd) { 43 return I * mpfr_get_ld (mpc_imagref (op), MPC_RND_IM (rnd)) 44 + mpfr_get_ld (mpc_realref (op), MPC_RND_RE (rnd)); 45 } 46 #endif 47 48 49 /* Code for mpc_get_str. The output format is "(real imag)", the decimal point 50 of the locale is used. */ 51 52 /* mpfr_prec_t can be either int or long int */ 53 #if (_MPFR_EXP_FORMAT == 2) 54 #define MPC_EXP_FORMAT_SPEC "i" 55 #elif (_MPFR_EXP_FORMAT == 3) 56 #define MPC_EXP_FORMAT_SPEC "li" 57 #else 58 #error "value of _MPFR_EXP_FORMAT not supported" 59 #endif 60 61 static char * 62 pretty_zero (mpfr_srcptr zero) 63 { 64 char *pretty; 65 66 pretty = mpc_alloc_str (3); 67 68 pretty[0] = mpfr_signbit (zero) ? '-' : '+'; 69 pretty[1] = '0'; 70 pretty[2] = '\0'; 71 72 return pretty; 73 } 74 75 static char * 76 prettify (const char *str, const mpfr_exp_t expo, int base, int special) 77 { 78 size_t sz; 79 char *pretty; 80 char *p; 81 const char *s; 82 mpfr_exp_t x; 83 int sign; 84 85 sz = strlen (str) + 1; /* + terminal '\0' */ 86 87 if (special) 88 { 89 /* special number: nan or inf */ 90 pretty = mpc_alloc_str (sz); 91 strcpy (pretty, str); 92 93 return pretty; 94 } 95 96 /* regular number */ 97 98 sign = (str[0] == '-' || str[0] == '+'); 99 100 x = expo - 1; /* expo is the exponent value with decimal point BEFORE 101 the first digit, we want decimal point AFTER the first 102 digit */ 103 if (base == 16) 104 x *= 4; /* the output exponent is a binary exponent */ 105 106 ++sz; /* + decimal point */ 107 108 if (x != 0) 109 { 110 /* augment sz with the size needed for an exponent written in base 111 ten */ 112 mpfr_exp_t xx; 113 114 sz += 3; /* + exponent char + sign + 1 digit */ 115 116 if (x < 0) 117 { 118 /* avoid overflow when changing sign (assuming that, for the 119 mpfr_exp_t type, (max value) is greater than (- min value / 10)) */ 120 if (x < -10) 121 { 122 xx = - (x / 10); 123 sz++; 124 } 125 else 126 xx = -x; 127 } 128 else 129 xx = x; 130 131 /* compute sz += floor(log(expo)/log(10)) without using libm 132 functions */ 133 while (xx > 9) 134 { 135 sz++; 136 xx /= 10; 137 } 138 } 139 140 pretty = mpc_alloc_str (sz); 141 p = pretty; 142 143 /* 1. optional sign plus first digit */ 144 s = str; 145 *p++ = *s++; 146 if (sign) 147 *p++ = *s++; 148 149 /* 2. decimal point */ 150 #ifdef HAVE_LOCALECONV 151 *p++ = *localeconv ()->decimal_point; 152 #else 153 *p++ = '.'; 154 #endif 155 *p = '\0'; 156 157 /* 3. other significant digits */ 158 strcat (pretty, s); 159 160 /* 4. exponent (in base ten) */ 161 if (x == 0) 162 return pretty; 163 164 p = pretty + strlen (str) + 1; 165 166 switch (base) 167 { 168 case 10: 169 *p++ = 'e'; 170 break; 171 case 2: 172 case 16: 173 *p++ = 'p'; 174 break; 175 default: 176 *p++ = '@'; 177 } 178 179 *p = '\0'; 180 181 sprintf (p, "%+" MPC_EXP_FORMAT_SPEC, x); 182 183 return pretty; 184 } 185 186 static char * 187 get_pretty_str (const int base, const size_t n, mpfr_srcptr x, mpfr_rnd_t rnd) 188 { 189 mpfr_exp_t expo; 190 char *ugly; 191 char *pretty; 192 193 if (mpfr_zero_p (x)) 194 return pretty_zero (x); 195 196 ugly = mpfr_get_str (NULL, &expo, base, n, x, rnd); 197 MPC_ASSERT (ugly != NULL); 198 pretty = prettify (ugly, expo, base, !mpfr_number_p (x)); 199 mpfr_free_str (ugly); 200 201 return pretty; 202 } 203 204 char * 205 mpc_get_str (int base, size_t n, mpc_srcptr op, mpc_rnd_t rnd) 206 { 207 size_t needed_size; 208 char *real_str; 209 char *imag_str; 210 char *complex_str = NULL; 211 212 if (base < 2 || base > 36) 213 return NULL; 214 215 real_str = get_pretty_str (base, n, mpc_realref (op), MPC_RND_RE (rnd)); 216 imag_str = get_pretty_str (base, n, mpc_imagref (op), MPC_RND_IM (rnd)); 217 218 needed_size = strlen (real_str) + strlen (imag_str) + 4; 219 220 complex_str = mpc_alloc_str (needed_size); 221 MPC_ASSERT (complex_str != NULL); 222 223 strcpy (complex_str, "("); 224 strcat (complex_str, real_str); 225 strcat (complex_str, " "); 226 strcat (complex_str, imag_str); 227 strcat (complex_str, ")"); 228 229 mpc_free_str (real_str); 230 mpc_free_str (imag_str); 231 232 return complex_str; 233 } 234