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