Mercurial > hg > xemacs-beta
annotate src/number-mp.c @ 5555:a39cd9dc92ba
Correct a typo from Mats' merge, process.el, thank you the byte-compiler
lisp/ChangeLog addition:
2011-08-24 Aidan Kehoe <kehoea@parhasard.net>
* process.el (shell-command-on-region):
Correct typo from the merge, nnot -> not.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Wed, 24 Aug 2011 11:22:30 +0100 |
parents | 2aa9cd456ae7 |
children | c9e5612f5424 |
rev | line source |
---|---|
1983 | 1 /* Numeric types for XEmacs using the MP library. |
2 Copyright (C) 2004 Jerry James. | |
3 | |
4 This file is part of XEmacs. | |
5 | |
5405
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
5231
diff
changeset
|
6 XEmacs is free software: you can redistribute it and/or modify it |
1983 | 7 under the terms of the GNU General Public License as published by the |
5405
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
5231
diff
changeset
|
8 Free Software Foundation, either version 3 of the License, or (at your |
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
5231
diff
changeset
|
9 option) any later version. |
1983 | 10 |
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 for more details. | |
15 | |
16 You should have received a copy of the GNU General Public License | |
5405
2aa9cd456ae7
Move src/ to GPLv3.
Mike Sperber <sperber@deinprogramm.de>
parents:
5231
diff
changeset
|
17 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
1983 | 18 |
19 /* Synched up with: Not in FSF. */ | |
20 | |
21 #include <config.h> | |
22 #include <limits.h> | |
23 #include <math.h> | |
24 #include "lisp.h" | |
25 | |
26 static MINT *bignum_bytesize, *bignum_long_sign_bit, *bignum_one, *bignum_two; | |
27 MINT *bignum_zero, *intern_bignum; | |
28 MINT *bignum_min_int, *bignum_max_int, *bignum_max_uint; | |
29 MINT *bignum_min_long, *bignum_max_long, *bignum_max_ulong; | |
30 short div_rem; | |
31 | |
32 char * | |
33 bignum_to_string (bignum b, int base) | |
34 { | |
35 REGISTER unsigned int i; | |
36 unsigned int bufsize = 128U, index = 0U; | |
37 int sign; | |
38 char *buffer = xnew_array (char, 128), *retval; | |
39 MINT *quo = MP_ITOM (0); | |
40 short rem; | |
41 | |
42 /* FIXME: signal something if base is < 2 or doesn't fit into a short. */ | |
43 | |
44 /* Save the sign for later */ | |
45 sign = MP_MCMP (b, bignum_zero); | |
46 | |
47 if (sign == 0) | |
48 { | |
49 XREALLOC_ARRAY (buffer, char, 2); | |
50 buffer[0] = '0'; | |
51 buffer[1] = '\0'; | |
52 return buffer; | |
53 } | |
54 /* Copy abs(b) into quo for destructive modification */ | |
55 else if (sign < 0) | |
56 MP_MSUB (bignum_zero, b, quo); | |
57 else | |
58 MP_MOVE (b, quo); | |
59 | |
60 quo = MP_ITOM (0); | |
61 | |
62 /* Loop over the digits of b (in BASE) and place each one into buffer */ | |
63 for (i = 0U; MP_MCMP(quo, bignum_zero) > 0; i++) | |
64 { | |
65 MP_SDIV (quo, base, quo, &rem); | |
66 if (index == bufsize) | |
67 { | |
68 bufsize <<= 1; | |
69 XREALLOC_ARRAY (buffer, char, bufsize); | |
70 } | |
71 buffer[index++] = rem < 10 ? rem + '0' : rem - 10 + 'a'; | |
72 } | |
73 MP_MFREE (quo); | |
74 | |
75 /* Reverse the digits, maybe add a minus sign, and add a null terminator */ | |
76 bufsize = index + (sign < 0 ? 1 : 0) + 1; | |
77 retval = xnew_array (char, bufsize); | |
78 if (sign < 0) | |
79 { | |
80 retval[0] = '-'; | |
81 i = 1; | |
82 } | |
83 else | |
84 i = 0; | |
85 for (; i < bufsize - 1; i++) | |
86 retval[i] = buffer[--index]; | |
87 retval[bufsize - 1] = '\0'; | |
4976
16112448d484
Rename xfree(FOO, TYPE) -> xfree(FOO)
Ben Wing <ben@xemacs.org>
parents:
4802
diff
changeset
|
88 xfree (buffer); |
1983 | 89 return retval; |
90 } | |
91 | |
92 #define BIGNUM_TO_TYPE(type,accumtype) do { \ | |
93 MP_MULT (b, quo, quo); \ | |
94 for (i = 0U; i < sizeof(type); i++) \ | |
95 { \ | |
96 MP_SDIV (quo, 256, quo, &rem); \ | |
97 retval |= ((accumtype) rem) << (8 * i); \ | |
98 } \ | |
99 MP_MFREE (quo); \ | |
100 } while (0) | |
101 | |
102 int | |
103 bignum_to_int (bignum b) | |
104 { | |
105 short rem, sign; | |
106 unsigned int retval = 0; | |
107 REGISTER unsigned int i; | |
108 MINT *quo; | |
109 | |
110 sign = MP_MCMP (b, bignum_zero) < 0 ? -1 : 1; | |
111 quo = MP_ITOM (sign); | |
112 BIGNUM_TO_TYPE (int, unsigned int); | |
113 return ((int) retval) * sign; | |
114 } | |
115 | |
116 unsigned int | |
117 bignum_to_uint (bignum b) | |
118 { | |
119 short rem; | |
120 unsigned int retval = 0U; | |
121 REGISTER unsigned int i; | |
122 MINT *quo; | |
123 | |
124 quo = MP_ITOM (MP_MCMP (b, bignum_zero) < 0 ? -1 : 1); | |
125 BIGNUM_TO_TYPE (unsigned int, unsigned int); | |
126 return retval; | |
127 } | |
128 | |
129 long | |
130 bignum_to_long (bignum b) | |
131 { | |
132 short rem, sign; | |
133 unsigned long retval = 0L; | |
134 REGISTER unsigned int i; | |
135 MINT *quo; | |
136 | |
137 sign = MP_MCMP (b, bignum_zero) < 0 ? -1 : 1; | |
138 quo = MP_ITOM (sign); | |
139 BIGNUM_TO_TYPE (long, unsigned long); | |
140 return ((long) retval) * sign; | |
141 } | |
142 | |
143 unsigned long | |
144 bignum_to_ulong (bignum b) | |
145 { | |
146 short rem; | |
147 unsigned long retval = 0UL; | |
148 REGISTER unsigned int i; | |
149 MINT *quo; | |
150 | |
151 quo = MP_ITOM (MP_MCMP (b, bignum_zero) < 0 ? -1 : 1); | |
152 BIGNUM_TO_TYPE (unsigned long, unsigned long); | |
153 return retval; | |
154 } | |
155 | |
156 double | |
157 bignum_to_double (bignum b) | |
158 { | |
159 short rem, sign; | |
1990 | 160 double retval = 0.0, factor = 1.0; |
1983 | 161 REGISTER unsigned int i; |
162 MINT *quo; | |
163 | |
164 sign = MP_MCMP (b, bignum_zero) < 0 ? -1 : 1; | |
165 quo = MP_ITOM (sign); | |
166 MP_MULT (b, quo, quo); | |
1990 | 167 for (i = 0U; MP_MCMP (quo, bignum_zero) > 0; i++) |
1983 | 168 { |
169 MP_SDIV (quo, 256, quo, &rem); | |
1990 | 170 retval += rem * factor; |
171 factor *= 256.0; | |
1983 | 172 } |
173 MP_MFREE (quo); | |
174 return retval * sign; | |
175 } | |
176 | |
177 static short | |
178 char_to_number (char c) | |
179 { | |
180 if (c >= '0' && c <= '9') | |
181 return c - '0'; | |
182 if (c >= 'a' && c <= 'z') | |
183 return c - 'a' + 10; | |
184 if (c >= 'A' && c <= 'Z') | |
185 return c - 'A' + 10; | |
186 return -1; | |
187 } | |
188 | |
189 int | |
190 bignum_set_string (bignum b, const char *s, int base) | |
191 { | |
192 MINT *mbase; | |
193 short digit; | |
1993 | 194 int neg = 0; |
1983 | 195 |
196 if (base == 0) | |
197 { | |
198 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) | |
199 { | |
200 base = 16; | |
201 s += 2; | |
202 } | |
203 else if (*s == '0') | |
204 { | |
205 base = 8; | |
206 s++; | |
207 } | |
208 else | |
209 base = 10; | |
210 } | |
211 | |
212 /* FIXME: signal something if base is < 2 or doesn't fit into a short. */ | |
213 | |
1993 | 214 if (*s == '-') |
215 { | |
216 s++; | |
217 neg = 1; | |
218 } | |
219 | |
1983 | 220 mbase = MP_ITOM ((short) base); |
221 MP_MOVE (bignum_zero, b); | |
4802
2fc0e2f18322
Don't create any bignums before pdumping. Add bignum, ratio, and bigfloat
Jerry James <james@xemacs.org>
parents:
1993
diff
changeset
|
222 |
1983 | 223 for (digit = char_to_number (*s); digit >= 0 && digit < base; |
224 digit = char_to_number (*++s)) | |
225 { | |
226 MINT *temp; | |
227 | |
228 MP_MULT (b, mbase, b); | |
229 temp = MP_ITOM (digit); | |
230 MP_MADD (b, temp, b); | |
231 MP_MFREE (temp); | |
232 } | |
233 | |
1993 | 234 if (neg) |
235 MP_MSUB (bignum_zero, b, b); | |
236 | |
1983 | 237 return (digit >= 0) ? -1 : 0; |
238 } | |
239 | |
240 void | |
241 bignum_set_long (MINT *b, long l) | |
242 { | |
243 /* Negative l is hard, not least because -LONG_MIN == LONG_MIN. We pretend | |
244 that l is unsigned, then subtract off the amount equal to the sign bit. */ | |
245 bignum_set_ulong (b, (unsigned long) l); | |
246 if (l < 0L) | |
247 MP_MSUB (b, bignum_long_sign_bit, b); | |
248 } | |
249 | |
250 void | |
251 bignum_set_ulong (bignum b, unsigned long l) | |
252 { | |
253 REGISTER unsigned int i; | |
254 MINT *multiplier = MP_ITOM (1); | |
255 | |
256 MP_MOVE (bignum_zero, b); | |
257 for (i = 0UL; l > 0UL; l >>= 8, i++) | |
258 { | |
259 MINT *temp = MP_ITOM ((short) (l & 255)); | |
260 MP_MULT (multiplier, temp, temp); | |
261 MP_MADD (b, temp, b); | |
262 MP_MULT (multiplier, bignum_bytesize, multiplier); | |
263 MP_MFREE (temp); | |
264 } | |
265 MP_MFREE (multiplier); | |
266 } | |
267 | |
268 void | |
269 bignum_set_double (bignum b, double d) | |
270 { | |
271 REGISTER unsigned int i; | |
272 int negative = (d < 0) ? 1 : 0; | |
273 MINT *multiplier = MP_ITOM (1); | |
274 | |
275 MP_MOVE (bignum_zero, b); | |
276 if (negative) | |
277 d = -d; | |
278 for (i = 0UL; d > 0.0; d /= 256, i++) | |
279 { | |
280 MINT *temp = MP_ITOM ((short) fmod (d, 256.0)); | |
281 MP_MULT (multiplier, temp, temp); | |
282 MP_MADD (b, temp, b); | |
283 MP_MULT (multiplier, bignum_bytesize, multiplier); | |
284 MP_MFREE (temp); | |
285 } | |
286 MP_MFREE (multiplier); | |
287 if (negative) | |
288 MP_MSUB (bignum_zero, b, b); | |
289 } | |
290 | |
291 /* Return nonzero if b1 is exactly divisible by b2 */ | |
292 int | |
293 bignum_divisible_p (bignum b1, bignum b2) | |
294 { | |
295 int retval; | |
296 MINT *rem = MP_ITOM (0); | |
297 MP_MDIV (b1, b2, intern_bignum, rem); | |
298 retval = (MP_MCMP (rem, bignum_zero) == 0); | |
299 MP_MFREE (rem); | |
300 return retval; | |
301 } | |
302 | |
303 void bignum_ceil (bignum quotient, bignum N, bignum D) | |
304 { | |
305 MP_MDIV (N, D, quotient, intern_bignum); | |
306 if (MP_MCMP (intern_bignum, bignum_zero) > 0 && | |
307 MP_MCMP (quotient, bignum_zero) > 0) | |
308 MP_MADD (quotient, bignum_one, quotient); | |
309 } | |
310 | |
311 void bignum_floor (bignum quotient, bignum N, bignum D) | |
312 { | |
313 MP_MDIV (N, D, quotient, intern_bignum); | |
314 if (MP_MCMP (intern_bignum, bignum_zero) > 0 && | |
315 MP_MCMP (quotient, bignum_zero) < 0) | |
316 MP_MSUB (quotient, bignum_one, quotient); | |
317 } | |
318 | |
319 /* RESULT = N to the POWth power */ | |
320 void | |
321 bignum_pow (bignum result, bignum n, unsigned long pow) | |
322 { | |
323 MP_MOVE (bignum_one, result); | |
324 for ( ; pow > 0UL; pow--) | |
325 MP_MULT (result, n, result); | |
326 } | |
327 | |
328 /* lcm(b1,b2) = b1 * b2 / gcd(b1, b2) */ | |
329 void | |
330 bignum_lcm (bignum result, bignum b1, bignum b2) | |
331 { | |
332 MP_MULT (b1, b2, result); | |
333 MP_GCD (b1, b2, intern_bignum); | |
334 MP_MDIV (result, intern_bignum, result, intern_bignum); | |
335 } | |
336 | |
337 /* FIXME: We can't handle negative args, so right now we just make them | |
338 positive before doing anything else. How should we really handle negative | |
339 args? */ | |
340 #define bignum_bit_op(result, b1, b2, op) \ | |
341 REGISTER unsigned int i; \ | |
342 MINT *multiplier = MP_ITOM (1), *n1 = MP_ITOM (0), *n2 = MP_ITOM (0); \ | |
343 \ | |
344 if (MP_MCMP (bignum_zero, b1) > 0) \ | |
345 MP_MSUB (bignum_zero, b1, n1); \ | |
346 else \ | |
347 MP_MOVE (b1, n1); \ | |
348 if (MP_MCMP (bignum_zero, b2) > 0) \ | |
349 MP_MSUB (bignum_zero, b2, n2); \ | |
350 else \ | |
351 MP_MOVE (b2, n2); \ | |
352 \ | |
353 MP_MOVE (bignum_zero, result); \ | |
354 \ | |
355 for (i = 0UL; MP_MCMP (bignum_zero, n1) < 0 && \ | |
356 MP_MCMP (bignum_zero, n2) < 0; i++) \ | |
357 { \ | |
358 short byte1, byte2; \ | |
359 MINT *temp; \ | |
360 \ | |
361 MP_SDIV (n1, 256, n1, &byte1); \ | |
362 MP_SDIV (n2, 256, n2, &byte2); \ | |
363 temp = MP_ITOM (byte1 op byte2); \ | |
364 MP_MULT (multiplier, temp, temp); \ | |
365 MP_MADD (result, temp, result); \ | |
366 MP_MULT (multiplier, bignum_bytesize, multiplier); \ | |
367 MP_MFREE (temp); \ | |
368 } \ | |
369 MP_MFREE (n2); \ | |
370 MP_MFREE (n1); \ | |
371 MP_MFREE (multiplier) | |
372 | |
373 void | |
374 bignum_and (bignum result, bignum b1, bignum b2) | |
375 { | |
376 bignum_bit_op (result, b1, b2, &); | |
377 } | |
378 | |
379 void | |
380 bignum_ior (bignum result, bignum b1, bignum b2) | |
381 { | |
382 bignum_bit_op (result, b1, b2, |); | |
383 } | |
384 | |
385 void | |
386 bignum_xor (bignum result, bignum b1, bignum b2) | |
387 { | |
388 bignum_bit_op (result, b1, b2, ^); | |
389 } | |
390 | |
391 /* NOT is not well-defined for bignums ... where do you stop flipping bits? | |
392 We just flip until we see the last one. This is probably a bad idea. */ | |
393 void | |
394 bignum_not (bignum result, bignum b) | |
395 { | |
396 REGISTER unsigned int i; | |
397 MINT *multiplier = MP_ITOM (1), *n = MP_ITOM (0); | |
398 | |
399 if (MP_MCMP (bignum_zero, b) > 0) | |
400 MP_MSUB (bignum_zero, b, n); | |
401 else | |
402 MP_MOVE (b, n); | |
403 | |
404 MP_MOVE (bignum_zero, result); | |
405 | |
406 for (i = 0UL; MP_MCMP (bignum_zero, n) < 0; i++) | |
407 { | |
408 short byte; | |
409 MINT *temp; | |
410 | |
411 MP_SDIV (n, 256, n, &byte); | |
412 temp = MP_ITOM (~byte); | |
413 MP_MULT (multiplier, temp, temp); | |
414 MP_MADD (result, temp, result); | |
415 MP_MULT (multiplier, bignum_bytesize, multiplier); | |
416 MP_MFREE (temp); | |
417 } | |
418 MP_MFREE (n); | |
419 MP_MFREE (multiplier); | |
420 } | |
421 | |
422 void | |
423 bignum_setbit (bignum b, unsigned long bit) | |
424 { | |
425 bignum_pow (intern_bignum, bignum_two, bit); | |
426 bignum_ior (b, b, intern_bignum); | |
427 } | |
428 | |
429 /* This is so evil, even I feel queasy. */ | |
430 void | |
431 bignum_clrbit (bignum b, unsigned long bit) | |
432 { | |
433 MINT *num = MP_ITOM (0); | |
434 | |
435 /* See if the bit is already set, and subtract it off if not */ | |
436 MP_MOVE (b, intern_bignum); | |
437 bignum_pow (num, bignum_two, bit); | |
438 bignum_ior (intern_bignum, intern_bignum, num); | |
439 if (MP_MCMP (b, intern_bignum) == 0) | |
440 MP_MSUB (b, num, b); | |
441 MP_MFREE (num); | |
442 } | |
443 | |
444 int | |
445 bignum_testbit (bignum b, unsigned long bit) | |
446 { | |
447 bignum_pow (intern_bignum, bignum_two, bit); | |
448 bignum_and (intern_bignum, b, intern_bignum); | |
449 return MP_MCMP (intern_bignum, bignum_zero); | |
450 } | |
451 | |
452 void | |
453 bignum_lshift (bignum result, bignum b, unsigned long bits) | |
454 { | |
455 bignum_pow (intern_bignum, bignum_two, bits); | |
456 MP_MULT (b, intern_bignum, result); | |
457 } | |
458 | |
459 void | |
460 bignum_rshift (bignum result, bignum b, unsigned long bits) | |
461 { | |
462 bignum_pow (intern_bignum, bignum_two, bits); | |
463 MP_MDIV (b, intern_bignum, result, intern_bignum); | |
464 } | |
465 | |
466 void bignum_random_seed(unsigned long seed) | |
467 { | |
468 /* FIXME: Implement me */ | |
469 } | |
470 | |
471 void bignum_random(bignum result, bignum limit) | |
472 { | |
473 /* FIXME: Implement me */ | |
474 MP_MOVE (bignum_zero, result); | |
475 } | |
476 | |
477 void | |
478 init_number_mp () | |
479 { | |
480 REGISTER unsigned int i; | |
481 | |
482 bignum_zero = MP_ITOM (0); | |
483 bignum_one = MP_ITOM (1); | |
484 bignum_two = MP_ITOM (2); | |
485 | |
486 /* intern_bignum holds throwaway values from macro expansions in | |
487 number-mp.h. Its value is immaterial. */ | |
488 intern_bignum = MP_ITOM (0); | |
489 | |
490 /* bignum_bytesize holds the number of bits in a byte. */ | |
491 bignum_bytesize = MP_ITOM (256); | |
492 | |
493 /* bignum_long_sign_bit holds an adjustment for negative longs. */ | |
494 bignum_long_sign_bit = MP_ITOM (256); | |
495 for (i = 1UL; i < sizeof (long); i++) | |
496 MP_MULT (bignum_bytesize, bignum_long_sign_bit, bignum_long_sign_bit); | |
497 | |
498 /* The MP interface only supports turning short ints into MINTs, so we have | |
499 to set these the hard way. */ | |
500 | |
501 bignum_min_int = MP_ITOM (0); | |
502 bignum_set_long (bignum_min_int, INT_MIN); | |
503 | |
504 bignum_max_int = MP_ITOM (0); | |
505 bignum_set_long (bignum_max_int, INT_MAX); | |
506 | |
507 bignum_max_uint = MP_ITOM (0); | |
508 bignum_set_ulong (bignum_max_uint, UINT_MAX); | |
509 | |
510 bignum_min_long = MP_ITOM (0); | |
511 bignum_set_long (bignum_min_long, LONG_MIN); | |
512 | |
513 bignum_max_long = MP_ITOM (0); | |
514 bignum_set_long (bignum_max_long, LONG_MAX); | |
515 | |
516 bignum_max_ulong = MP_ITOM (0); | |
517 bignum_set_ulong (bignum_max_ulong, ULONG_MAX); | |
518 } |