Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 944 lines (870 sloc) 36.989 kB
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
1 /* biggishint.c */
2 /* Biggish integers in this library are arrays of up 32766 16-bit */
3 /* (unsigned short) integers for arbitrary precision integer */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
4 /* arithmetic up to 524240-bit (16*32765 bit) numbers. A biggish */
5 /* rational library (biggishrat) using these is also being developed. */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
6
7 /* The data format for these (fairly) big integers is an array of */
8 /* short ints allocated on the heap, with the following layout: */
9 /* +--------------------------------+-------------------------------+ */
10 /* | required (2 short ints) | optional (up to 16382 times) | */
11 /* | word 0 | word 1 | word 2 | word 3 etc | */
12 /* | 14 bits: size | 16 bits: int | 16 bits: int | 16 bits: int | */
13 /* | 1 bit: overflow | | | | */
14 /* | 1 bit: sign | | | | */
15 /* +-----------------+--------------+---------------+---------------+ */
16 /* Word 0 uses 14 bits for the size in units of pairs of short ints, */
17 /* 1 bit for overflow/underflow and 1 bit for (minus) sign. */
18 /* The remaining words are all unsigned short integers, always an odd */
19 /* number of them because of word 0 and the even array size. Thus */
20 /* memory allocation occurs in multiples of 4 bytes, a nice alignment */
21 /* compromise between small and large processor types. */
22
23 /* The most compact biggishint uses 4 bytes to count from -65536 to */
24 /* +65535, the next size (8 bytes) spans -281474976710656 (-2^48) to */
25 /* +281474976710655 (+2^48-1), and so on to the largest (65532 bytes) */
26 /* calculating from about -9.22e157811 (-2^524240) to about */
27 /* +9.22e157811 (+2^524240-1). */
28
29 /* The word order is big endian, no matter what the byte order of the */
30 /* processor may be. There is no reason for this, it just is. */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
31 /* Update: there is a reason to be little endian: the trim() and */
32 /* shortmultiply() would improve. */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
33
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
34 /* All words are unsigned. Negative numbers are stored as positive */
35 /* numbers and the first word keeps a sign bit. Thus the functions */
36 /* behave as if each word is simply a digit in a base-65536 number. */
37 /* The design would use 32-bit words (base-4294967296 numbers) */
38 /* instead if every possible C compiler had a 64-bit data type to do */
39 /* carries, but this is not the case. */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
40
41 /* Functions set the overflow bit if the result does not fit in 32766 */
42 /* words (including the initial size word). If the overflow bit is */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
43 /* set the other fields change their meaning: */
44 /* * The sign bit indicates positive overflow or negative overflow. */
45 /* * The integer value is unusable, and is therefore reduced to the */
46 /* minimum of 1 word. A design in which the value might represent */
47 /* positive or negative infinity (as opposed to mere overflow), */
48 /* or other forms of NaN (Not a Number) is under consideration. */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
49
50 /* Use biggishint at your risk and without warranty. Give due credit */
51 /* if you do. Written by Martin Berends. */
52
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
53 /* See also: a much bigger library: http://gmplib.org/manual/ */
54 /* Donald E. Knuth The Art of Computer Programming Vol 2 */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
55
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
56 /* TODO: overflow detection */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
57 /* TODO: change from big endian to little endian */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
58
59 #include <assert.h> /* assert */
60 #include <ctype.h> /* tolower */
61 #include <limits.h> /* USHRT_MAX */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
62 #include <stdio.h> /* printf, only when debugging */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
63 #include <stdlib.h> /* calloc malloc realloc free */
64 #include <string.h> /* strlen strncmp */
65 #include "biggishint.h" /* (all externally callable functions) */
66
67 #if USHRT_MAX != 65535
68 #error In this C compiler a short int is not a 16 bit number.
69 #endif
70
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
71 /* #define BIGGISHINT_TRACE */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
72
73 /* Internal functions are declared here, their definitions are lower */
74 /* down. */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
75 unsigned short * biggishint_internal_addsubtract(unsigned short * bi1, unsigned short * bi2, int flipsign2);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
76 int biggishint_internal_bitsize(unsigned long);
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
77 unsigned short * biggishint_internal_clone(unsigned short * bi1);
78 int biggishint_internal_comparemagnitude(unsigned short * bi1, unsigned short * bi2);
79 unsigned short * biggishint_internal_shiftleft(unsigned short * bi1, unsigned int bitcount);
80 unsigned short * biggishint_internal_shiftright(unsigned short * bi1, unsigned int bitcount);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
81 void biggishint_internal_shortdivide(unsigned short * bi1, unsigned short * i2);
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
82 void biggishint_internal_shortmultiply(unsigned short ** bi1, unsigned short i2);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
83 unsigned short * biggishint_internal_trim(unsigned short ** bi1);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
84
85
86 /* --------------------------- Functions ---------------------------- */
87
88
89 /* biggishintAdd */
90 unsigned short *
91 biggishintAdd(unsigned short * bi1, unsigned short * bi2)
92 {
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
93 return biggishint_internal_addsubtract(bi1, bi2, 0);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
94 }
95
96
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
97 /* biggishintCompare */
98 int
99 biggishintCompare(unsigned short * bi1, unsigned short * bi2)
100 {
101 int sign1, sign2, result;
102 sign1 = * bi1 & 1;
103 sign2 = * bi2 & 1;
104 result = sign1
105 ? ( sign2 ? biggishint_internal_comparemagnitude(bi2, bi1) : -1 )
106 : (!sign2 ? biggishint_internal_comparemagnitude(bi1, bi2) : 1 );
107 return result;
108 }
109
110
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
111 /* biggishintDivide */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
112 /* see The Art of Computer Programming Vol 2 3rd Ed p270-275 */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
113 unsigned short *
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
114 biggishintDivide(unsigned short * bi1, unsigned short * divisor)
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
115 {
116 /* Before starting on the main long division, which is slow, try */
117 /* to identify divisors that offer an opportunity for a shortcut, */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
118 /* for example shifting right for divisors that are powers of two */
119 /* or short division for divisors that fit into a small int. */
120 /* In contast with most of the other routines, this one uses */
121 /* multiple returns to avoid having many levels of nested */
122 /* conditionals. */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
123 unsigned short bi1size, divisorsize, dividendword1, dividendword2;
124 unsigned short * dividend, * pdividend, * pdividendhi, * pdividendlo;
125 unsigned short * quotient, * pquotient, * pquotienthi, * pquotientlo;
126 unsigned short * pdivisor, * pdivisorhi, * pdivisorlo;
127 int sign1, sign2, sign, comparison, divisorshift;
128 unsigned long dividendcarry, trialdivisor;
129 unsigned long tempquotient, trialquotientmin, quotientcarry;
130 bi1size = (* bi1 & 0xfffc) >> 1;
131 divisorsize = (* divisor & 0xfffc) >> 1;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
132 sign1 = * bi1 & 1;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
133 sign2 = * divisor & 1;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
134 sign = sign1 ^ sign2;
135 /* Does dividend have fewer words than divisor? */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
136 if (bi1size < divisorsize) { /* quotient becomes 0 */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
137 quotient = (unsigned short *) calloc(2, sizeof(short));
138 * quotient = 4;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
139 return quotient;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
140 }
141 /* Is divisor only a 16 bit unsigned number? */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
142 if (divisorsize == 2) { /* use short division instead of long */
143 unsigned short shortdivisor = divisor[1];
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
144 quotient = biggishint_internal_clone(bi1);
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
145 biggishint_internal_shortdivide(quotient, & shortdivisor);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
146 * quotient ^= sign2;
147 return biggishint_internal_trim(&quotient);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
148 }
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
149 /* Is dividend less in magnitude than divisor? */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
150 comparison = biggishint_internal_comparemagnitude(bi1, divisor);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
151 if (comparison<0) { /* quotient becomes 0 */
152 /* Hope the C compiler merges this code with the same code in */
153 /* (bi1size < bi2size) above. Repeated here because the */
154 /* earlier case avoids the comparemagnitude function. */
155 quotient = (unsigned short *) calloc(2, sizeof(short));
156 * quotient = 4;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
157 return quotient;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
158 }
159 /* Is dividend equal in magnitude to divisor? */
160 if (comparison==0) { /* quotient becomes 1 (+ or -) */
161 quotient = (unsigned short *) calloc(2, sizeof(short));
162 * quotient = 4 | sign;
163 quotient[1] = 1;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
164 return quotient;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
165 }
166 /* Is divisor a power of two or a multiple of a power of two? */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
167 /* ie is there only a single 1 bit or at least one trailing 0 bit? */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
168 if (0) {
169 ; /* TODO: right shift optimization */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
170 }
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
171 /* Perform long division because none of the quicker algorithms */
172 /* above could be used with the given parameters. */
173 assert( bi1size >= 4 ); assert( divisorsize >= 4 );
174 /* Initialize dividend with bi1. The loop below will repeatedly */
175 /* subtract multiples of divisorshifted until the remainder is */
176 /* less than divisor. */
177 dividend = biggishint_internal_clone(bi1);
178 pdividendhi = dividend + (dividend[1] ? 1 : 2);
179 pdividendlo = dividend + bi1size - 1;
180 #ifdef BIGGISHINT_TRACE
181 fprintf(stdout,"dividend %s%04x", (* dividend & 1)?"-":"",
182 * (pdividend=pdividendhi));
183 while (++pdividend <= pdividendlo)
184 fprintf(stdout,"_%04x", * pdividend);
185 fprintf(stdout," at %p hi %+ld lo %+ld\n",
186 dividend, pdividendhi-dividend, pdividendlo-dividend);
187 #endif
188 /* Point to the divisor's highest and lowest data words */
189 pdivisorhi = divisor + (divisor[1] ? 1 : 2);
190 pdivisorlo = divisor + divisorsize - 1;
191 trialdivisor = (unsigned long) (* pdivisorhi) + 1;
192 #ifdef BIGGISHINT_TRACE
193 fprintf(stdout,"divisor %s%04x", (* divisor & 1)?"-":"",
194 * (pdivisor=pdivisorhi));
195 while (++pdivisor <= pdivisorlo)
196 fprintf(stdout,"_%04x", * pdivisor);
197 fprintf(stdout," at %p hi %+ld lo %+ld\n",
198 divisor, pdivisorhi-divisor, pdivisorlo-divisor);
199 #endif
200 /* Initialize the quotient (result) */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
201 quotient = (unsigned short *) calloc(bi1size, sizeof(short));
202 * quotient = bi1size << 1 | sign;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
203 /* Work out at which word in quotient the result will begin */
204 pquotienthi = quotient + (bi1[1] ? 1 : 2) + (pdivisorlo-pdivisorhi);
205 pquotientlo = quotient + bi1size - 1;
206 dividendcarry = 0;
207 /* Calculate one word of the quotient per loop */
208 while (pquotienthi<=pquotientlo) {
209 /* To avoid comparing all the words of the divisor, perform a */
210 /* trial division of dividendcarry by the first word of the */
211 /* divisor plus one. */
212 dividendcarry += * pdividendhi;
213 trialquotientmin = dividendcarry / trialdivisor;
214 while (trialquotientmin) {
215 #ifdef BIGGISHINT_TRACE
216 fprintf(stdout,"carry(%ld) %x dividendcarry %lx/%lx=%lx\n",
217 pdividendhi-dividend, * pdividendhi, dividendcarry,
218 trialdivisor, trialquotientmin);
219 fprintf(stdout," quotient %s%04x", (* quotient & 1)?"-":"",
220 * (pquotient=quotient));
221 while (++pquotient <= pquotientlo)
222 fprintf(stdout,"_%04x", * pquotient);
223 fprintf(stdout," at %p hi %+ld lo %+ld\n",
224 quotient, pquotienthi-quotient, pquotientlo-quotient);
225 #endif
226
227 /* Subtract shifted trialquotient*divisor from dividend. */
228 tempquotient = trialquotientmin;
229 divisorshift = 0;
230 while (tempquotient) {
231 pdividend = pdividendhi + (pdivisorlo - pdivisorhi) - divisorshift++;
232 #ifdef BIGGISHINT_TRACE
233 fprintf(stdout," tempquotient %lx pdividend %+ld\n",
234 tempquotient, pdividend-dividend);
235 #endif
236 /* Use tempquotient1 to subtract successive words of */
237 /* divisor multiplied by tempquotient2 from dividend. */
238 quotientcarry = 0UL;
239 for (pdivisor=pdivisorlo; pdivisor>=pdivisorhi; --pdivisor) {
240 quotientcarry += (* pdivisor) * (tempquotient & 0xffff);
241 dividendword1 = (* pdividend);
242 dividendword2 = quotientcarry & 0xffff;
243 #ifdef BIGGISHINT_TRACE
244 fprintf(stdout," dividend[%ld] = %04x-%04x = ",
245 pdividend-dividend, dividendword1, dividendword2);
246 #endif
247 if (dividendword1 >= dividendword2) /* just subtract */
248 dividendword1 -= dividendword2;
249 else { /* borrow, then subtract */
250 dividendword1 = 0x10000UL + dividendword1 - dividendword2;
251 quotientcarry += 0x10000UL;
252 }
253 #ifdef BIGGISHINT_TRACE
254 fprintf(stdout,"%04x tempquotient1 %lx\n",
255 dividendword1, quotientcarry);
256 #endif
257 * pdividend-- = dividendword1;
258 quotientcarry>>=16;
259 }
260 assert( quotientcarry <= 0xffff ); /* no loop required */
261 if (quotientcarry) {
262 #ifdef BIGGISHINT_TRACE
263 fprintf(stdout," dividend[%ld] = %04x-%04lx = ",
264 pdividend-dividend, * pdividend, quotientcarry);
265 #endif
266 (* pdividend) -= (unsigned short) quotientcarry;
267 #ifdef BIGGISHINT_TRACE
268 fprintf(stdout,"%04x\n", * pdividend);
269 #endif
270 }
271 tempquotient >>= 16;
272 } /* Subtracting shifted trialquotient*divisor from dividend */
273
274 /* Add shifted trialquotient to quotient */
275 tempquotient = trialquotientmin;
276 pquotient = pquotienthi;
277 while (tempquotient) {
278 tempquotient += * pquotient;
279 * pquotient-- = tempquotient & 0xffff;
280 tempquotient >>= 16;
281 }
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
282
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
283 /* Make a new dividendcarry from dividend. */
284 /* TODO: use assert() to check whether a loop is really needed */
285 dividendcarry = 0;
286 for (pdividend=dividend+1; pdividend<=pdividendhi; ++pdividend ) {
287 dividendcarry = (dividendcarry<<16) + (* pdividend);
288 }
289 trialquotientmin = dividendcarry / trialdivisor;
290 } /* while (trialquotientmin > 0) */
291
292 #ifdef BIGGISHINT_TRACE
293 fprintf(stdout," dividend %s%04x", (* dividend & 1)?"-":"",
294 * (pdividend=dividend));
295 while (++pdividend <= pdividendlo)
296 fprintf(stdout,"_%04x", * pdividend);
297 fprintf(stdout," at %p hi %+ld lo %+ld\n",
298 dividend, pdividendhi-dividend, pdividendlo-dividend);
299 #endif
300
301 /* Proceed to the next word in the quotient and dividend */
302 dividendcarry <<= 16;
303 ++pquotienthi;
304 ++pdividendhi;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
305 }
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
306
307 #ifdef BIGGISHINT_TRACE
308 fprintf(stdout," quotient %s%04x", (* quotient & 1)?"-":"",
309 * (pquotient=quotient));
310 while (++pquotient <= pquotientlo)
311 fprintf(stdout,"_%04x", * pquotient);
312 fprintf(stdout," at %p hi %+ld lo %+ld\n",
313 quotient, pquotienthi-quotient, pquotientlo-quotient);
314 #endif
315
316 /* Subtract (trialquotient2*divisor) from dividend. */
317 pdividend = pdividendlo;
318 #ifdef BIGGISHINT_TRACE
319 fprintf(stdout," trialquotientmin %lx pdividend %+ld\n",
320 trialquotientmin, pdividend-dividend);
321 #endif
322 /* Try to subtract the divisor from the dividend (this is the */
323 /* only time divisor is used instead of leading word of divisor */
324 /* + 1. */
325 dividendcarry = 0;
326 while (biggishint_internal_comparemagnitude(dividend, divisor) >= 0) {
327 pdividend = pdividendlo;
328 dividendword2 = 0; /* used as the borrow word in subtraction */
329 for (pdivisor=pdivisorlo; pdivisor>=pdivisorhi; --pdivisor) {
330 dividendword1 = * pdividend;
331 if ((unsigned long) dividendword1 >= (unsigned long) * pdivisor + dividendword2) {
332 /* just subtract */
333 dividendword1 -= * pdivisor + dividendword2;
334 dividendword2 = 0;
335 }
336 else { /* borrow, then subtract */
337 dividendword1 = (unsigned long) dividendword1 - * pdivisor + dividendword2;
338 dividendword2 = 1;
339 }
340 * pdividend-- = dividendword1;
341 }
342 // unsigned short * dividend_temp = dividend;
343 // dividend = biggishint_internal_addsubtract(dividend_temp, divisor, 1);
344 // free(dividend_temp);
345 ++dividendcarry;
346 }
347 #ifdef BIGGISHINT_TRACE
348 fprintf(stdout,"final dividendcarry %lx\n", dividendcarry);
349 #endif
350 assert( dividendcarry <= 1 );
351 pquotient = pquotientlo;
352 while (dividendcarry && (pquotient>quotient)){
353 dividendcarry += * pquotient;
354 * pquotient-- = dividendcarry & 0xffff;
355 dividendcarry >>= 16;
356 }
357
358 free(dividend);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
359 return biggishint_internal_trim(&quotient);
360 }
361
362
363 /* biggishintFree */
364 void
365 biggishintFree(unsigned short * bi1)
366 {
367 free(bi1);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
368 }
369
370
371 /* biggishintFromDecimalString */
372 /* Note: this algorithm is unacceptably inefficient and should be */
373 /* rewritten, because the two other biggishint functions it calls */
374 /* cause two malloc() calls per decimal digit. */
375 unsigned short *
376 biggishintFromDecimalString(char * str)
377 {
378 char * ps, c;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
379 int sign = 0;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
380 unsigned short * bi1, * bi2;
381 unsigned short digitvalue[2] = {4,0};
382 ps = str;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
383 if (* ps == '-') { /* Detect a leading minus sign */
384 sign = 1;
385 ++ps;
386 }
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
387 /* Create the initial biggishint result with a value of 0 */
388 bi1 = (unsigned short *) calloc(2,2);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
389 * bi1 = 4 | sign;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
390 /* take one digit at a time, convert to binary, accumulate values */
391 while ( isdigit(c = * ps++) ) {
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
392 biggishint_internal_shortmultiply(&bi1, 10);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
393 digitvalue[1] = c - '0';
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
394 bi2 = biggishint_internal_addsubtract(bi1, digitvalue, 0);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
395 free(bi1);
396 bi1 = bi2;
397 }
398 return bi1;
399 }
400
401
402 /* biggishintFromHexadecimalString */
403 unsigned short *
404 biggishintFromHexadecimalString(char * str)
405 {
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
406 int hexdigitcount, biggishintwordcount, i, nybble, sign=0;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
407 unsigned short biggishintarraysize, * biggishint, * shortPointer, value;
408 char character, * strPointer;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
409
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
410 strPointer = str;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
411 if (* strPointer == '-') { /* Detect a leading minus sign */
412 sign = 1;
413 ++strPointer;
414 }
415 if (strncmp(strPointer, "0x", 2) == 0) /* skip the '0x' prefix if it exists */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
416 strPointer += 2;
417 hexdigitcount = strlen(strPointer);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
418 /* The number of short integers holding values must always be odd */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
419 biggishintwordcount = (((hexdigitcount+3)>>3)<<1)+1; /* 1-4=>1, 5-12=>3 etc */
420 biggishintarraysize = biggishintwordcount + 1;
421 biggishint = (unsigned short *) calloc(biggishintarraysize, sizeof(unsigned short));
422 assert( biggishint != NULL );
423 shortPointer = biggishint;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
424 * shortPointer++ = (biggishintarraysize << 1) | sign;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
425 /* leave one word blank for 5-8 13-16 21-24 digit strings */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
426 if ( (hexdigitcount-1) & 0x4) ++shortPointer;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
427 value = 0;
428 for (i=hexdigitcount-1; i>=0; --i) {
429 character = tolower(* strPointer++);
430 nybble = character - '0' - (character>='a' ? 'a'-'9'-1 : 0);
431 value = (value<<4) + nybble;
432 if ((i%4) == 0) {
433 * shortPointer++ = value;
434 value = 0;
435 }
436 }
437 return biggishint;
438 }
439
440
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
441 /* biggishintFromLong */
442 unsigned short *
443 biggishintFromLong(long l)
444 {
445 unsigned short * bi1, negative_bit=0;
446 if (l<0) {
447 negative_bit = 1;
448 l = -l;
449 }
450 if (l <= USHRT_MAX) {
451 bi1 = (unsigned short *) calloc(2,sizeof(short));
452 * bi1 = 4 | negative_bit;
453 bi1[1] = (unsigned short) l;
454 }
455 else {
456 bi1 = (unsigned short *) calloc(4,sizeof(short));
457 * bi1 = 8 | negative_bit;
458 bi1[3] = (unsigned short) l;
459 bi1[2] = l >> 16;
460 }
461 return bi1;
462 }
463
464
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
465 /* biggishintMultiply */
466 unsigned short *
467 biggishintMultiply(unsigned short * bi1, unsigned short * bi2)
468 {
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
469 unsigned short bi1size, bi2size, res1size, res2size, sign1, sign2;
470 unsigned short * p1, * p2, * result, * presult;
471 int i1, i2;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
472 unsigned long resultsize, n1, n2, subtotal, carry;
473
474 /* Before starting on the main long multiplication, which is */
475 /* slow, try to identify multipliers that offer an opportunity */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
476 /* for a shortcut, for example by 0 or 1, shifting left for */
477 /* multipliers that are multiples of powers of two, or short */
478 /* multiplication. */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
479 bi1size = (* bi1 & 0xfffc) >> 1;
480 bi2size = (* bi2 & 0xfffc) >> 1;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
481 if (bi1size == 2) {
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
482 result = biggishint_internal_clone(bi2);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
483 * result &= 0xfffe; /* clear the sign bit */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
484 biggishint_internal_shortmultiply(&result, bi1[1]);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
485 }
486 else {
487 if (bi2size == 2) {
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
488 result = biggishint_internal_clone(bi1);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
489 * result &= 0xfffe; /* clear the sign bit */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
490 biggishint_internal_shortmultiply(&result, bi2[1]);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
491 }
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
492 else { /* both bi1 and bi2 are more than 16 bit numbers */
493 /* Create a result array that is large enough for any */
494 /* possible product. First calculate the smallest size */
495 /* according to the contents of bi1 and bi2, regardless */
496 /* of the need to round up to an even number. */
497 res1size = bi1size + (bi1[1] ? 0 : -1); /* the first word may be 0 */
498 res2size = bi2size + (bi2[1] ? 0 : -1);
499 /* Then add them together and round to an even number */
500 resultsize = (res1size + res2size + 1) & 0xfffe;
501 result = (unsigned short *) calloc(resultsize, sizeof(short));
502 * result = (resultsize << 1);
503 presult = result + resultsize;
504 p1 = bi1 + bi1size;
505 for (i1=1; i1<bi1size; ++i1) {
506 n1 = * --p1;
507 presult = result + resultsize - i1;
508 p2 = bi2 + bi2size;
509 carry = 0;
510 for (i2=1; i2<bi2size; ++i2) {
511 n2 = * --p2;
512 subtotal = (* presult) + n1 * n2 + carry;
513 carry = subtotal >> 16;
514 * presult-- = subtotal & 0xffff;
515 }
516 while (carry) {
517 * presult-- = carry;
518 carry >>= 16;
519 }
520 }
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
521 }
522 }
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
523 sign1 = * bi1 & 1;
524 sign2 = * bi2 & 1;
525 * result |= sign1 ^ sign2;
526 return biggishint_internal_trim(&result);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
527 }
528
529
530 /* biggishintShiftLeft */
531 unsigned short *
532 biggishintShiftLeft(unsigned short * bi1, unsigned short * bi2)
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
533 { /* TODO: shift counts from 65536 to 524239 and -1 to -524239 bits */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
534 return biggishint_internal_shiftleft(bi1, bi2[1]);
535 }
536
537
538 unsigned short *
539 biggishintShiftRight(unsigned short * bi1, unsigned short * bi2)
540 {
541 return NULL;
542 }
543
544
545 /* biggishintSubtract */
546 unsigned short *
547 biggishintSubtract(unsigned short * bi1, unsigned short * bi2)
548 {
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
549 return biggishint_internal_addsubtract(bi1, bi2, 1);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
550 }
551
552
553 /* biggishintToDecimalString */
554 char *
555 biggishintToDecimalString(unsigned short * bi1)
556 {
557 /* The number of decimal digits that will be created is difficult */
558 /* (or slow) to calculate in advance. This routine initially */
559 /* over-allocates memory, and then sizes it correctly at the end. */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
560 unsigned short bi1size, * bi2, digit, sign1;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
561 int strsize, leadingzeroes;
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
562 char * result, * pdigits, * p1;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
563 /* Calculate the very maximum number of characters that the */
564 /* resulting string can occupy, including a terminating '\0'. */
565 /* Each word is '65535' at most, then '\0' */
566 bi2 = biggishint_internal_clone(bi1);
567 bi1size = (* bi1 & 0xfffc) >> 1;
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
568 sign1 = * bi1 & 1;
569 strsize = (bi1size-1) * 5 + sign1 + 1;
570 result = (char *) malloc(strsize);
571 assert( result != NULL );
572 pdigits = result;
573 if (sign1) * pdigits++ = '-';
574 p1 = result + strsize;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
575 (* --p1) = '\0';
576 do {
577 digit = 10;
578 biggishint_internal_shortdivide(bi2, &digit);
579 (* --p1) = '0' + digit;
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
580 } while ( p1 > pdigits ); /* TODO: find other ways to finish early */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
581 free(bi2);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
582 /* Count how many '0' characters there are at the beginning of */
583 /* the string, and then move the non '0' characters. */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
584 leadingzeroes = strspn(pdigits, "0");
585 if (leadingzeroes == strsize - sign1 - 1)
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
586 --leadingzeroes;
587 if (leadingzeroes) {
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
588 memmove(pdigits, pdigits+leadingzeroes, strsize-sign1-leadingzeroes); /* (Big Endian)-- ;) */
589 result = realloc(result, strsize-leadingzeroes);
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
590 }
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
591 return result;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
592 }
593
594
595 /* biggishintToHexadecimalString */
596 char *
597 biggishintToHexadecimalString(unsigned short * bi1)
598 {
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
599 int bi1size, hexstringsize, i, j, value, nybble, emitzero, sign;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
600 char * hexString, * hexPointer;
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
601 bi1size = (* bi1 & 0xfffc) >> 1;
602 sign = * bi1 & 1;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
603 /* Calculate how many characters the hex string needs, including */
604 /* the "0x" at the beginning and a '\0' at the end */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
605 hexstringsize = (biggishint_internal_bitsize(bi1[1])+3)>>2; /* 0=>0, 1-4=>1, 5-8=>2 */
606 hexstringsize += (hexstringsize?0:1) /* allow for 0 digit */
607 + 3 + sign + ((bi1size-2) << 2); /* '0x' + sign + digits + '\0' */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
608 hexString = (char *) malloc(hexstringsize);
609 assert( hexString != NULL );
610 hexPointer = hexString;
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
611 if (sign) * hexPointer++ = '-';
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
612 * hexPointer++ = '0'; * hexPointer++ = 'x';
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
613 emitzero = 0; /* do not emit leading zeroes */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
614 for (i=1; i<bi1size; ++i) {
615 value = bi1[i];
616 for (j=3; j>=0; --j) {
617 nybble = (value >> (j*4)) & 0xf;
618 if (nybble || emitzero) {
619 * hexPointer++ = '0' + nybble + ((nybble>9) ? 'a'-'9'-1 : 0);
620 emitzero = 1;
621 }
622 }
623 }
624 if (! emitzero)
625 * hexPointer++ = '0';
626 * hexPointer = '\0';
627 return hexString;
628 }
629
630
631 /* ----------------------- Internal functions ----------------------- */
632 /* Except for biggishint_internal_trim, the internal functions do not */
633 /* trim their results, because it costs time, may be redundant, and */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
634 /* increases heap churn. */
635
636
637 /* biggishint_internal_addsubtract */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
638 unsigned short * biggishint_internal_addsubtract(unsigned short * bi1,
639 unsigned short * bi2, int flipsign2)
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
640 {
641 unsigned short bi1size, bi2size, res1size, res2size, resultsize;
642 unsigned short * result1, * result2, * larger, * smaller, * p1, * p2;
643 unsigned int sign1, sign2, sign, carry, i1, i2;
644 signed long partialresult;
645 sign1 = * bi1 & 1;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
646 sign2 = (* bi2 & 1) ^ flipsign2;
647 if (sign1 ^ sign2) { /* different signs, do a subtract */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
648 /* the larger number determines the size and sign of the result */
649 if (biggishint_internal_comparemagnitude(bi1,bi2) >= 0) {
650 larger = bi1; smaller = bi2; sign = sign1;
651 }
652 else {
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
653 smaller = bi1; larger = bi2; sign = sign2;
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
654 }
655 resultsize = (* larger & 0xfffc) >> 1;
656 result1 = (unsigned short *) calloc(resultsize, sizeof(short));
657 result2 = result1 + resultsize;
658 p1 = larger + ((* larger & 0xfffc) >> 1);
659 p2 = smaller + ((* smaller & 0xfffc) >> 1);
660 carry = 0;
661 partialresult = 0;
662 while (--p1 > larger) {
663 i1 = * p1;
664 i2 = (--p2 > smaller) ? * p2 : 0;
665 partialresult += i1 - i2;
666 * --result2 = (partialresult >=0)
667 ? (unsigned short) partialresult
668 : (unsigned short) (partialresult + 65536);
669 partialresult = (partialresult & 0xffff0000) ? -1 : 0;
670 }
671 } /* subtract */
672 else { /* same signs, do an add */
673 bi1size = (* bi1 & 0xfffc) >> 1;
674 bi2size = (* bi2 & 0xfffc) >> 1;
675 res1size = bi1size + (bi1[1] ? 1 : 0); /* the first word may be 0 */
676 res2size = bi2size + (bi2[1] ? 1 : 0);
677 resultsize = ((res1size > res2size ? res1size : res2size) + 1) & 0xfffe;
678 sign = sign1;
679 result1 = (unsigned short *) calloc(resultsize, sizeof(short));
680 assert( result1 != NULL );
681 /* Initialize pointers to the augend (bi1), addend (bi2) and partialresult */
682 * result1 = resultsize << 1;
683 p1 = bi1 + bi1size - 1;
684 p2 = bi2 + bi2size - 1;
685 result2 = result1 + resultsize - 1;
686 carry = 0;
687 /* Iteratively add words from least significant to most */
688 while (result2 > result1) {
689 i1 = i2 = 0;
690 if (p1 > bi1)
691 i1 = * p1--;
692 if (p2 > bi2)
693 i2 = * p2--;
694 partialresult = i1 + i2 + carry;
695 carry = 0;
696 if (partialresult > USHRT_MAX) {
697 carry = 1;
698 partialresult -= (USHRT_MAX + 1);
699 }
700 * result2-- = (unsigned short) partialresult;
701 } /* while */
702 } /* add */
703 * result1 = (resultsize << 1) | sign;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
704 return biggishint_internal_trim(&result1);
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
705 }
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
706
707 /* biggishint_internal_bitsize */
708 /* Count how many bits a number uses (0-64), returns 1 + position of first 1 bit */
709 int
710 biggishint_internal_bitsize(unsigned long n)
711 {
712 int bitsize = 0;
713 for ( ; n; n >>= 1)
714 ++bitsize;
715 return bitsize;
716 }
717
718
719 /* biggishint_internal_clone */
720 unsigned short *
721 biggishint_internal_clone(unsigned short * bi1)
722 {
723 unsigned short clonebytes, * clone;
724 clonebytes = * bi1 & 0xfffffffe;
725 clone = (unsigned short *) malloc(clonebytes);
726 assert( clone != NULL );
727 memcpy(clone, bi1, clonebytes);
728 return clone;
729 }
730
731
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
732 /* biggishint_internal_comparemagnitude */
733 /* returns -1 if bi1<bi2, 0 if bi1==bi2, +1 if bi1>bi2 */
734 int biggishint_internal_comparemagnitude(unsigned short * bi1, unsigned short * bi2)
735 {
736 unsigned short * pi1data, * pi1, * pi2data, * pi2;
737 unsigned short i1, i2, bi1size, bi2size, loopcount;
738 int result=0;
739 /* This function could often be quicker by comparing the sizes of */
740 /* the two numbers, but that implies trusting the rest of the */
741 /* code to always trim leading zero words where possible. The */
742 /* test suite currently lacks the coverage required to enable */
743 /* that trust. */
744 bi1size = (* bi1 & 0xfffc) >> 1;
745 bi2size = (* bi2 & 0xfffc) >> 1;
746 /* the max number of comparisons is max(bi1size,bi2size)-1 */
747 loopcount = ((bi1size>bi2size) ? bi1size : bi2size) - 1;
748 pi1data = bi1 + 1;
749 pi2data = bi2 + 1;
750 pi1 = bi1 + bi1size - loopcount;
751 pi2 = bi2 + bi2size - loopcount;
752 while (result==0 && loopcount--) {
753 /* substitute leading zeroes for whichever number is shorter */
754 i1 = (pi1<pi1data) ? 0 : * pi1; ++pi1;
755 i2 = (pi2<pi2data) ? 0 : * pi2; ++pi2;
756 /* compare the two words from each biggishint */
757 result = (i1<i2) ? -1 : (i1>i2) ? 1 : 0;
758 }
759 return result;
760 }
761
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
762 /* biggishint_internal_shiftleft */
763 unsigned short *
764 biggishint_internal_shiftleft(unsigned short * bi1, unsigned int bitcount)
765 {
766 unsigned short bi1size, * result, * p1, * p2, carry;
767 unsigned int inputbitcount, resultbitcount, resultsize, inputloop;
768 unsigned int shiftleft, shiftright, inputword, resultword;
769 bi1size = (* bi1 & 0xfffc) >> 1;
770 /* Calculate the number of data bits needed for the result */
771 inputbitcount = biggishint_internal_bitsize(bi1[1]) + ((bi1size - 2) << 4);
772 resultbitcount = inputbitcount + bitcount;
773 assert( resultbitcount < 524272);
774 /* Calculate the total number of words to allocate for the result */
775 resultsize = 1 + ((resultbitcount + 15) >> 4);
776 result = (unsigned short *) calloc(resultsize, sizeof(short));
777 * result = resultsize << 1;
778 /* prepare initial values for the loop below */
779 shiftleft = bitcount & 0xf;
780 shiftright = 16 - shiftleft;
781 p1 = bi1 + 1;
782 p2 = result + 1;
783 inputword = * p1++;
784 inputloop = bi1size;
785 carry = inputword << shiftleft;
786 /* Check whether part of the first word of the input needs to */
787 /* carry over to the second word of the result */
788 if ( ((inputbitcount-1) & 0xf) > ((resultbitcount-1) & 0xf) ) {
789 /* Yes, so here store the bits that will not be carried */
790 resultword = inputword >> shiftright;
791 * p2++ = resultword;
792 --inputloop;
793 }
794 while (--inputloop) {
795 inputword = * p1++;
796 resultword = carry | (inputword >> shiftright);
797 * p2++ = resultword;
798 carry = inputword << shiftleft;
799 }
800 * p2++ = carry;
801 return result;
802 }
803
804
805 /* TODO: biggishint_internal_shiftright */
806 unsigned short *
807 biggishint_internal_shiftright(unsigned short * bi1, unsigned int bitcount)
808 {
809 unsigned short bi1size, * result;
810 bi1size = 2;
811 result = (unsigned short *) malloc(bi1size);
812 return result;
813 }
814
815
816 /* biggishint_internal_shortdivide */
817 /* Short division only (divisor <= 0xffff). */
818 /* Returns quotient in (* bi1), remainder in (* i2) */
819 void
820 biggishint_internal_shortdivide(unsigned short * bi1, unsigned short * i2)
821 {
822 unsigned short bi1size, * pi1, * pi2, divisor, remainder, hi, lo;
823 unsigned long partialdividend, partialquotient;
824 bi1size = (* bi1 & 0xfffc) >> 1;
825 divisor = * i2;
826 remainder = 0;
827 pi1 = bi1 + 1;
828 pi2 = bi1 + bi1size;
829 lo = 0;
830 while ( pi1 < pi2 ) {
831 hi = lo;
832 lo = * pi1;
833 partialdividend = ((unsigned long)hi << 16) | lo;
834 partialquotient = partialdividend / divisor;
835 remainder = partialdividend % divisor;
836 hi = partialquotient & 0xffff;
837 lo = remainder;
838 * pi1++ = hi;
839 }
840 * i2 = remainder;
841 }
842
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
843
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
844 /* biggishint_internal_shortmultiply */
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
845 void
846 biggishint_internal_shortmultiply(unsigned short ** bi1, unsigned short multiplier)
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
847 {
848 unsigned short bi1size, productsize, * product, * pi, * pp;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
849 unsigned long productcarry;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
850 if (multiplier == 0) {
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
851 * bi1 = realloc(* bi1, sizeof(short)<<1);
852 (* bi1)[0] = 4; (* bi1)[1] = 0;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
853 }
854 else {
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
855 if (multiplier != 1) {
856 /* TODO: avoid realloc if possible */
857 bi1size = (** bi1 & 0xfffc) >> 1;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
858 productsize = bi1size + 2; /* even number of words */
859 product = (unsigned short *) calloc(productsize, sizeof(short));
860 * product = productsize << 1;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
861 pi = * bi1 + bi1size - 1;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
862 pp = product + productsize - 1;
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
863 productcarry = 0;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
864 do {
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
865 productcarry += (* pi--) * (unsigned int)multiplier;
866 (* pp--) = (unsigned short) productcarry;
867 productcarry >>= 16;
868 } while ( pi > * bi1 );
869 assert( productcarry < 0xffffffff );
870 while (productcarry) {
871 (* pp--) = (unsigned short) productcarry;
872 productcarry >>= 16;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
873 }
98c307b @mberends [examples/biggishint.c] make biggishintDivide() handle biggish divisors
mberends authored
874 free(* bi1);
875 * bi1 = product;
876 biggishint_internal_trim(bi1);
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
877 }
878 }
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
879 }
880
881
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
882 /*
883 #include <stdio.h>
884 fprintf(stderr,"sign %d\n", sign);
885 */
886
887
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
888 /* biggishint_internal_trim */
889 /* If possible, remove leading zeroes from the front of the biggishint */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
890 /* Also remove the minus sign from -0 results */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
891 /* Note: it reallocates the data, so it may be at a new address. */
892 unsigned short *
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
893 biggishint_internal_trim(unsigned short ** pbi1)
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
894 {
895 /* For example, change this: */
896 /* +------+------+------+------+------+------+ */
897 /* | 000c | 0000 | 0000 | 0000 | 1234 | cdef | */
898 /* +------+------+------+------+------+------+ */
899 /* to this: */
900 /* +------+------+------+------+ */
901 /* | 0008 | 0000 | 1234 | cdef | */
902 /* +------+------+------+------+ */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
903 unsigned int sign;
904 unsigned short bi1size, newsize;
905 unsigned short * bi1, * pLeft, * pSearch, * pRight, * pAfterZeroes;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
906
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
907 bi1 = * pbi1;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
908 /* Count the number of contiguous leading zero words */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
909 bi1size = (* bi1 & 0xfffc) >> 1;
910 sign = * bi1 & 1;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
911 pLeft = bi1 + 1;
912 pSearch = bi1;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
913 pRight = bi1 + bi1size; /* just outside the biggishint */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
914 pAfterZeroes = pRight;
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
915 /* Try to set pSearch to the address of the first non zero word. */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
916 /* After this loop completes, pAfterZeroes either points to the */
917 /* first nonzero word, or to the first address after the biggishint. */
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
918 while (++pSearch < pAfterZeroes) /* note pAfterZeroes moves! */
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
919 if ( * pSearch )
920 pAfterZeroes = pSearch;
921 /* If there are leading words filled with zeroes, move the non */
922 /* zero words to the left to overwrite them */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
923 if (pAfterZeroes > pLeft) {
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
924 newsize = (pRight - pAfterZeroes + 2) & 0xfffe; /* always even */
925 if (newsize < bi1size) {
926 /* Trim the size of the memory allocation */
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
927 /* Bump the destination by 1 if the first non zero word */
928 /* was at an even subscript */
929 pLeft += (pAfterZeroes - bi1 + 1) & 1;
930 /* If the array was little endian, memmove would not happen */
931 memmove(pLeft, pAfterZeroes, (pRight - pAfterZeroes) << 1);
932 bi1 = realloc(bi1, newsize << 1);
933 * bi1 = (newsize << 1) | sign;
934 * pbi1 = bi1;
2790e3a @mberends [examples/biggishint] hex calc example in .pl6, many lib bugs fixed
mberends authored
935 }
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
936 }
09ffefe @mberends [examples/biggishint] small corrections and fix memory leaks
mberends authored
937 /* Convert the silly case of -0 into 0 */
938 if (* bi1 == 5 && bi1[1]==0) * bi1 = 4;
7329c5a @mberends [examples/biggishint] add a fairly big integer lib still under develo…
mberends authored
939 return bi1;
940 }
941
942
943 /* end of biggishint.c */
Something went wrong with that request. Please try again.