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
mpc_get_dc(mpc_srcptr op,mpc_rnd_t rnd)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
mpc_get_ldc(mpc_srcptr op,mpc_rnd_t rnd)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 *
pretty_zero(mpfr_srcptr zero)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 *
prettify(const char * str,const mpfr_exp_t expo,int base,int special)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 *
get_pretty_str(const int base,const size_t n,mpfr_srcptr x,mpfr_rnd_t rnd)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 *
mpc_get_str(int base,size_t n,mpc_srcptr op,mpc_rnd_t rnd)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