1 /*
2 Copyright (C) 2015 Fredrik Johansson
3
4 This file is part of Arb.
5
6 Arb is free software: you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version. See <http://www.gnu.org/licenses/>.
10 */
11
12 #include <string.h>
13 #include <ctype.h>
14 #include "arb.h"
15
16 static int
arb_set_float_str(arb_t res,const char * inp,slong prec)17 arb_set_float_str(arb_t res, const char * inp, slong prec)
18 {
19 char * emarker;
20 char * buf;
21 int error;
22 slong i;
23 fmpz_t exp;
24 fmpz_t man;
25 slong num_int, num_frac;
26 int after_radix;
27
28 if (inp[0] == '+')
29 {
30 return arb_set_float_str(res, inp + 1, prec);
31 }
32
33 if (inp[0] == '-')
34 {
35 error = arb_set_float_str(res, inp + 1, prec);
36 arb_neg(res, res);
37 return error;
38 }
39
40 if (strcmp(inp, "inf") == 0)
41 {
42 arb_pos_inf(res);
43 return 0;
44 }
45
46 if (strcmp(inp, "nan") == 0)
47 {
48 arb_indeterminate(res);
49 return 0;
50 }
51
52 error = 0;
53 fmpz_init(exp);
54 fmpz_init(man);
55 buf = flint_malloc(strlen(inp) + 1);
56
57 emarker = strchr(inp, 'e');
58
59 /* parse exponent (0 by default) */
60 if (emarker != NULL)
61 {
62 /* allow e+42 as well as e42 */
63 if (emarker[1] == '+')
64 {
65 if (!(emarker[2] >= '0' && emarker[2] <= '9'))
66 error = 1;
67 else
68 error = fmpz_set_str(exp, emarker + 2, 10);
69 }
70 else
71 error = fmpz_set_str(exp, emarker + 1, 10);
72
73 if (error)
74 goto cleanup;
75 }
76
77 /* parse floating-point part */
78 {
79 num_int = 0;
80 num_frac = 0;
81 after_radix = 0;
82
83 for (i = 0; inp + i != emarker && inp[i] != '\0'; i++)
84 {
85 if (inp[i] == '.' && !after_radix)
86 {
87 after_radix = 1;
88 }
89 else if (inp[i] >= '0' && inp[i] <= '9')
90 {
91 buf[num_int + num_frac] = inp[i];
92
93 num_frac += after_radix;
94 num_int += !after_radix;
95 }
96 else
97 {
98 error = 1;
99 goto cleanup;
100 }
101 }
102
103 buf[num_int + num_frac] = '\0';
104
105 /* put trailing zeros into the exponent */
106 while (num_int + num_frac > 1 && buf[num_int + num_frac - 1] == '0')
107 {
108 buf[num_int + num_frac - 1] = '\0';
109 num_frac--;
110 }
111
112 fmpz_sub_si(exp, exp, num_frac);
113
114 error = fmpz_set_str(man, buf, 10);
115 if (error)
116 goto cleanup;
117 }
118
119 if (fmpz_is_zero(man))
120 {
121 arb_zero(res);
122 }
123 else if (fmpz_is_zero(exp))
124 {
125 arb_set_round_fmpz(res, man, prec);
126 }
127 else
128 {
129 arb_t t;
130 arb_init(t);
131 arb_set_ui(t, 10);
132 arb_set_fmpz(res, man);
133
134 if (fmpz_sgn(exp) > 0)
135 {
136 arb_pow_fmpz_binexp(t, t, exp, prec + 4);
137 arb_mul(res, res, t, prec);
138 }
139 else
140 {
141 fmpz_neg(exp, exp);
142 arb_pow_fmpz_binexp(t, t, exp, prec + 4);
143 arb_div(res, res, t, prec);
144 }
145
146 arb_clear(t);
147 }
148
149 cleanup:
150 fmpz_clear(exp);
151 fmpz_clear(man);
152 flint_free(buf);
153
154 if (error)
155 arb_indeterminate(res);
156
157 return error;
158 }
159
160 int
arb_set_str(arb_t res,const char * inp,slong prec)161 arb_set_str(arb_t res, const char * inp, slong prec)
162 {
163 char * buf;
164 char * split;
165 char * first;
166 char * last;
167 slong i, len;
168 int error;
169
170 error = 0;
171 len = strlen(inp);
172 buf = flint_malloc(len + 1);
173
174 for (i = 0; i <= len; i++)
175 buf[i] = tolower(inp[i]);
176
177 split = strstr(buf, "+/-");
178
179 if (split == NULL)
180 {
181 /* strip whitespace and brackets */
182 first = buf;
183 while (isspace(first[0]) || first[0] == '[')
184 first++;
185 last = buf + len;
186 while (last - first > 0 && (isspace(last[-1]) || last[-1] == ']'))
187 last--;
188 last[0] = '\0';
189
190 error = arb_set_float_str(res, first, prec);
191 }
192 else
193 {
194 arb_t rad;
195 arb_init(rad);
196
197 /* strip whitespace and brackets */
198 first = buf;
199 while (isspace(first[0]) || first[0] == '[')
200 first++;
201 last = split;
202 while (last - first > 0 && (isspace(last[-1]) || last[-1] == ']'))
203 last--;
204 last[0] = '\0';
205
206 if (first == last)
207 arb_zero(res);
208 else
209 error = arb_set_float_str(res, first, prec);
210
211 if (!error)
212 {
213 /* strip whitespace and brackets */
214 first = split + 3;
215 while (isspace(first[0]) || first[0] == '[')
216 first++;
217 last = buf + len;
218 while (last - first > 0 && (isspace(last[-1]) || last[-1] == ']'))
219 last--;
220 last[0] = '\0';
221
222 error = arb_set_float_str(rad, first, prec);
223 arb_abs(rad, rad);
224 arb_add_error(res, rad);
225 }
226
227 arb_clear(rad);
228 }
229
230 flint_free(buf);
231 return error;
232 }
233
234