1 | /******************************************************************* |
---|
2 | * |
---|
3 | * MP version 1.1.2: Multi Protocol |
---|
4 | * Kent State University, Kent, OH |
---|
5 | * Authors: S. Gray, N. Kajler, P. Wang |
---|
6 | * (C) 1993, 1994, 1995, 1996, 1997 All Rights Reserved |
---|
7 | * |
---|
8 | * NOTICE |
---|
9 | * |
---|
10 | * Permission to use, copy, modify, and distribute this software and |
---|
11 | * its documentation for non-commercial purposes and without fee is |
---|
12 | * hereby granted provided that the above copyright notice appear in all |
---|
13 | * copies and that both the copyright notice and this permission notice |
---|
14 | * appear in supporting documentation. |
---|
15 | * |
---|
16 | * Neither Kent State University nor the Authors make any representations |
---|
17 | * about the suitability of this software for any purpose. The MP Library |
---|
18 | * is distributed in the hope that it will be useful, but is provided "as |
---|
19 | * is" and without any warranty of any kind and without even the implied |
---|
20 | * warranty of merchantability or fitness for a particular purpose. |
---|
21 | * |
---|
22 | * IMPORTANT ADDITION: as of September 2006, MP is also licenced under GPL |
---|
23 | * |
---|
24 | * IMPLEMENTATION FILE: MP_SacBigInt.c |
---|
25 | * |
---|
26 | * The default BigInt package is the Gnu Multiple Precision |
---|
27 | * package. Here we have the routines to put/get/print a SAC bigint |
---|
28 | * and to convert between the SAC and GMP bigints. |
---|
29 | * |
---|
30 | * NOTE: This is a short explanation of the the way MP deals with |
---|
31 | * arbtrary precision numbers. For now this really only applies |
---|
32 | * to Big Ints. When the sender and receiver are using the same |
---|
33 | * format, we don't want to force them to have to convert to a |
---|
34 | * common format to do the exchange. So we provide conversion |
---|
35 | * routines for some common formats (SAC <-> GMP, PARI <-> GMP). |
---|
36 | * The BigNum format to be used is characterized by routines to |
---|
37 | * Put(), Get(), and Print() these formats. The routines are |
---|
38 | * kept in a BigInt ops struct (see MP_Env.h). The user may |
---|
39 | * replace the default GMP ops in an MP env with those of some |
---|
40 | * other format by calling MP_SetEnvBigIntFormat() and sending |
---|
41 | * in the address of the struct containing the proper routines |
---|
42 | * and the "name" of the format to be used. It must be one of |
---|
43 | * the formats supported (as defined in MP_Types.h). |
---|
44 | * In any event, we want the sender to always have at least the |
---|
45 | * illusion that it is sending in its "native" format, so all |
---|
46 | * necessary conversions between representations are hidden in |
---|
47 | * supplied ops structs. See below for examples!!! Observe |
---|
48 | * that if SAC supported a straightforward conversion to string |
---|
49 | * routine, we wouldn't have to do all this messy convert to GMP |
---|
50 | * format first. For TCP connections, the two endpoints negotiate |
---|
51 | * which format to use. If both use the same format (GMP or other- |
---|
52 | * wise) then transmission should be "optimal". But if they use |
---|
53 | * different formats, the non-GMP side (may be both sides), must |
---|
54 | * do conversions. For other transport devices (e.g., files, |
---|
55 | * PVM, ToolBus), there is no negotiation. There is no miracle |
---|
56 | * here, the programmer must be aware of the needs of the other |
---|
57 | * applications involved and know if they all support the same |
---|
58 | * format, setting the environment accordingly. |
---|
59 | * --> BTW: This approach is consistent with and similar to how |
---|
60 | * we deal with new transport devices. |
---|
61 | * |
---|
62 | * Change Log: |
---|
63 | * 4/22/96 sgray Life begins for this file. |
---|
64 | * 4/23/96 sgray Completed and tested. Seems okay. :-) |
---|
65 | * |
---|
66 | ************************************************************************/ |
---|
67 | |
---|
68 | #ifndef lint |
---|
69 | static char vcid[] = "@(#) $Id$"; |
---|
70 | #endif /* lint */ |
---|
71 | |
---|
72 | #include "MP.h" |
---|
73 | |
---|
74 | #ifdef MP_HAVE_SAC |
---|
75 | |
---|
76 | /*#define MP_DEBUG */ |
---|
77 | |
---|
78 | MP_BigIntOps_t imp_sac_bigint_ops = { |
---|
79 | IMP_PutSacBigInt, |
---|
80 | IMP_GetSacBigInt, |
---|
81 | IMP_SacBigIntToStr, |
---|
82 | IMP_SacBigIntAsciiSize |
---|
83 | }; |
---|
84 | |
---|
85 | #if MP_DEFAULT_APINT_FORMAT == MP_SAC |
---|
86 | MP_BigIntOps_t imp_default_bigint_ops = { |
---|
87 | IMP_PutSacBigInt, |
---|
88 | IMP_GetSacBigInt, |
---|
89 | IMP_SacBigIntToStr, |
---|
90 | IMP_SacBigIntAsciiSize |
---|
91 | }; |
---|
92 | MP_BigNumFormat_t imp_default_bigint_format = MP_SAC; |
---|
93 | #endif |
---|
94 | |
---|
95 | |
---|
96 | /* |
---|
97 | * macro to determine if the GMP bignum is negative |
---|
98 | */ |
---|
99 | #define mpz_is_neg(mp_int) ((mp_int->_mp_size < 0)) |
---|
100 | |
---|
101 | |
---|
102 | /* |
---|
103 | * sac_to_gmp() assumes that the incoming integer really is a bignum and is |
---|
104 | * not representable as a machine precision integer. If the argument sac is |
---|
105 | * machine precision, the while loop becomes infinite (this is bad). |
---|
106 | * |
---|
107 | * On entry I also assume that the caller has initialized gmp_int. |
---|
108 | */ |
---|
109 | static void sac_to_gmp(mpz_ptr gmp_int, Word sac) |
---|
110 | { |
---|
111 | short set_neg_flag = -1; /* when set, this will be 0 or 1 */ |
---|
112 | MP_INT pwr, temp; |
---|
113 | Word lsac, d; |
---|
114 | #ifdef MP_DEBUG |
---|
115 | fprintf(stderr, "sac_to_gmp: entering, the bignum here is "); |
---|
116 | IWRITE(sac);printf("\n"); fflush(stderr); |
---|
117 | #endif |
---|
118 | |
---|
119 | if (ISATOM(sac)) { |
---|
120 | if (sac < 0) { |
---|
121 | set_neg_flag = 1; |
---|
122 | sac = -sac; |
---|
123 | } |
---|
124 | else set_neg_flag = 0; |
---|
125 | mpz_set_si(gmp_int, (int) sac); |
---|
126 | if (set_neg_flag) mpz_neg(gmp_int, gmp_int); |
---|
127 | return; |
---|
128 | } |
---|
129 | ADV(sac, &d, &lsac); |
---|
130 | mpz_init(&pwr); mpz_set_si(&pwr, 1); |
---|
131 | |
---|
132 | if (d != 0) { |
---|
133 | set_neg_flag = (d < 0) ? 1 : 0; |
---|
134 | if (set_neg_flag) d = -d; |
---|
135 | } |
---|
136 | |
---|
137 | mpz_set_si(gmp_int, d); |
---|
138 | mpz_init(&temp); |
---|
139 | while (!ISNIL(lsac)) { |
---|
140 | mpz_mul_ui(&pwr, &pwr, BETA); |
---|
141 | ADV(lsac, &d, &lsac); |
---|
142 | if (d != 0) { |
---|
143 | mpz_clear(&temp); |
---|
144 | /* Argh!! We need to keep checking because we may have |
---|
145 | had all leading zeroes to this point! */ |
---|
146 | if (set_neg_flag == -1) set_neg_flag = (d < 0) ? 1 : 0; |
---|
147 | if (set_neg_flag) d = -d; |
---|
148 | mpz_mul_ui(&temp, &pwr, d); |
---|
149 | mpz_add(gmp_int, gmp_int, &temp); |
---|
150 | } |
---|
151 | } |
---|
152 | if (set_neg_flag) mpz_neg(gmp_int, gmp_int); |
---|
153 | |
---|
154 | #ifdef MP_DEBUG |
---|
155 | fprintf(stderr,"sac_to_gmp: exiting\n");fflush(stderr); |
---|
156 | #endif |
---|
157 | return; |
---|
158 | } |
---|
159 | |
---|
160 | |
---|
161 | |
---|
162 | static void gmp_to_sac(Word *sac_int, mpz_ptr gmp_int) |
---|
163 | { |
---|
164 | MP_INT n, q, r; |
---|
165 | Word i = 0; |
---|
166 | long d; |
---|
167 | short set_neg_flag = mpz_is_neg(gmp_int); |
---|
168 | |
---|
169 | if (abs(gmp_int->_mp_size) == 1) { |
---|
170 | d = mpz_get_si(gmp_int); |
---|
171 | if (set_neg_flag && (d > 0)) d = -d; |
---|
172 | if (abs(d) < BETA) { |
---|
173 | *sac_int = d; |
---|
174 | return; |
---|
175 | } |
---|
176 | } |
---|
177 | mpz_init(&n); |
---|
178 | mpz_set(&n, gmp_int); |
---|
179 | mpz_init(&q); mpz_init(&r); |
---|
180 | if (set_neg_flag) n._mp_size = -n._mp_size; |
---|
181 | *sac_int = NIL; |
---|
182 | while (1) { |
---|
183 | d = mpz_fdiv_qr_ui(&q, &r, &n, BETA); |
---|
184 | if (set_neg_flag && (d > 0)) d = -d; |
---|
185 | *sac_int = LEINST(*sac_int, i, d); i++; |
---|
186 | d = mpz_cmp_si(&q, BETA); |
---|
187 | if (mpz_cmp_si(&q, BETA) < 0) |
---|
188 | break; |
---|
189 | mpz_clear(&n); |
---|
190 | mpz_set(&n, &q); |
---|
191 | } |
---|
192 | /* |
---|
193 | * now get the last value from q |
---|
194 | */ |
---|
195 | d = mpz_get_si(&q); |
---|
196 | if (set_neg_flag && (d > 0)) d = -d; |
---|
197 | *sac_int = LEINST(*sac_int, i, d); |
---|
198 | } |
---|
199 | |
---|
200 | |
---|
201 | |
---|
202 | /* Generic routine to recursively put a SAC list */ |
---|
203 | #ifdef __STDC__ |
---|
204 | int IMP_PutSacList(MP_Link_pt link, |
---|
205 | Word L) |
---|
206 | #else |
---|
207 | int IMP_PutSacList(link, L) |
---|
208 | MP_Link_pt link; |
---|
209 | Word L; |
---|
210 | #endif |
---|
211 | { |
---|
212 | #ifdef MP_DEBUG |
---|
213 | fprintf(stderr, "IMP_PutSacList: entering\n"); fflush(stderr); |
---|
214 | #endif |
---|
215 | |
---|
216 | if ( L == NIL || ISATOM(L) ) { /* Packing atom*/ |
---|
217 | if (MP_PutSint32Packet(link, L, 0) != MP_Success) |
---|
218 | return(-1); |
---|
219 | } |
---|
220 | else { /* Packing s-exp*/ |
---|
221 | if (MP_PutCommonOperatorPacket(link, MP_BasicDict, |
---|
222 | MP_CopBasicList, 0, 1) |
---|
223 | != MP_Success) |
---|
224 | return(-1); |
---|
225 | if (IMP_PutSacList(link, FIRST(L)) < 0 ) |
---|
226 | return(-1); |
---|
227 | if (IMP_PutSacList(link, RED(L)) < 0 ) |
---|
228 | return(-1); |
---|
229 | } |
---|
230 | |
---|
231 | #ifdef MP_DEBUG |
---|
232 | fprintf(stderr, "IMP_PutSacList: exiting\n"); fflush(stderr); |
---|
233 | #endif |
---|
234 | |
---|
235 | return(0); |
---|
236 | } |
---|
237 | |
---|
238 | |
---|
239 | |
---|
240 | #ifdef __STDC__ |
---|
241 | Word IMP_GetSacList(MP_Link_pt link) |
---|
242 | #else |
---|
243 | Word IMP_GetSacList(link) |
---|
244 | MP_Link_pt link; |
---|
245 | #endif |
---|
246 | { |
---|
247 | Word a, b; |
---|
248 | MP_NodeType_t ntype; |
---|
249 | MP_NumAnnot_t na; |
---|
250 | MP_NumChild_t nc; |
---|
251 | MP_DictTag_t dtag; |
---|
252 | MP_Common_t cv; |
---|
253 | #ifdef MP_DEBUG |
---|
254 | fprintf(stderr, "IMP_GetSacList: entering\n");fflush(stderr); |
---|
255 | #endif |
---|
256 | |
---|
257 | if (IMP_GetNodeHeader(link, &ntype, |
---|
258 | &dtag, &cv, &na, &nc) != MP_Success){ |
---|
259 | MP_PrintError(link); |
---|
260 | return(-1); |
---|
261 | } |
---|
262 | if (ntype == MP_Sint32Type) { /* Unpack atom */ |
---|
263 | if (IMP_GetSint32(link, (MP_Sint32_t *) &a) != MP_Success) { |
---|
264 | MP_PrintError(link); |
---|
265 | return -1; |
---|
266 | } |
---|
267 | return(a); |
---|
268 | } |
---|
269 | else if (ntype == MP_CommonOperatorType && dtag == MP_BasicDict && |
---|
270 | cv == MP_CopBasicList) { |
---|
271 | /* Unpack s-exp */ |
---|
272 | a = IMP_GetSacList(link); |
---|
273 | b = IMP_GetSacList(link); |
---|
274 | return(COMP(a,b)); |
---|
275 | } else { /* error */ |
---|
276 | fprintf(stderr, "IMP_GetSacList: invalid s-expression\n"); |
---|
277 | fflush(stderr); |
---|
278 | return -1; |
---|
279 | } |
---|
280 | } |
---|
281 | |
---|
282 | |
---|
283 | |
---|
284 | #ifdef __STDC__ |
---|
285 | MP_Status_t IMP_PutSacBigInt(MP_Link_pt link, MP_ApInt_t sac_int) |
---|
286 | #else |
---|
287 | MP_Status_t IMP_PutSacBigInt(link, sac_int) |
---|
288 | MP_Link_pt link; |
---|
289 | MP_ApInt_t sac_int; |
---|
290 | #endif |
---|
291 | { |
---|
292 | Word n = *((Word *)sac_int); |
---|
293 | MP_INT gmp_int; |
---|
294 | #ifdef MP_DEBUG |
---|
295 | fprintf(stderr, "IMP_PutSacBigInt: entering, n is \n");fflush(stderr); |
---|
296 | IWRITE (n); printf("\n"); fflush(stdout); |
---|
297 | #endif |
---|
298 | |
---|
299 | if (link->link_bigint_format == MP_SAC) |
---|
300 | return(IMP_PutSacList(link, n)); |
---|
301 | else { |
---|
302 | mpz_init(&gmp_int); |
---|
303 | sac_to_gmp(&gmp_int, n); |
---|
304 | ERR_CHK(IMP_PutGmpInt(link, (MP_ApInt_t)&gmp_int)); |
---|
305 | mpz_clear(&gmp_int); /* sloppy, we don't cleanup on failure */ |
---|
306 | } |
---|
307 | RETURN_OK(link); |
---|
308 | } |
---|
309 | |
---|
310 | |
---|
311 | |
---|
312 | |
---|
313 | #ifdef __STDC__ |
---|
314 | MP_Status_t IMP_GetSacBigInt(MP_Link_pt link, MP_ApInt_pt sac_int) |
---|
315 | #else |
---|
316 | MP_Status_t IMP_GetSacBigInt(link, sac_int) |
---|
317 | MP_Link_pt link; |
---|
318 | MP_ApInt_pt sac_int; |
---|
319 | #endif |
---|
320 | { |
---|
321 | mpz_ptr gmp_int = NULL; |
---|
322 | Word sac_tmp = 0, *sacptr; |
---|
323 | |
---|
324 | #ifdef MP_DEBUG |
---|
325 | fprintf(stderr,"IMP_GetSacBigInt: entering\n"); |
---|
326 | fprintf(stderr, "\tbigint_format is %d\n", link->link_bigint_format); |
---|
327 | fflush(stderr); |
---|
328 | #endif |
---|
329 | |
---|
330 | |
---|
331 | if (link->link_bigint_format == MP_SAC) { |
---|
332 | sacptr = (Word *)*sac_int; |
---|
333 | *sacptr = IMP_GetSacList(link); |
---|
334 | if (*sacptr == -1) |
---|
335 | return MP_Failure; |
---|
336 | else |
---|
337 | RETURN_OK(link); |
---|
338 | } else { |
---|
339 | ERR_CHK(IMP_GetGmpInt(link, (MP_ApInt_t *)&gmp_int)); |
---|
340 | /* gmp_to_sac((Word *)sac_int, gmp_int); */ |
---|
341 | gmp_to_sac((Word)*((Word *)sac_int), gmp_int); |
---|
342 | mpz_clear(gmp_int); /* sloppy, we don't cleanup on failure */ |
---|
343 | } |
---|
344 | |
---|
345 | #ifdef MP_DEBUG |
---|
346 | fprintf(stderr, "IMP_GetSacBigInt: returning\n");fflush(stderr); |
---|
347 | #endif |
---|
348 | |
---|
349 | RETURN_OK(link); |
---|
350 | } |
---|
351 | |
---|
352 | |
---|
353 | |
---|
354 | char * |
---|
355 | #ifdef __STDC__ |
---|
356 | IMP_SacBigIntToStr(MP_ApInt_t big_int, char *buffer) |
---|
357 | #else |
---|
358 | IMP_SacBigIntToStr(big_int, buffer) |
---|
359 | MP_ApInt_t big_int; |
---|
360 | char *buffer; |
---|
361 | #endif |
---|
362 | { |
---|
363 | MP_INT gmp_int; |
---|
364 | #ifdef MP_DEBUG |
---|
365 | fprintf(stderr,"IMP_SacBigIntToStr: entering.\n"); |
---|
366 | fflush(stderr); fprintf(stderr, "\tthe bignum is "); |
---|
367 | IWRITE(*(Word*)big_int);fprintf(stderr, "\n");fflush(stdout); |
---|
368 | #endif |
---|
369 | |
---|
370 | mpz_init(&gmp_int); |
---|
371 | sac_to_gmp(&gmp_int, *(Word*)big_int); |
---|
372 | mpz_get_str(buffer, 10, &gmp_int); |
---|
373 | mpz_clear(&gmp_int); |
---|
374 | |
---|
375 | #ifdef MP_DEBUG |
---|
376 | fprintf(stderr,"IMP_SacBigIntToStr: exiting\n");fflush(stderr); |
---|
377 | #endif |
---|
378 | |
---|
379 | return buffer; |
---|
380 | } |
---|
381 | |
---|
382 | |
---|
383 | #ifdef __STDC__ |
---|
384 | long IMP_SacBigIntAsciiSize(MP_ApInt_t mp_apint) |
---|
385 | #else |
---|
386 | long IMP_SacBigIntAsciiSize(mp_apint) |
---|
387 | MP_ApInt_t mp_apint; |
---|
388 | #endif |
---|
389 | { |
---|
390 | int len = 0; |
---|
391 | Word tmp = *((Word *)mp_apint); |
---|
392 | |
---|
393 | if (ISATOM(tmp)) return 9; |
---|
394 | |
---|
395 | len = LENGTH(tmp); |
---|
396 | return len * 9; |
---|
397 | } |
---|
398 | |
---|
399 | |
---|
400 | |
---|
401 | char * OLD_IMP_SacBigIntToStrOriginal(MP_Link_pt link, MP_ApInt_t big_int, |
---|
402 | int direction) |
---|
403 | { |
---|
404 | char *str = NULL; |
---|
405 | mpz_ptr gmp_int = NULL; |
---|
406 | |
---|
407 | |
---|
408 | fprintf(stderr,"IMP_SacBigIntToStr: entering\n"); |
---|
409 | if (direction == MP_SEND || |
---|
410 | link->link_bigint_format == MP_SAC) { |
---|
411 | fprintf(stderr,"\thave to convert - SAC format\n"); |
---|
412 | mpz_init(gmp_int); |
---|
413 | sac_to_gmp(gmp_int, *((Word *)big_int)); |
---|
414 | printf("\tdone conversion\n"); |
---|
415 | str = mpz_get_str(NULL, 10, gmp_int); |
---|
416 | printf("\thave the string, cleaning up\n"); |
---|
417 | mpz_clear(gmp_int); |
---|
418 | } else { /* must be receiving in GMP format */ |
---|
419 | fprintf(stderr,"\tdont' have to convert - GMP format\n"); |
---|
420 | str = mpz_get_str(NULL, 10, (mpz_ptr)big_int); |
---|
421 | } |
---|
422 | fprintf(stderr,"IMP_SacBigIntToStr: exiting\n");fflush(stderr); |
---|
423 | |
---|
424 | return str; |
---|
425 | } |
---|
426 | |
---|
427 | |
---|
428 | #endif /* MP_HAVE_SAC */ |
---|