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