3 * $Id: mp.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
5 * Multiprecision arithmetic
7 * (c) 1998 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
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.
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.
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,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.1 1999/09/03 08:41:12 mdw
38 /*----- Header files ------------------------------------------------------*/
49 /*----- Important types ---------------------------------------------------*/
55 typedef unsigned short mpw
;
57 #define MPW_MAX 0xffffu
58 typedef unsigned int mpd
;
60 #define MPD_MAX 0xffffffffu
64 typedef unsigned long mpw
;
65 static unsigned mpw_bits
;
67 typedef unsigned long mpd
;
69 #define MPW_BITS mpw_bits
70 #define MPW_MAX mpw_max
74 /*----- Data structures ---------------------------------------------------*/
76 /*----- Some basic values which are important -----------------------------*/
78 static mpw mp__v
[] = { 1, 2, 3, 4, 5, 10 };
80 { 0, 0, 0, 0 }, /* 0 */
81 { mp__v
+ 0, 0, 0, 1 }, /* 1 */
82 { mp__v
+ 1, 0, 0, 1 }, /* 2 */
83 { mp__v
+ 2, 0, 0, 1 }, /* 3 */
84 { mp__v
+ 3, 0, 0, 1 }, /* 4 */
85 { mp__v
+ 4, 0, 0, 1 }, /* 5 */
86 { mp__v
+ 5, 0, 0, 1 }, /* 10 */
87 { mp__v
+ 0, MPF_SIGN
, 0, 1 } /* -1 */
90 /*----- Memory management -------------------------------------------------*/
92 /* --- @mp_create@ --- *
94 * Arguments @mp *x@ = pointer to MP head
98 * Use: Initializes an MP ready for use. The initial value is zero.
101 void mp_create(mp
*x
)
109 /* --- @mp_destroy@ --- *
111 * Arguments: @mp *x@ = pointer to MP head
115 * Use: Releases the memory used by an MP.
118 void mp_destroy(mp
*x
) { MP_DESTROY(x
); }
120 /* --- @mp_resize@ --- *
122 * Arguments: @mp *x@ = pointer to MP head
123 * @size_t sz@ = size required (in words)
127 * Use: Resizes the MP so that its word vector has space for
128 * exactly @sz@ words.
131 void mp_resize(mp
*x
, size_t sz
)
136 size_t min
= sz
> x
->sz ? x
->sz
: sz
;
137 mpw
*v
= xmalloc(sz
* sizeof(mpw
));
139 memcpy(v
, x
->v
, min
* sizeof(mpw
));
144 memset(v
+ min
, 0, (sz
- min
) * sizeof(mpw
));
150 /* --- @mp_norm@ --- *
152 * Arguments: @mp *x@ = pointer to MP head
156 * Use: `Normalizes' an MP. Fixes the @len@ field so that it's
157 * correct. Assumes that @len@ is either already correct or
161 void mp_norm(mp
*x
) { MP_NORM(x
); }
163 /* --- @mp_dump@ --- *
165 * Arguments: @mp *x@ = pointer to MP head
166 * @FILE *fp@ = pointer to stream to write on
170 * Use: Dumps an MP to a stream.
173 void mp_dump(mp
*x
, FILE *fp
)
176 mpw
*v
= x
->v
, *vl
= v
+ x
->len
;
178 fprintf(fp
, "%lx", (unsigned long)*v
++);
179 if (v
< vl
) fputc('-', fp
);
185 /* --- @mp_copy@ --- *
187 * Arguments: @mp *d@ = pointer to MP head for destination
188 * @const mp *s@ = pointer to MP head for source
195 void mp_copy(mp
*d
, const mp
*s
)
202 MP_ENSURE(d
, s
->len
);
203 memcpy(d
->v
, s
->v
, s
->len
* sizeof(mpw
));
204 if (d
->f
& MPF_BURN
&& d
->sz
> s
->len
)
205 memset(d
->v
+ s
->len
, 0, (d
->sz
- s
->len
) * sizeof(mpw
));
211 /* --- @mp_bits@ --- *
213 * Arguments: @mp *x@ = pointer to MP head
215 * Returns: Length of the number in bits.
217 * Use: Calculates the number of bits required to represent a number.
218 * The number must be normalized.
221 unsigned long mp_bits(mp
*x
)
226 unsigned long bits
= MPW_BITS
* (x
->len
- 1);
227 mpw w
= x
->v
[x
->len
- 1];
236 /* --- @mp_octets@ --- *
238 * Arguments: @mp *x@ = pointer to MP head
240 * Returns: Length of number in octets.
242 * Use: Calculates the number of octets required to represent a
243 * number. The number must be normalized.
246 size_t mp_octets(mp
*x
)
248 return ((mp_bits(x
) + 7) & 7);
251 /*----- Loading and storing as binary data --------------------------------*/
253 /* --- @mp_storel@ --- *
255 * Arguments: @mp *x@ = pointer to MP head
256 * @octet *p@ = pointer to octet array
257 * @size_t sz@ = size of octet array
261 * Use: Stores an MP in an octet array, least significant octet
262 * first. High-end octets are silently discarded if there
263 * isn't enough space for them.
266 void mp_storel(mp
*x
, octet
*p
, size_t sz
)
268 mpw
*v
= x
->v
, *vl
= x
->v
+ x
->len
;
275 n
= (v
>= vl
) ?
0 : *v
++;
276 *p
++ = (w
| n
<< bits
) & MASK8
;
278 bits
+= MPW_BITS
- 8;
287 /* --- @mp_loadl@ --- *
289 * Arguments: @mp *x@ = pointer to MP head
290 * @const octet *p@ = pointer to octet array
291 * @size_t sz@ = size of octet array
295 * Use: Loads an MP in an octet array, least significant octet
299 void mp_loadl(mp
*x
, const octet
*p
, size_t sz
)
304 const octet
*q
= p
+ sz
;
308 MP_ENSURE(x
, ((sz
* 8 + MPW_BITS
- 1) * MPW_BITS
) / MPW_BITS
);
315 if (bits
>= MPW_BITS
) {
317 w
= n
>> (MPW_BITS
- bits
+ 8);
327 /* --- @mp_storeb@ --- *
329 * Arguments: @mp *x@ = pointer to MP head
330 * @octet *p@ = pointer to octet array
331 * @size_t sz@ = size of octet array
335 * Use: Stores an MP in an octet array, most significant octet
336 * first. High-end octets are silently discarded if there
337 * isn't enough space for them.
340 void mp_storeb(mp
*x
, octet
*p
, size_t sz
)
342 mpw
*v
= x
->v
, *vl
= x
->v
+ x
->len
;
349 n
= (v
>= vl
) ?
0 : *v
++;
350 *--q
= (w
| n
<< bits
) & MASK8
;
352 bits
+= MPW_BITS
- 8;
361 /* --- @mp_loadb@ --- *
363 * Arguments: @mp *x@ = pointer to MP head
364 * @const octet *p@ = pointer to octet array
365 * @size_t sz@ = size of octet array
369 * Use: Loads an MP in an octet array, most significant octet
373 void mp_loadb(mp
*x
, const octet
*p
, size_t sz
)
378 const octet
*q
= p
+ sz
;
382 MP_ENSURE(x
, ((sz
* 8 + MPW_BITS
- 1) * MPW_BITS
) / MPW_BITS
);
389 if (bits
>= MPW_BITS
) {
391 w
= n
>> (MPW_BITS
- bits
+ 8);
401 /*----- Iterating through bits --------------------------------------------*/
403 /* --- @mp_mkbitscan@ --- *
405 * Arguments: @mp_bitscan *sc@ = pointer to bitscan object
406 * @const mp *x@ = pointer to MP head
410 * Use: Initializes a bitscan object.
413 void mp_mkbitscan(mp_bitscan
*sc
, const mp
*x
)
420 /* --- @mp_bstep@ --- *
422 * Arguments: @mp_bitscan *sc@ = pointer to bitscanner object
424 * Returns: Nonzero if there is another bit to read.
426 * Use: Steps on to the next bit, and tells the caller whether one
430 int mp_bstep(mp_bitscan
*sc
)
437 if (sc
->i
>= sc
->x
->len
)
439 sc
->w
= sc
->x
->v
[sc
->i
++];
440 sc
->bits
= MPW_BITS
- 1;
444 /* --- @mp_bit@ --- *
446 * Arguments: @const mp_bitscan *sc@ = pointer to bitscanner
448 * Returns: Current bit value.
450 * Use: Returns the value of the current bit.
453 int mp_bit(const mp_bitscan
*sc
) { return (MP_BIT(sc
)); }
455 /*----- Shifting ----------------------------------------------------------*/
457 /* --- @mp_lsl@ --- *
459 * Arguments: @mp *d@ = pointer to MP head of destination
460 * @const mp *x@ = pointer to MP head of source
461 * @size_t n@ = number of bits to shift
465 * Use: Shifts a number left by a given number of bit positions.
468 void mp_lsl(mp
*d
, const mp
*x
, size_t n
)
470 size_t nw
= n
/ MPW_BITS
;
471 unsigned nb
= n
% MPW_BITS
;
472 unsigned nr
= MPW_BITS
- nb
;
475 /* --- Trivial special case --- */
477 if (n
== 0 || mp_ucmp(x
, MP_ZERO
) == 0) {
482 /* --- Decide on the about of memory needed in the destination --- */
485 if (nb
&& (x
->v
[x
->len
- 1] >> nr
) != 0)
491 /* --- Handle single bit shifting --- */
495 const mpw
*vx
= x
->v
;
502 *v
++ = ((t
<< 1) | w
) & MPW_MAX
;
503 w
= t
>> (MPW_BITS
- 1);
510 /* --- Handle shifts by a multiple of the word size --- *
512 * This would be easy, except that C is irritating. Shifting an integer
513 * by an amount equal to the type's width yields undefined behaviour;
514 * in particular, under Intel it's a no-op.
519 const mpw
*vx
= x
->v
;
520 memmove(v
+ nw
, vx
, (req
- nw
) * sizeof(mpw
));
521 memset(v
, 0, nw
* sizeof(mpw
));
525 /* --- Now do the difficult version --- */
529 const mpw
*vx
= x
->v
+ x
->len
;
533 /* --- First shift the data over --- */
535 if (req
> x
->len
+ nw
)
540 *--v
= ((w
<< nb
) | (t
>> nr
)) & MPW_MAX
;
544 /* --- Deal with tail-end data --- */
554 /* --- Common end code --- */
563 /* --- @mp_lsr@ --- *
565 * Arguments: @mp *d@ = pointer to MP head of destination
566 * @const mp *x@ = pointer to MP head of source
567 * @size_t n@ = number of bits to shift
571 * Use: Shifts a number right by a given number of bit positions.
574 void mp_lsr(mp
*d
, const mp
*x
, size_t n
)
576 size_t nw
= n
/ MPW_BITS
;
577 unsigned nb
= n
% MPW_BITS
;
578 unsigned nr
= MPW_BITS
- nb
;
581 /* --- Trivial special case --- */
583 if (n
== 0 || mp_ucmp(x
, MP_ZERO
) == 0) {
588 /* --- Decide on the about of memory needed in the destination --- */
591 if ((x
->v
[x
->len
- 1] >> nb
) == 0)
597 /* --- Handle single bit shifting --- */
601 const mpw
*vx
= x
->v
+ x
->len
;
606 *--v
= (w
>> 1) & MPW_MAX
;
610 *--v
= (w
<< (MPW_BITS
- 1) | (t
>> 1)) & MPW_MAX
;
616 /* --- Handle shifts by a multiple of the word size --- *
618 * This would be easy, except that C is irritating. Shifting an integer
619 * by an amount equal to the type's width yields undefined behaviour;
620 * in particular, under Intel it's a no-op.
625 const mpw
*vx
= x
->v
;
626 memmove(v
, vx
+ nw
, (x
->len
- nw
) * sizeof(mpw
));
630 /* --- Now do the difficult version --- */
634 const mpw
*vx
= x
->v
+ nw
;
638 /* --- First shift the data over --- */
643 *v
++ = ((w
>> nb
) | (t
<< nr
)) & MPW_MAX
;
646 if (req
== x
->len
- nw
) {
647 *v
++ = (w
>> nb
) & MPW_MAX
;
651 /* --- Common end code --- */
660 /*----- Adding and subtracting --------------------------------------------*/
662 /* --- @mp_uadd@ --- *
664 * Arguments: @const mp *d@ = pointers to MP head of destination
665 * @const mp *x, *y@ = pointers to MP heads of operands
669 * Use: Performs unsigned MP addition.
672 void mp_uadd(mp
*d
, const mp
*x
, const mp
*y
)
677 const mpw
*vxl
, *vyl
;
679 /* --- Some trivial initialization --- */
681 if (d
!= x
&& d
!= y
)
683 MP_ENSURE(d
, (x
->len
> y
->len ? x
->len
: y
->len
) + 1);
684 vx
= x
->v
; vxl
= vx
+ x
->len
;
685 vy
= y
->v
; vyl
= vy
+ y
->len
;
689 /* --- Start on the work --- */
691 while (vx
< vxl
|| vy
< vyl
) {
692 if (vx
< vxl
) c
+= *vx
++;
693 if (vy
< vyl
) c
+= *vy
++;
700 /* --- Tidy up --- */
704 if (x
->f
& MPF_BURN
|| y
->f
& MPF_BURN
)
709 /* --- @mp_usub@ --- *
711 * Arguments: @const mp *d@ = pointers to MP head of destination
712 * @const mp *x, *y@ = pointers to MP heads of operands
716 * Use: Performs unsigned MP subtraction.
719 void mp_usub(mp
*d
, const mp
*x
, const mp
*y
)
724 const mpw
*vxl
, *vyl
;
726 /* --- Some trivial initialization --- */
728 if (d
!= x
&& d
!= y
)
730 MP_ENSURE(d
, x
->len
);
731 vx
= x
->v
; vxl
= vx
+ x
->len
;
732 vy
= y
->v
; vyl
= vy
+ y
->len
;
736 /* --- Start on the work --- */
740 if (vy
< vyl
) c
-= *vy
++;
748 /* --- Tidy up --- */
752 if (x
->f
& MPF_BURN
|| y
->f
& MPF_BURN
)
757 /* --- @mp_ucmp@ --- *
759 * Arguments: @const mp *x, *y@ = pointers to MP heads of operands
761 * Returns: Less than, equal to, or greater than zero.
763 * Use: Performs unsigned MP comparison.
766 int mp_ucmp(const mp
*x
, const mp
*y
)
771 /* --- Decide which to examine --- */
778 /* --- Loop through the data --- */
782 a
= (i
< x
->len ? x
->v
[i
] : 0);
783 b
= (i
< y
->len ? y
->v
[i
] : 0);
790 /* --- Finished --- */
795 /*----- Multiplying and dividing ------------------------------------------*/
797 /* --- @mp_umul@ --- *
799 * Arguments: @mp *d@ = pointer to MP head of destination
800 * @const mp *x, *y@ = pointes to MP heads of operands
804 * Use: Performs unsigned MP multiplication.
807 void mp_umul(mp
*d
, const mp
*x
, const mp
*y
)
812 const mpw
*vxl
, *vyl
;
814 /* --- Check for special cases --- */
816 if (mp_ucmp(x
, MP_ZERO
) == 0 || mp_ucmp(y
, MP_ZERO
) == 0) {
821 /* --- Some trivial initialization --- */
824 MP_ENSURE(d
, x
->len
+ y
->len
);
828 memset(v
, 0, (x
->len
+ y
->len
) * sizeof(mpw
));
830 /* --- Main loop --- */
832 for (vx
= x
->v
; vx
< vxl
; vx
++) {
836 for (vy
= y
->v
; vy
< vyl
; vy
++) {
844 /* --- Tidying up --- */
848 if (x
->f
& MPF_BURN
|| y
->f
& MPF_BURN
)
853 /* --- @mp_udiv@ --- *
855 * Arguments: @mp *q, *r@ = pointers to MP heads for quotient, remainder
856 * @const mp *x, *y@ = pointers to MP heads for operands
860 * Use: Performs unsigned MP division.
863 void mp_udiv(mp
*q
, mp
*r
, const mp
*x
, const mp
*y
)
865 size_t n
= x
->len
, t
= y
->len
;
867 mpw
*vx
, *vq
, *vxl
, *va
, *vb
;
870 mp nx
= MP_INIT
, ny
= MP_INIT
, nq
= MP_INIT
;
874 /* --- Fiddle with some pointers --- */
881 /* --- Find the top word in @y@ --- */
886 THROW(EXC_FAIL
, "mp_udiv detected divide-by-zero");
887 if ((yt
= vy
[t
- 1]) != 0)
892 /* --- Check for a zero dividend --- */
894 if (mp_ucmp(x
, MP_ZERO
)) {
895 if (q
) mp_copy(q
, MP_ZERO
);
896 if (r
) mp_copy(r
, MP_ZERO
);
900 /* --- Test for some other trivial cases --- */
903 int i
= mp_ucmp(x
, y
);
905 if (r
) mp_copy(r
, x
);
906 if (q
) mp_copy(q
, MP_ZERO
);
909 if (r
) mp_copy(r
, MP_ZERO
);
910 if (q
) mp_copy(q
, MP_ONE
);
915 /* --- Normalize the divisor --- *
917 * Cheat. The original algorithm wants two-word values at least, so I just
918 * shift everything up by a word if necessary.
922 while (yt
< MPW_MAX
/ 2) {
929 mp_lsl(&ny
, y
, shift
);
934 yd
= ((mpd
)yt
<< MPW_BITS
) | (mpd
)ytt
;
936 /* --- Initialize the quotient --- */
938 MP_ENSURE(q
, n
- t
+ 1);
940 memset(vq
, 0, (n
- t
) * sizeof(mpw
));
942 /* --- Shift the divisor up to match the dividend --- */
944 mp_lsl(&ny
, (n
- t
) * MPW_BITS
);
947 /* --- Get the most significant quotient digit --- *
949 * Because of the normalization, this should only happen once.
952 while (mp_ucmp(x
, y
) >= 0) {
957 /* --- Now do the main loop --- */
967 /* --- Fetch the top words from @x@ --- */
973 xd
= ((mpd
)xi
<< MPW_BITS
) | (mpd
)xii
;
975 /* --- Get an approximation for @qi@ --- */
982 /* --- Work out how close the approximation is --- *
984 * This is more than a little ugly.
989 yhi
+= ylo
>> MPW_BITS
;
992 /* --- Now fix the approximation --- *
994 * Again, the normalization helps; this is never done more than twice.
997 while (!(yhi
<= xd
&& ylo
<= xiii
)) {
1002 ylo
= (ylo
- ytt
) & MPW_MAX
;
1005 /* --- Subtract off a goodly big chunk --- */
1010 /*----- Test rig ----------------------------------------------------------*/
1016 #include "testrig.h"
1018 /* --- Loading and storing numbers --- *
1020 * The most reliable way I can think of for doing this is to convert both
1021 * numbers (the MP and the original hexgorp) into binary text, and compare.
1022 * This ought to be reliable, and it's sufficiently different from what the
1023 * actual load and store routines are doing not to have any common bugs.
1026 static void mpbindump(const mp
*x
, char *p
)
1029 for (mp_mkbitscan(&sc
, x
); mp_bstep(&sc
); )
1030 *p
++ = '0' + MP_BIT(&sc
);
1034 static void bindumpl(const octet
*q
, size_t sz
, char *p
)
1041 for (bits
= 8; bits
> 0; bits
--) {
1042 *p
++ = '0' + (w
& 1);
1050 static void bindumpb(const octet
*q
, size_t sz
, char *p
)
1058 for (bits
= 8; bits
> 0; bits
--) {
1059 *p
++ = '0' + (w
& 1);
1067 static int bincmp(const char *p
, const char *q
)
1072 else if (!*p
&& *q
== '0')
1074 else if (*p
== '0' && !*q
)
1083 static int lscheck(const char *reason
, int w
, dstr
*d
, mp
*x
,
1084 const char *bufa
, const char *bufb
)
1086 if (bincmp(bufa
, bufb
)) {
1087 printf("\nmismatch in %s (width = %i):\n"
1088 "\tvalue = ", reason
, w
);
1089 type_hex
.dump(d
, stdout
);
1090 printf("\n\tmp = ");
1092 printf("\n\texpected = %s\n"
1093 "\tcalculated = %s\n",
1100 static int loadstore(dstr
*d
)
1102 octet
*p
= (octet
*)d
[0].buf
;
1103 size_t sz
= d
[0].len
;
1104 char bufa
[1024], bufb
[1024];
1111 for (i
= 8; ok
&& i
<= 32; i
++) {
1113 mpw_max
= (mp_wmax
<< 1) + 1;
1115 mp_create(&x
); mp_loadl(&x
, p
, sz
);
1116 mpbindump(&x
, bufa
); bindumpl(p
, sz
, bufb
);
1117 if (lscheck("mp_loadl", i
, d
, &x
, bufa
, bufb
)) ok
= 0;
1118 mp_storeb(&x
, bufc
, sizeof(bufc
));
1119 bindumpb(bufc
, sizeof(bufc
), bufa
);
1120 if (lscheck("mp_storeb", i
, d
, &x
, bufa
, bufb
)) ok
= 0;
1123 mp_create(&x
); mp_loadb(&x
, p
, sz
);
1124 mpbindump(&x
, bufa
); bindumpb(p
, sz
, bufb
);
1125 if (lscheck("mp_loadb", i
, d
, &x
, bufa
, bufb
)) ok
= 0;
1126 mp_storel(&x
, bufc
, sizeof(bufc
));
1127 bindumpl(bufc
, sizeof(bufc
), bufa
);
1128 if (lscheck("mp_storel", i
, d
, &x
, bufa
, bufb
)) ok
= 0;
1137 /* --- Comparison test --- */
1139 static int compare(dstr
*d
)
1145 mp_create(&x
); mp_create(&y
);
1146 mp_loadb(&x
, (octet
*)d
[0].buf
, d
[0].len
);
1147 mp_loadb(&y
, (octet
*)d
[1].buf
, d
[1].len
);
1148 r
= *(int *)d
[2].buf
;
1149 s
= mp_ucmp(&x
, &y
);
1153 printf("\nfailed compare:"
1155 type_hex
.dump(&d
[0], stdout
);
1157 type_hex
.dump(&d
[1], stdout
);
1158 printf("\n\texpected %i; found %i\n", r
, s
);
1164 /* --- Addition and subtraction test --- */
1166 static int addsub(dstr
*d
)
1171 mp_create(&t
); mp_create(&x
); mp_create(&y
); mp_create(&z
);
1172 mp_loadb(&x
, (octet
*)d
[0].buf
, d
[0].len
);
1173 mp_loadb(&y
, (octet
*)d
[1].buf
, d
[1].len
);
1174 mp_loadb(&z
, (octet
*)d
[2].buf
, d
[2].len
);
1176 mp_uadd(&t
, &x
, &y
);
1177 if (mp_ucmp(&t
, &z
)) {
1179 printf("\nfailed add:");
1180 printf("\n\tx = "); type_hex
.dump(&d
[0], stdout
);
1181 printf("\n\ty = "); type_hex
.dump(&d
[1], stdout
);
1182 printf("\n\tz = "); type_hex
.dump(&d
[2], stdout
);
1183 fputc('\n', stdout
);
1186 mp_usub(&t
, &z
, &x
);
1187 if (mp_ucmp(&t
, &y
)) {
1189 printf("\nfailed subtract:");
1190 printf("\n\tz = "); type_hex
.dump(&d
[2], stdout
);
1191 printf("\n\tx = "); type_hex
.dump(&d
[0], stdout
);
1192 printf("\n\ty = "); type_hex
.dump(&d
[1], stdout
);
1193 fputc('\n', stdout
);
1199 /* --- Shifting --- */
1201 static int shift(dstr
*d
)
1203 char bufa
[1024], bufb
[1024];
1205 int n
= *(int *)d
[1].buf
;
1213 mp_loadb(&x
, (octet
*)d
[0].buf
, d
[0].len
);
1215 for (i
= 0; i
< n
; i
++)
1220 mpbindump(&y
, bufb
);
1221 if (lscheck("lsl", n
, d
, &x
, bufb
, bufa
))
1225 mpbindump(&y
, bufb
);
1226 if (lscheck("lsr", n
, d
, &x
, bufb
, bufa
+ 2 * n
))
1232 /* --- Test driver stub --- */
1234 static test_chunk mp__defs
[] = {
1235 { "mp-loadstore", loadstore
, { &type_hex
, 0 } },
1236 { "mp-cmp", compare
, { &type_hex
, &type_hex
, &type_int
, 0 } },
1237 { "mp-addsub", addsub
, { &type_hex
, &type_hex
, &type_hex
, 0 } },
1238 { "mp-shift", shift
, { &type_hex
, &type_int
, 0 } },
1242 int main(int argc
, char *argv
[])
1244 test_run(argc
, argv
, mp__defs
, SRCDIR
"/tests/mp");
1250 /*----- That's all, folks -------------------------------------------------*/