1 /*
2  * Copyright (C) 1987-2008 Sun Microsystems, Inc. All Rights Reserved.
3  * Copyright (C) 2008-2011 Robert Ancell
4  *
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 2 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <math.h>
17 #include <langinfo.h>
18 
19 #include "mp.h"
20 
21 void
mp_set_from_mp(const MPNumber * x,MPNumber * z)22 mp_set_from_mp(const MPNumber *x, MPNumber *z)
23 {
24     mpc_set(z->num, x->num, MPC_RNDNN);
25 }
26 
27 
28 void
mp_set_from_double(double dx,MPNumber * z)29 mp_set_from_double(double dx, MPNumber *z)
30 {
31     mpc_set_d(z->num, dx, MPC_RNDNN);
32 }
33 
34 
35 void
mp_set_from_integer(long x,MPNumber * z)36 mp_set_from_integer(long x, MPNumber *z)
37 {
38     mpc_set_si(z->num, x, MPC_RNDNN);
39 }
40 
41 
42 void
mp_set_from_unsigned_integer(unsigned long x,MPNumber * z)43 mp_set_from_unsigned_integer(unsigned long x, MPNumber *z)
44 {
45     mpc_set_ui(z->num, x, MPC_RNDNN);
46 }
47 
48 
49 void
mp_set_from_fraction(long numerator,long denominator,MPNumber * z)50 mp_set_from_fraction(long numerator, long denominator, MPNumber *z)
51 {
52     if (denominator < 0) {
53         numerator = -numerator;
54         denominator = -denominator;
55     }
56 
57     mp_set_from_integer(numerator, z);
58     if (denominator != 1)
59         mp_divide_integer(z, denominator, z);
60 }
61 
62 
63 void
mp_set_from_polar(const MPNumber * r,MPAngleUnit unit,const MPNumber * theta,MPNumber * z)64 mp_set_from_polar(const MPNumber *r, MPAngleUnit unit, const MPNumber *theta, MPNumber *z)
65 {
66     MPNumber x = mp_new();
67     MPNumber y = mp_new();
68 
69     mp_cos(theta, unit, &x);
70     mp_multiply(&x, r, &x);
71     mp_sin(theta, unit, &y);
72     mp_multiply(&y, r, &y);
73     mp_set_from_complex(&x, &y, z);
74 
75     mp_clear(&x);
76     mp_clear(&y);
77 }
78 
79 void
mp_set_from_complex(const MPNumber * x,const MPNumber * y,MPNumber * z)80 mp_set_from_complex(const MPNumber *x, const MPNumber *y, MPNumber *z)
81 {
82     mpc_set_fr_fr(z->num, mpc_realref(x->num), mpc_realref(y->num), MPC_RNDNN);
83 }
84 
85 void
mp_set_from_random(MPNumber * z)86 mp_set_from_random(MPNumber *z)
87 {
88     mp_set_from_double(drand48(), z);
89 }
90 
91 long
mp_to_integer(const MPNumber * x)92 mp_to_integer(const MPNumber *x)
93 {
94     return mpfr_get_si(mpc_realref(x->num), MPFR_RNDN);
95 }
96 
97 
98 unsigned long
mp_to_unsigned_integer(const MPNumber * x)99 mp_to_unsigned_integer(const MPNumber *x)
100 {
101     return mpfr_get_ui(mpc_realref(x->num), MPFR_RNDN);
102 }
103 
104 float
mp_to_float(const MPNumber * x)105 mp_to_float(const MPNumber *x)
106 {
107     return mpfr_get_flt(mpc_realref(x->num), MPFR_RNDN);
108 }
109 
110 double
mp_to_double(const MPNumber * x)111 mp_to_double(const MPNumber *x)
112 {
113     return mpfr_get_d(mpc_realref(x->num), MPFR_RNDN);
114 }
115 
116 static int
char_val(char ** c,int base)117 char_val(char **c, int base)
118 {
119     int i, j, value;
120     size_t offset;
121     const char *digits[][10] = {{"٠", "١", "٢", "٣", "٤", "٥", "٦", "٧", "٨", "٩"},
122                                 {"〇", "〡", "〢", "〣", "〤", "〥", "〦", "〧", "〨", "〩"},
123                                 {"۰", "۱", "۲", "۳", "۴", "۵", "۶", "۷", "۸", "۹"},
124                                 {"߀", "߁", "߂", "߃", "߄", "߅", "߆", "߇", "߈", "߉"},
125                                 {"०", "१", "२", "३", "४", "५", "६", "७", "८", "९"},
126                                 {"০", "১", "২", "৩", "৪", "৫", "৬", "৭", "৮", "৯"},
127                                 {"੦", "੧", "੨", "੩", "੪", "੫", "੬", "੭", "੮", "੯"},
128                                 {"૦", "૧", "૨", "૩", "૪", "૫", "૬", "૭", "૮", "૯"},
129                                 {"୦", "୧", "୨", "୩", "୪", "୫", "୬", "୭", "୮", "୯"},
130                                 {"௦", "௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯"},
131                                 {"౦", "౧", "౨", "౩", "౪", "౫", "౬", "౭", "౮", "౯"},
132                                 {"೦", "೧", "೨", "೩", "೪", "೫", "೬", "೭", "೮", "೯"},
133                                 {"൦", "൧", "൨", "൩", "൪", "൫", "൬", "൭", "൮", "൯"},
134                                 {"๐", "๑", "๒", "๓", "๔", "๕", "๖", "๗", "๘", "๙"},
135                                 {"໐", "໑", "໒", "໓", "໔", "໕", "໖", "໗", "໘", "໙"},
136                                 {"༠", "༡", "༢", "༣", "༤", "༥", "༦", "༧", "༨", "༩"},
137                                 {"၀", "၁", "၂", "၃", "၄", "၅", "၆", "၇", "၈", "၉"},
138                                 {"႐", "႑", "႒", "႓", "႔", "႕", "႖", "႗", "႘", "႙"},
139                                 {"០", "១", "២", "៣", "៤", "៥", "៦", "៧", "៨", "៩"},
140                                 {"᠐", "᠑", "᠒", "᠓", "᠔", "᠕", "᠖", "᠗", "᠘", "᠙"},
141                                 {"᥆", "᥇", "᥈", "᥉", "᥊", "᥋", "᥌", "᥍", "᥎", "᥏"},
142                                 {"᧐", "᧑", "᧒", "᧓", "᧔", "᧕", "᧖", "᧗", "᧘", "᧙"},
143                                 {"᭐", "᭑", "᭒", "᭓", "᭔", "᭕", "᭖", "᭗", "᭘", "᭙"},
144                                 {"᮰", "᮱", "᮲", "᮳", "᮴", "᮵", "᮶", "᮷", "᮸", "᮹"},
145                                 {"᱀", "᱁", "᱂", "᱃", "᱄", "᱅", "᱆", "᱇", "᱈", "᱉"},
146                                 {"᱐", "᱑", "᱒", "᱓", "᱔", "᱕", "᱖", "᱗", "᱘", "᱙"},
147                                 {"꘠", "꘡", "꘢", "꘣", "꘤", "꘥", "꘦", "꘧", "꘨", "꘩"},
148                                 {"꣐", "꣑", "꣒", "꣓", "꣔", "꣕", "꣖", "꣗", "꣘", "꣙"},
149                                 {"꤀", "꤁", "꤂", "꤃", "꤄", "꤅", "꤆", "꤇", "꤈", "꤉"},
150                                 {"꩐", "꩑", "꩒", "꩓", "꩔", "꩕", "꩖", "꩗", "꩘", "꩙"},
151                                 {"��", "��", "��", "��", "��", "��", "��", "��", "��", "��"},
152                                 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
153 
154     if (**c >= '0' && **c <= '9') {
155         value = **c - '0';
156         offset = 1;
157     } else if (**c >= 'a' && **c <= 'f') {
158         value = **c - 'a' + 10;
159         offset = 1;
160     } else if (**c >= 'A' && **c <= 'F') {
161         value = **c - 'A' + 10;
162         offset = 1;
163     } else {
164         for (i = 0; digits[i][0]; i++) {
165             for (j = 0; j < 10; j++) {
166                 if (strncmp(*c, digits[i][j], strlen(digits[i][j])) == 0)
167                     break;
168             }
169             if (j != 10)
170                 break;
171         }
172         if (digits[i][0] == NULL)
173             return -1;
174         value = j;
175         offset = strlen(digits[i][j]);
176     }
177     if (value >= base)
178        return -1;
179 
180     *c += offset;
181 
182     return value;
183 }
184 
185 
186 static int
ends_with(const char * start,const char * end,const char * word)187 ends_with(const char *start, const char *end, const char *word)
188 {
189     size_t word_len = strlen(word);
190 
191     if (word_len > end - start)
192         return 0;
193 
194     return strncmp(end - word_len, word, word_len) == 0;
195 }
196 
197 
198 // FIXME: Doesn't handle errors well (e.g. trailing space)
199 static bool
set_from_sexagesimal(const char * str,int length,MPNumber * z)200 set_from_sexagesimal(const char *str, int length, MPNumber *z)
201 {
202     int degrees = 0, minutes = 0;
203     char seconds[length+1];
204     int n_matched;
205 
206     seconds[0] = '\0';
207     n_matched = sscanf(str, "%d°%d'%s\"", &degrees, &minutes, seconds);
208 
209     if (n_matched < 1)
210         return true;
211     MPNumber t = mp_new();
212     mp_set_from_integer(degrees, z);
213     if (n_matched > 1) {
214         mp_set_from_integer(minutes, &t);
215         mp_divide_integer(&t, 60, &t);
216         mp_add(z, &t, z);
217     }
218     if (n_matched > 2) {
219         mp_set_from_string(seconds, 10, &t);
220         mp_divide_integer(&t, 3600, &t);
221         mp_add(z, &t, z);
222     }
223     mp_clear(&t);
224 
225     return false;
226 }
227 
228 
229 bool
mp_set_from_string(const char * str,int default_base,MPNumber * z)230 mp_set_from_string(const char *str, int default_base, MPNumber *z)
231 {
232     int i, base, negate = 0, multiplier = 0, base_multiplier = 1;
233     const char *c, *end;
234     gboolean has_fraction = FALSE;
235 
236     const char *base_digits[]   = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL};
237     const char *fractions[]     = {"½", "⅓", "⅔", "¼", "¾", "⅕", "⅖", "⅗", "⅘", "⅙", "⅚", "⅛", "⅜", "⅝", "⅞", NULL};
238     int numerators[]            = { 1,   1,   2,   1,   3,   1,   2,   3,   4,   1,   5,   1,   3,   5,   7};
239     int denominators[]          = { 2,   3,   3,   4,   4,   5,   5,   5,   5,   6,   6,   8,   8,   8,   8};
240 
241     if (strstr(str, "°"))
242         return set_from_sexagesimal(str, strlen(str), z);
243 
244     /* Find the base */
245     end = str;
246     while (*end != '\0')
247         end++;
248     base = 0;
249     while (1) {
250         for (i = 0; base_digits[i] != NULL; i++) {
251             if (ends_with(str, end, base_digits[i])) {
252                 base += i * base_multiplier;
253                 end -= strlen(base_digits[i]);
254                 base_multiplier *= 10;
255                 break;
256             }
257         }
258         if (base_digits[i] == NULL)
259             break;
260     }
261     if (base_multiplier == 1)
262         base = default_base;
263 
264     /* Check if this has a sign */
265     c = str;
266     if (*c == '+') {
267         c++;
268     } else if (*c == '-') {
269         negate = 1;
270         c++;
271     } else if (strncmp(c, "−", strlen("−")) == 0) {
272         negate = 1;
273         c += strlen("−");
274     }
275 
276     /* Convert integer part */
277     mp_set_from_integer(0, z);
278     while ((i = char_val((char **)&c, base)) >= 0) {
279         if (i > base)
280             return true;
281         mp_multiply_integer(z, base, z);
282         mp_add_integer(z, i, z);
283     }
284 
285     /* Look for fraction characters, e.g. ⅚ */
286     for (i = 0; fractions[i] != NULL; i++) {
287         if (ends_with(str, end, fractions[i])) {
288             end -= strlen(fractions[i]);
289             break;
290         }
291     }
292     if (fractions[i] != NULL) {
293         MPNumber fraction = mp_new();
294         mp_set_from_fraction(numerators[i], denominators[i], &fraction);
295         mp_add(z, &fraction, z);
296         mp_clear(&fraction);
297     }
298 
299     if (*c == '.') {
300         has_fraction = TRUE;
301         c++;
302     }
303 
304     /* Convert fractional part */
305     if (has_fraction) {
306         MPNumber numerator = mp_new();
307         MPNumber denominator = mp_new();
308 
309         mp_set_from_integer(0, &numerator);
310         mp_set_from_integer(1, &denominator);
311         while ((i = char_val((char **)&c, base)) >= 0) {
312             mp_multiply_integer(&denominator, base, &denominator);
313             mp_multiply_integer(&numerator, base, &numerator);
314             mp_add_integer(&numerator, i, &numerator);
315         }
316         mp_divide(&numerator, &denominator, &numerator);
317         mp_add(z, &numerator, z);
318         mp_clear(&numerator);
319         mp_clear(&denominator);
320     }
321 
322     if (c != end) {
323         return true;
324     }
325 
326     if (multiplier != 0) {
327         MPNumber t = mp_new();
328         mp_set_from_integer(10, &t);
329         mp_xpowy_integer(&t, multiplier, &t);
330         mp_multiply(z, &t, z);
331         mp_clear(&t);
332     }
333 
334     if (negate == 1)
335         mp_invert_sign(z, z);
336 
337     return false;
338 }
339