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\"", °rees, &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