Fix bug which failed to favour `x' when `y' wasn't wanted and the two
[u/mdw/catacomb] / mp.h
CommitLineData
d03ab969 1/* -*-c-*-
2 *
24e1e862 3 * $Id: mp.h,v 1.4 1999/11/21 22:13:02 mdw Exp $
d03ab969 4 *
d3409d5e 5 * Simple multiprecision arithmetic
d03ab969 6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: mp.h,v $
24e1e862 33 * Revision 1.4 1999/11/21 22:13:02 mdw
34 * Add mp version of MPX_BITS.
35 *
a790733d 36 * Revision 1.3 1999/11/19 13:19:14 mdw
37 * Fix const annotation.
38 *
d3409d5e 39 * Revision 1.2 1999/11/17 18:02:16 mdw
40 * New multiprecision integer arithmetic suite.
d03ab969 41 *
42 */
43
44#ifndef MP_H
45#define MP_H
46
47#ifdef __cplusplus
48 extern "C" {
49#endif
50
51/*----- Header files ------------------------------------------------------*/
52
d3409d5e 53#include <assert.h>
d03ab969 54#include <string.h>
55
d3409d5e 56#include <mLib/sub.h>
57
58#ifndef MPW_H
59# include "mpw.h"
d03ab969 60#endif
61
62#ifndef MPX_H
63# include "mpx.h"
64#endif
65
d03ab969 66/*----- Data structures ---------------------------------------------------*/
67
68typedef struct mp {
d3409d5e 69 mpw *v, *vl;
70 size_t sz;
71 unsigned f;
72 unsigned ref;
d03ab969 73} mp;
74
d3409d5e 75#define MP_NEG 1u
76#define MP_BURN 2u
77#define MP_CONST 4u
78#define MP_UNDEF 8u
d03ab969 79
d3409d5e 80/*----- Useful constants --------------------------------------------------*/
d03ab969 81
d3409d5e 82extern mp mp_const[];
d03ab969 83
d3409d5e 84#define MP_ZERO (&mp_const[0])
85#define MP_ONE (&mp_const[1])
86#define MP_TWO (&mp_const[2])
87#define MP_THREE (&mp_const[3])
88#define MP_FOUR (&mp_const[4])
89#define MP_FIVE (&mp_const[5])
90#define MP_TEN (&mp_const[6])
91#define MP_MONE (&mp_const[7])
d03ab969 92
d3409d5e 93#define MP_NEW ((mp *)0)
d03ab969 94
d3409d5e 95/*----- Memory allocation hooks -------------------------------------------*/
d03ab969 96
d3409d5e 97#ifndef MPARENA_H
98# include "mparena.h"
99#endif
100
101/* --- @MP_ARENA@ --- *
d03ab969 102 *
d3409d5e 103 * This selects where memory is allocated from. Tweak to use more fancy
104 * things like custom arenas.
105 */
106
107#ifndef MP_ARENA
108# define MP_ARENA MPARENA_GLOBAL
109#endif
110
111/* --- @MP_ALLOC@ --- *
d03ab969 112 *
d3409d5e 113 * Arguments: @size_t sz@ = size required
114 *
115 * Returns: Pointer to an allocated vector of the requested size.
d03ab969 116 *
d3409d5e 117 * Use: Hook for vector allocation.
d03ab969 118 */
119
d3409d5e 120#ifndef MP_ALLOC
121# define MP_ALLOC(sz) mpalloc(MP_ARENA, (sz))
122#endif
d03ab969 123
d3409d5e 124/* --- @MP_FREE@ --- *
125 *
126 * Arguments: @mpw *v@ = pointer to vector
d03ab969 127 *
d3409d5e 128 * Returns: ---
d03ab969 129 *
d3409d5e 130 * Use: Hook for vector deallocation.
d03ab969 131 */
132
d3409d5e 133#ifndef MP_FREE
134# define MP_FREE(v) mpfree(MP_ARENA, (v))
135#endif
d03ab969 136
d3409d5e 137/*----- Paranoia management -----------------------------------------------*/
138
139/* --- @mp_burn@ --- *
d03ab969 140 *
d3409d5e 141 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 142 *
143 * Returns: ---
144 *
d3409d5e 145 * Use: Marks the integer as `burn-after-use'. When the integer's
146 * memory is deallocated, it is deleted so that traces can't
147 * remain in the swap file. In theory.
d03ab969 148 */
149
d3409d5e 150extern void mp_burn(mp */*m*/);
d03ab969 151
d3409d5e 152/*----- Trivial macros ----------------------------------------------------*/
153
154/* --- @MP_LEN@ --- *
d03ab969 155 *
d3409d5e 156 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 157 *
d3409d5e 158 * Returns: Length of the integer, in words.
d03ab969 159 */
160
d3409d5e 161#define MP_LEN(m) ((m)->vl - ((m)->v))
d03ab969 162
d3409d5e 163/*----- Memory management and reference counting --------------------------*/
164
165/* --- @mp_create@ --- *
d03ab969 166 *
d3409d5e 167 * Arguments: @size_t sz@ = size of vector required
d03ab969 168 *
d3409d5e 169 * Returns: Pointer to pristine new MP structure with enough memory
170 * bolted onto it.
d03ab969 171 *
d3409d5e 172 * Use: Creates a new multiprecision integer with indeterminate
173 * contents. The integer has a single reference.
d03ab969 174 */
175
d3409d5e 176extern mp *mp_create(size_t /*sz*/);
d03ab969 177
d3409d5e 178/* --- @mp_build@ --- *
d03ab969 179 *
d3409d5e 180 * Arguments: @mp *m@ = pointer to an MP block to fill in
181 * @mpw *v@ = pointer to a word array
182 * @mpw *vl@ = pointer just past end of array
d03ab969 183 *
184 * Returns: ---
185 *
d3409d5e 186 * Use: Creates a multiprecision integer representing some smallish
187 * number. You must provide storage for the number and dispose
188 * of it when you've finished with it. The number is marked as
189 * constant while it exists.
d03ab969 190 */
191
d3409d5e 192extern void mp_build(mp */*m*/, mpw */*v*/, mpw */*vl*/);
d03ab969 193
d3409d5e 194/* --- @mp_destroy@ --- *
d03ab969 195 *
d3409d5e 196 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 197 *
198 * Returns: ---
199 *
d3409d5e 200 * Use: Destroys a multiprecision integer. The reference count isn't
201 * checked. Don't use this function if you don't know what
202 * you're doing: use @mp_drop@ instead.
d03ab969 203 */
204
d3409d5e 205extern void mp_destroy(mp */*m*/);
d03ab969 206
d3409d5e 207/* --- @mp_copy@ --- *
d03ab969 208 *
d3409d5e 209 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 210 *
d3409d5e 211 * Returns: A copy of the given multiprecision integer.
212 *
213 * Use: Copies the given integer. In fact you just get another
214 * reference to the same old one again.
d03ab969 215 */
216
d3409d5e 217extern mp *mp_copy(mp */*m*/);
d03ab969 218
d3409d5e 219#define MP_COPY(m) ((m)->ref++, (m))
220
221/* --- @mp_drop@ --- *
d03ab969 222 *
d3409d5e 223 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 224 *
225 * Returns: ---
226 *
d3409d5e 227 * Use: Drops a reference to an integer which isn't wanted any more.
228 * If there are no more references, the integer is destroyed.
d03ab969 229 */
230
d3409d5e 231extern void mp_drop(mp */*m*/);
d03ab969 232
d3409d5e 233#define MP_DROP(m) do { \
234 mp *_mm = (m); \
235 if (_mm->ref > 1) \
236 _mm->ref--; \
237 else if (!(_mm->f & MP_CONST)) \
238 mp_destroy(_mm); \
239} while (0)
240
241/* --- @mp_split@ --- *
d03ab969 242 *
d3409d5e 243 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 244 *
d3409d5e 245 * Returns: A reference to the same integer, possibly with a different
246 * address.
d03ab969 247 *
d3409d5e 248 * Use: Splits off a modifiable version of the integer referred to.
d03ab969 249 */
250
d3409d5e 251extern mp *mp_split(mp */*m*/);
252
253#define MP_SPLIT(m) do { \
254 mp *_mm = (m); \
255 if ((_mm->f & MP_CONST) || _mm->ref != 1) { \
256 mp *_dd = mp_create(_mm->sz); \
257 _dd->vl = _dd->v + MP_LEN(_mm); \
258 _dd->f = _mm->f & (MP_NEG | MP_BURN); \
259 memcpy(_dd->v, _mm->v, MPWS(MP_LEN(_mm))); \
260 _dd->ref = 1; \
261 _mm->ref--; \
262 (m) = _dd; \
263 } \
264} while (0)
d03ab969 265
d3409d5e 266/* --- @mp_resize@ --- *
d03ab969 267 *
d3409d5e 268 * Arguments: @mp *m@ = pointer to a multiprecision integer
269 * @size_t sz@ = new size
d03ab969 270 *
d3409d5e 271 * Returns: ---
d03ab969 272 *
d3409d5e 273 * Use: Resizes the vector containing the integer's digits. The new
274 * size must be at least as large as the current integer's
275 * length. The integer's length is increased and new digits are
276 * filled with zeroes. This isn't really intended for client
277 * use.
d03ab969 278 */
279
d3409d5e 280extern void mp_resize(mp */*m*/, size_t /*sz*/);
281
282#define MP_RESIZE(m, ssz) do { \
283 mp *_m = (m); \
284 size_t _sz = (ssz); \
285 size_t _len = MP_LEN(_m); \
286 mpw *_v = MP_ALLOC(_sz); \
287 memcpy(_v, _m->v, MPWS(_len)); \
288 if (_m->f & MP_BURN) \
289 memset(_m->v, 0, MPWS(_m->sz)); \
290 MP_FREE(_m->v); \
291 _m->v = _v; \
292 _m->vl = _v + _len; \
293 _m->sz = _sz; \
294} while (0)
d03ab969 295
d3409d5e 296/* --- @mp_ensure@ --- *
d03ab969 297 *
d3409d5e 298 * Arguments: @mp *m@ = pointer to a multiprecision integer
299 * @size_t sz@ = required size
d03ab969 300 *
301 * Returns: ---
302 *
d3409d5e 303 * Use: Ensures that the integer has enough space for @sz@ digits.
304 * The value is not changed.
d03ab969 305 */
306
d3409d5e 307extern void mp_ensure(mp */*m*/, size_t /*sz*/);
308
309#define MP_ENSURE(m, ssz) do { \
310 mp *_mm = (m); \
311 size_t _ssz = (ssz); \
312 size_t _len = MP_LEN(_mm); \
313 if (_ssz > _mm->sz) \
314 MP_RESIZE(_mm, _ssz); \
315 if (!(_mm->f & MP_UNDEF) && _ssz > _len) { \
316 memset(_mm->vl, 0, MPWS(_ssz - _len)); \
317 _mm->vl = _mm->v + _ssz; \
318 } \
319} while (0)
d03ab969 320
d3409d5e 321/* --- @mp_modify@ --- *
d03ab969 322 *
d3409d5e 323 * Arguments: @mp *m@ = pointer to a multiprecision integer
324 * @size_t sz@ = size required
d03ab969 325 *
d3409d5e 326 * Returns: Pointer to the integer (possibly different).
d03ab969 327 *
d3409d5e 328 * Use: Prepares an integer to be overwritten. It's split off from
329 * other references to the same integer, and sufficient space is
330 * allocated.
d03ab969 331 */
332
d3409d5e 333extern mp *mp_modify(mp */*m*/, size_t /*sz*/);
d03ab969 334
d3409d5e 335#define MP_MODIFY(m, sz) do { \
336 size_t _rq = (sz); \
337 mp *_m = (m); \
338 if (_m == MP_NEW) \
339 _m = mp_create(_rq); \
340 else { \
341 MP_SPLIT(_m); \
342 MP_ENSURE(_m, _rq); \
343 } \
344 _m->vl = _m->v + _rq; \
345 (m) = _m; \
346} while (0)
347
348/*----- Size manipulation -------------------------------------------------*/
349
350/* --- @mp_shrink@ --- *
d03ab969 351 *
d3409d5e 352 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 353 *
354 * Returns: ---
355 *
d3409d5e 356 * Use: Reduces the recorded length of an integer. This doesn't
357 * reduce the amount of memory used, although it can improve
358 * performance a bit. To reduce memory, use @mp_minimize@
359 * instead. This can't change the value of an integer, and is
360 * therefore safe to use even when there are multiple
361 * references.
d03ab969 362 */
363
d3409d5e 364extern void mp_shrink(mp */*m*/);
d03ab969 365
d3409d5e 366#define MP_SHRINK(m) do { \
367 mp *_mm = (m); \
368 MPX_SHRINK(_mm->v, _mm->vl); \
369 if (!MP_LEN(_mm)) \
370 _mm->f &= ~MP_NEG; \
371} while (0)
372
373/* --- @mp_minimize@ --- *
d03ab969 374 *
d3409d5e 375 * Arguments: @mp *m@ = pointer to a multiprecision integer
d03ab969 376 *
377 * Returns: ---
378 *
d3409d5e 379 * Use: Reduces the amount of memory an integer uses. It's best to
380 * do this to numbers which aren't going to change in the
381 * future.
d03ab969 382 */
383
d3409d5e 384extern void mp_minimize(mp */*m*/);
d03ab969 385
d3409d5e 386/*----- Bit scanning ------------------------------------------------------*/
d03ab969 387
d3409d5e 388#ifndef MPSCAN_H
389# include "mpscan.h"
390#endif
391
392/* --- @mp_scan@ --- *
d03ab969 393 *
d3409d5e 394 * Arguments: @mpscan *sc@ = pointer to bitscanner block
395 * @const mp *m@ = pointer to a multiprecision integer
d03ab969 396 *
397 * Returns: ---
398 *
d3409d5e 399 * Use: Initializes a bitscanner on a multiprecision integer.
d03ab969 400 */
401
d3409d5e 402extern void mp_scan(mpscan */*sc*/, const mp */*m*/);
403
404#define MP_SCAN(sc, m) do { \
a790733d 405 const mp *_mm = (m); \
d3409d5e 406 mpscan *_sc = (sc); \
407 MPSCAN_INITX(_sc, _mm->v, _mm->vl); \
408} while (0)
409
410/* --- Other bitscanning aliases --- */
411
412#define mp_step mpscan_step
413#define mp_bit mpscan_bit
414
415#define MP_STEP MPSCAN_STEP
416#define MP_BIT MPSCAN_BIT
417
418/*----- Loading and storing -----------------------------------------------*/
d03ab969 419
d3409d5e 420/* --- @mp_octets@ --- *
d03ab969 421 *
d3409d5e 422 * Arguments: @const mp *m@ = a multiprecision integer
d03ab969 423 *
d3409d5e 424 * Returns: The number of octets required to represent @m@.
d03ab969 425 *
d3409d5e 426 * Use: Calculates the external storage required for a multiprecision
427 * integer.
d03ab969 428 */
429
24e1e862 430extern size_t mp_octets(const mp */*m*/);
431
432/* --- @mp_bits@ --- *
433 *
434 * Arguments: @const mp *m@ = a multiprecision integer
435 *
436 * Returns: The number of bits required to represent @m@.
437 *
438 * Use: Calculates the external storage required for a multiprecision
439 * integer.
440 */
441
442extern unsigned long mp_bits(const mp */*m*/);
d03ab969 443
d3409d5e 444/* --- @mp_loadl@ --- *
d03ab969 445 *
d3409d5e 446 * Arguments: @mp *d@ = destination
447 * @const void *pv@ = pointer to source data
448 * @size_t sz@ = size of the source data
d03ab969 449 *
d3409d5e 450 * Returns: Resulting multiprecision number.
d03ab969 451 *
d3409d5e 452 * Use: Loads a multiprecision number from an array of octets. The
453 * first byte in the array is the least significant. More
454 * formally, if the bytes are %$b_0, b_1, \ldots, b_{n-1}$%
455 * then the result is %$N = \sum_{0 \le i < n} b_i 2^{8i}$%.
d03ab969 456 */
457
d3409d5e 458extern mp *mp_loadl(mp */*d*/, const void */*pv*/, size_t /*sz*/);
d03ab969 459
d3409d5e 460/* --- @mp_storel@ --- *
461 *
462 * Arguments: @const mp *m@ = source
463 * @void *pv@ = pointer to output array
464 * @size_t sz@ = size of the output array
465 *
466 * Returns: ---
467 *
468 * Use: Stores a multiprecision number in an array of octets. The
469 * first byte in the array is the least significant. If the
470 * array is too small to represent the number, high-order bits
471 * are truncated; if the array is too large, high order bytes
472 * are filled with zeros. More formally, if the number is
473 * %$N = \sum{0 \le i} b_i 2^{8i}$% where %$0 \le b_i < 256$%,
474 * then the array is %$b_0, b_1, \ldots, b_{n-1}$%.
475 */
d03ab969 476
d3409d5e 477extern void mp_storel(const mp */*m*/, void */*pv*/, size_t /*sz*/);
d03ab969 478
d3409d5e 479/* --- @mp_loadb@ --- *
d03ab969 480 *
d3409d5e 481 * Arguments: @mp *d@ = destination
482 * @const void *pv@ = pointer to source data
483 * @size_t sz@ = size of the source data
d03ab969 484 *
d3409d5e 485 * Returns: Resulting multiprecision number.
d03ab969 486 *
d3409d5e 487 * Use: Loads a multiprecision number from an array of octets. The
488 * last byte in the array is the least significant. More
489 * formally, if the bytes are %$b_{n-1}, b_{n-2}, \ldots, b_0$%
490 * then the result is %$N = \sum_{0 \le i < n} b_i 2^{8i}$%.
d03ab969 491 */
492
d3409d5e 493extern mp *mp_loadb(mp */*d*/, const void */*pv*/, size_t /*sz*/);
d03ab969 494
d3409d5e 495/* --- @mp_storeb@ --- *
d03ab969 496 *
d3409d5e 497 * Arguments: @const mp *m@ = source
498 * @void *pv@ = pointer to output array
499 * @size_t sz@ = size of the output array
d03ab969 500 *
501 * Returns: ---
502 *
d3409d5e 503 * Use: Stores a multiprecision number in an array of octets. The
504 * last byte in the array is the least significant. If the
505 * array is too small to represent the number, high-order bits
506 * are truncated; if the array is too large, high order bytes
507 * are filled with zeros. More formally, if the number is
508 * %$N = \sum{0 \le i} b_i 2^{8i}$% where %$0 \le b_i < 256$%,
509 * then the array is %$b_{n-1}, b_{n-2}, \ldots, b_0$%.
d03ab969 510 */
511
d3409d5e 512extern void mp_storeb(const mp */*m*/, void */*pv*/, size_t /*sz*/);
d03ab969 513
d3409d5e 514/*----- Simple arithmetic -------------------------------------------------*/
d03ab969 515
d3409d5e 516/* --- @mp_2c@ --- *
d03ab969 517 *
d3409d5e 518 * Arguments: @mp *d@ = destination
519 * @mp *a@ = source
d03ab969 520 *
d3409d5e 521 * Returns: Result, @a@ converted to two's complement notation.
522 */
523
524extern mp *mp_2c(mp */*d*/, mp */*a*/);
525
526/* --- @mp_sm@ --- *
527 *
528 * Arguments: @mp *d@ = destination
529 * @mp *a@ = source
d03ab969 530 *
d3409d5e 531 * Returns: Result, @a@ converted to the native signed-magnitude
532 * notation.
d03ab969 533 */
534
d3409d5e 535extern mp *mp_sm(mp */*d*/, mp */*a*/);
d03ab969 536
d3409d5e 537/* --- @mp_lsl@ --- *
d03ab969 538 *
d3409d5e 539 * Arguments: @mp *d@ = destination
540 * @const mp *a@ = source
541 * @size_t n@ = number of bits to move
d03ab969 542 *
d3409d5e 543 * Returns: Result, @a@ shifted left by @n@.
544 */
545
546extern mp *mp_lsl(mp */*d*/, const mp */*a*/, size_t /*n*/);
547
548/* --- @mp_lsr@ --- *
549 *
550 * Arguments: @mp *d@ = destination
551 * @const mp *a@ = source
552 * @size_t n@ = number of bits to move
d03ab969 553 *
d3409d5e 554 * Returns: Result, @a@ shifted left by @n@.
d03ab969 555 */
556
d3409d5e 557extern mp *mp_lsr(mp */*d*/, const mp */*a*/, size_t /*n*/);
d03ab969 558
d3409d5e 559/* --- @mp_cmp@ --- *
d03ab969 560 *
d3409d5e 561 * Arguments: @const mp *a, *b@ = two numbers
d03ab969 562 *
d3409d5e 563 * Returns: Less than, equal to or greater than zero, according to
564 * whether @a@ is less than, equal to or greater than @b@.
565 */
566
567extern int mp_cmp(const mp */*a*/, const mp */*b*/);
568
569#define MP_CMP(a, op, b) (mp_cmp((a), (b)) op 0)
570
571/* --- @mp_add@ --- *
d03ab969 572 *
d3409d5e 573 * Arguments: @mp *d@ = destination
574 * @const mp *a, *b@ = sources
575 *
576 * Returns: Result, @a@ added to @b@.
d03ab969 577 */
578
d3409d5e 579extern mp *mp_add(mp */*d*/, const mp */*a*/, const mp */*b*/);
d03ab969 580
d3409d5e 581/* --- @mp_sub@ --- *
582 *
583 * Arguments: @mp *d@ = destination
584 * @const mp *a, *b@ = sources
585 *
586 * Returns: Result, @b@ subtracted from @a@.
587 */
d03ab969 588
d3409d5e 589extern mp *mp_sub(mp */*d*/, const mp */*a*/, const mp */*b*/);
590
591/* --- @mp_mul@ --- *
d03ab969 592 *
d3409d5e 593 * Arguments: @mp *d@ = destination
594 * @const mp *a, *b@ = sources
d03ab969 595 *
d3409d5e 596 * Returns: Result, @a@ multiplied by @b@.
597 */
598
599extern mp *mp_mul(mp */*d*/, const mp */*a*/, const mp */*b*/);
600
601/* --- @mp_sqr@ --- *
602 *
603 * Arguments: @mp *d@ = destination
604 * @const mp *a@ = source
605 *
606 * Returns: Result, @a@ squared.
607 */
608
609extern mp *mp_sqr(mp */*d*/, const mp */*a*/);
610
611/* --- @mp_div@ --- *
d03ab969 612 *
d3409d5e 613 * Arguments: @mp **qq, **rr@ = destination, quotient and remainder
614 * @const mp *a, *b@ = sources
615 *
616 * Use: Calculates the quotient and remainder when @a@ is divided by
617 * @b@.
d03ab969 618 */
619
d3409d5e 620extern void mp_div(mp **/*qq*/, mp **/*rr*/,
621 const mp */*a*/, const mp */*b*/);
622
623/*----- More advanced algorithms ------------------------------------------*/
d03ab969 624
d3409d5e 625/* --- @mp_gcd@ --- *
d03ab969 626 *
d3409d5e 627 * Arguments: @mp **gcd, **xx, **yy@ = where to write the results
628 * @mp *a, *b@ = sources (must be nonzero)
d03ab969 629 *
630 * Returns: ---
631 *
d3409d5e 632 * Use: Calculates @gcd(a, b)@, and two numbers @x@ and @y@ such that
633 * @ax + by = gcd(a, b)@. This is useful for computing modular
634 * inverses. Neither @a@ nor @b@ may be zero. Note that,
635 * unlike @mp_div@ for example, it is not possible to specify
636 * explicit destinations -- new MPs are always allocated.
d03ab969 637 */
638
d3409d5e 639extern void mp_gcd(mp **/*gcd*/, mp **/*xx*/, mp **/*yy*/,
640 mp */*a*/, mp */*b*/);
641
642/*----- Test harness support ----------------------------------------------*/
643
644#include <mLib/testrig.h>
645
646#ifndef MPTEXT_H
647# include "mptext.h"
648#endif
649
650extern const test_type type_mp;
d03ab969 651
652/*----- That's all, folks -------------------------------------------------*/
653
654#ifdef __cplusplus
655 }
656#endif
657
658#endif