summaryrefslogtreecommitdiff
path: root/lisp/mp/mp.h
blob: 88f1b2490164baeda8fbbbfaabedb390d709f7d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
/*
 * Copyright (c) 2002 by The XFree86 Project, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *  
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Except as contained in this notice, the name of the XFree86 Project shall
 * not be used in advertising or otherwise to promote the sale, use or other
 * dealings in this Software without prior written authorization from the
 * XFree86 Project.
 *
 * Author: Paulo César Pereira de Andrade
 */

/* $XFree86: xc/programs/xedit/lisp/mp/mp.h,v 1.6 2003/01/12 03:55:51 tsi Exp $ */

#include <stdio.h>
#include <math.h>
#ifdef sun
#include <ieeefp.h>
#endif
#include <float.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include <string.h>

#ifndef __mp_h_
#define __mp_h_

#ifdef __GNUC__
#define INLINE __inline__
#else
#define INLINE /**/
#endif

/* this normally is better for multiplication and also
 * simplify addition loops putting the larger value first */
#define MP_SWAP(op1, op2, len1, len2) {	\
    BNS *top = op1;			\
    BNI tlen = len1;			\
					\
    op1 = op2;				\
    len1 = len2;			\
    op2 = top;				\
    len2 = tlen;			\
}

/*
 * At least this length to use Karatsuba multiplication method
 */
#define KARATSUBA		32

/*
 * At least this length to use Toom multiplication method
 */
#define TOOM			128

#if ULONG_MAX > 4294967295UL
  /* sizeof(long) == 8 and sizeof(int) == 4 */
# define BNI		unsigned long
# define BNS		unsigned int
# define MINSLONG	0x8000000000000000UL
# define CARRY		0x100000000
# define LMASK		0xffffffff00000000UL
# define SMASK		0x00000000ffffffffUL
# define BNIBITS	64
# define BNSBITS	32
# ifndef LONG64
#  define LONG64
# endif
#else
  /* sizeof(long) == 4 and sizeof(short) == 2 */
# define BNI		unsigned long
# define BNS		unsigned short
# define MINSLONG	0x80000000UL
# define CARRY		0x10000
# define LMASK		0xffff0000UL
# define SMASK		0x0000ffffUL
# define BNIBITS	32
# define BNSBITS	16
#endif

#ifdef MAX
#undef MAX
#endif
#define MAX(a, b)	((a) > (b) ? (a) : (b))

#ifdef MIN
#undef MIN
#endif
#define MIN(a, b)	((a) < (b) ? (a) : (b))

/*
 * Types
 */
typedef struct _mpi {
    unsigned int size : 31;
    unsigned int sign : 1;
    BNI alloc;
    BNS *digs;		/* LSF format */
} mpi;

typedef struct _mpr {
    mpi num;
    mpi den;
} mpr;

typedef void *(*mp_malloc_fun)(size_t);
typedef void *(*mp_calloc_fun)(size_t, size_t);
typedef void *(*mp_realloc_fun)(void*, size_t);
typedef void (*mp_free_fun)(void*);

/*
 * Prototypes
 */
/* GENERIC FUNCTIONS */
	/* memory allocation wrappers */
void *mp_malloc(size_t size);
void *mp_calloc(size_t nmemb, size_t size);
void *mp_realloc(void *pointer, size_t size);
void mp_free(void *pointer);
mp_malloc_fun mp_set_malloc(mp_malloc_fun);
mp_calloc_fun mp_set_calloc(mp_calloc_fun);
mp_realloc_fun mp_set_realloc(mp_realloc_fun);
mp_free_fun mp_set_free(mp_free_fun);

	/* adds op1 and op2, stores result in rop
	 * rop must pointer to at least len1 + len2 + 1 elements
	 * rop can be either op1 or op2 */
long mp_add(BNS *rop, BNS *op1, BNS *op2, BNI len1, BNI len2);

	/* subtracts op2 from op1, stores result in rop
	 * rop must pointer to at least len1 + len2 elements
	 * op1 must be >= op2
	 * rop can be either op1 or op2 */
long mp_sub(BNS *rop, BNS *op1, BNS *op2, BNI len1, BNI len2);

	/* shift op to the left shift bits
	 * rop must have enough storage for result
	 * rop can be op */
long mp_lshift(BNS *rop, BNS *op, BNI len, long shift);

	/* shift op to the right shift bits
	 * shift must be positive
	 * rop can be op */
long mp_rshift(BNS *rop, BNS *op, BNI len, long shift);

	/* use simple generic multiplication method
	 * rop cannot be the same as op1 or op2
	 * rop must be zeroed
	 * op1 can be op2 */
long mp_base_mul(BNS *rop, BNS *op1, BNS *op2, BNI len1, BNI len2);

	/* use Karatsuba method
	 * MIN(len1, len2) must be larger than (MAX(len1, len2) + 1) >> 1
	 * MAX(len1, len2) should be at least 2
	 * rop cannot be the same as op1 or op2
	 * rop must be zeroed
	 * op1 can be op2 */
long mp_karatsuba_mul(BNS *rop, BNS *op1, BNS *op2, BNI len1, BNI len2);

	/* use Toom method
	 * len1 / 3 should be equal to len2 / 3
	 * len1 / 3 should be at least 1
	 * rop cannot be the same as op1 or op2
	 * rop must be zeroed
	 * op1 can be op2 */
long mp_toom_mul(BNS *rop, BNS *op1, BNS *op2, BNI len1, BNI len2);

	/* chooses the available multiplication methods based on it's input
	 * rop must be a pointer to len1 + len2 elements
	 * rop cannot be the same as op1 or op2
	 * rop must be zeroed
	 * op1 can be op2 */
long mp_mul(BNS *rop, BNS *op1, BNS *op2, BNI len1, BNI len2);

/* INTEGER FUNCTIONS */
	/* initialize op and set it to 0 */
void mpi_init(mpi *op);

	/* clear memory associated to op */
void mpi_clear(mpi *op);

	/* set rop to the value of op */
void mpi_set(mpi *rop, mpi *op);

	/* set rop to the value of si */
void mpi_seti(mpi *rop, long si);

	/* set rop to the floor(fabs(d)) */
void mpi_setd(mpi *rop, double d);

	/* initialize rop to number representation in str in the given base.
	 * leading zeros are skipped.
	 * if sign present, it is processed.
	 * base must be in the range 2 to 36. */
void mpi_setstr(mpi *rop, char *str, int base);

	/* adds two mp integers */
void mpi_add(mpi *rop, mpi *op1, mpi *op2);

	/* adds op1 and op2 */
void mpi_addi(mpi *rop, mpi *op1, long op2);

	/* subtracts two mp integers */
void mpi_sub(mpi *rop, mpi *op1, mpi *op2);

	/* subtracts op2 from op1 */
void mpi_subi(mpi *rop, mpi *op1, long op2);

	/* multiply two mp integers */
void mpi_mul(mpi *rop, mpi *op1, mpi *op2);

	/* multiply op1 by op2 */
void mpi_muli(mpi *rop, mpi *op1, long op2);

	/* divides num by den and sets rop to result */
void mpi_div(mpi *rop, mpi *num, mpi *den);

	/* divides num by den and sets rop to the remainder */
void mpi_rem(mpi *rop, mpi *num, mpi *den);

	/* divides num by den, sets quotient to qrop and remainder to rrop
	 * qrop is truncated towards zero.
	 * qrop and rrop are optional
	 * qrop and rrop cannot be the same variable */
void mpi_divqr(mpi *qrop, mpi *rrop, mpi *num, mpi *den);

	/* divides num by then and stores result in rop */
void mpi_divi(mpi *rop, mpi *num, long den);

	/* divides num by den and returns remainder */
long mpi_remi(mpi *num, long den);

	/* divides num by den
	 * stores quotient in qrop and returns remainder */
long mpi_divqri(mpi *qrop, mpi *num, long den);

	/* sets rop to num modulo den */
void mpi_mod(mpi *rop, mpi *num, mpi *den);

	/* returns num modulo den */
long mpi_modi(mpi *num, long den);

	/* sets rop to the greatest common divisor of num and den
	 * result is always positive */
void mpi_gcd(mpi *rop, mpi *num, mpi *den);

	/* sets rop to the least common multiple of num and den
	 * result is always positive */
void mpi_lcm(mpi *rop, mpi *num, mpi *den);

	/* sets rop to op raised to exp */
void mpi_pow(mpi *rop, mpi *op, unsigned long exp);

	/* sets rop to the integer part of the nth root of op.
	 * returns 1 if result is exact, 0 otherwise */
int mpi_root(mpi *rop, mpi *op, unsigned long nth);

	/* sets rop to the integer part of the square root of op.
	 * returns 1 if result is exact, 0 otherwise */
int mpi_sqrt(mpi *rop, mpi *op);

	/* bit shift, left if shift positive, right if negative
	 * a fast way to multiply and divide by powers of two */
void mpi_ash(mpi *rop, mpi *op, long shift);

	/* sets rop to op1 logand op2 */
void mpi_and(mpi *rop, mpi *op1, mpi *op2);

	/* sets rop to op1 logior op2 */
void mpi_ior(mpi *rop, mpi *op1, mpi *op2);

	/* sets rop to op1 logxor op2 */
void mpi_xor(mpi *rop, mpi *op1, mpi *op2);

	/* sets rop to one's complement of op */
void mpi_com(mpi *rop, mpi *op);

	/* sets rop to -op */
void mpi_neg(mpi *rop, mpi *op);

	/* sets rop to the absolute value of op */
void mpi_abs(mpi *rop, mpi *op);

	/* compares op1 and op2
	 * returns >0 if op1 > op2, 0 if op1 = op2, and  <0 if op1 < op2 */
int mpi_cmp(mpi *op1, mpi *op2);

	/* mpi_cmp with a long integer operand */
int mpi_cmpi(mpi *op1, long op2);

	/* compares absolute value of op1 and op2
	 * returns >0 if abs(op1) > abs(op2), 0 if abs(op1) = abs(op2),
	 * and  <0 if abs(op1) < abs(op2) */
int mpi_cmpabs(mpi *op1, mpi *op2);

	/* mpi_cmpabs with a long integer operand */
int mpi_cmpabsi(mpi *op1, long op2);

	/* returns 1 if op1 > 0, 0 if op1 = 0, and  -1 if op1 < 0 */
int mpi_sgn(mpi *op);

	/* fastly swaps contents of op1 and op2 */
void mpi_swap(mpi *op1, mpi *op2);

	/* returns 1 if op fits in a signed long int, 0 otherwise */
int mpi_fiti(mpi *op);

	/* converts mp integer to long int
	 * to know if the value will fit, call mpi_fiti */
long mpi_geti(mpi *op);

	/* convert mp integer to double */
double mpi_getd(mpi *op);

	/* returns exact number of characters to represent mp integer
	 * in given base, excluding sign and ending null character.
	 * base must be in the range 2 to 36 */
unsigned long mpi_getsize(mpi *op, int base);

	/* returns pointer to string with representation of mp integer
	 * if str is not NULL, it must have enough space to store integer
	 * representation, if NULL a newly allocated string is returned.
	 * base must be in the range 2 to 36 */
char *mpi_getstr(char *str, mpi *op, int base);

/* RATIO FUNCTIONS */
#define mpr_num(op)	(&((op)->num))
#define mpr_den(op)	(&((op)->den))

	/* initialize op and set it to 0/1 */
void mpr_init(mpr *op);

	/* clear memory associated to op */
void mpr_clear(mpr *op);

	/* set rop to the value of op */
void mpr_set(mpr *rop, mpr *op);

	/* set rop to num/den */
void mpr_seti(mpr *rop, long num, long den);

	/* set rop to the value of d */
void mpr_setd(mpr *rop, double d);

	/* initialize rop to number representation in str in the given base.
	 * leading zeros are skipped.
	 * if sign present, it is processed.
	 * base must be in the range 2 to 36. */
void mpr_setstr(mpr *rop, char *str, int base);

	/* remove common factors of op */
void mpr_canonicalize(mpr *op);

	/* adds two mp rationals */
void mpr_add(mpr *rop, mpr *op1, mpr *op2);

	/* adds op1 and op2 */
void mpr_addi(mpr *rop, mpr *op1, long op2);

	/* subtracts two mp rationals */
void mpr_sub(mpr *rop, mpr *op1, mpr *op2);

	/* subtracts op2 from op1 */
void mpr_subi(mpr *rop, mpr *op1, long op2);

	/* multiply two mp rationals */
void mpr_mul(mpr *rop, mpr *op1, mpr *op2);

	/* multiply op1 by op2 */
void mpr_muli(mpr *rop, mpr *op1, long op2);

	/* divide two mp rationals */
void mpr_div(mpr *rop, mpr *op1, mpr *op2);

	/* divides op1 by op2 */
void mpr_divi(mpr *rop, mpr *op1, long op2);

	/* sets rop to 1/op */
void mpr_inv(mpr *rop, mpr *op);

	/* sets rop to -op */
void mpr_neg(mpr *rop, mpr *op);

	/* sets rop to the absolute value of op */
void mpr_abs(mpr *rop, mpr *op);

	/* compares op1 and op2
	 * returns >0 if op1 > op2, 0 if op1 = op2, and  <0 if op1 < op2 */
int mpr_cmp(mpr *op1, mpr *op2);

	/* mpr_cmp with a long integer operand */
int mpr_cmpi(mpr *op1, long op2);

	/* compares absolute value of op1 and op2
	 * returns >0 if abs(op1) > abs(op2), 0 if abs(op1) = abs(op2),
	 * and  <0 if abs(op1) < abs(op2) */
int mpr_cmpabs(mpr *op1, mpr *op2);

	/* mpr_cmpabs with a long integer operand */
int mpr_cmpabsi(mpr *op1, long op2);

	/* fastly swaps contents of op1 and op2 */
void mpr_swap(mpr *op1, mpr *op2);

	/* returns 1 if op fits in a signed long int, 0 otherwise */
int mpr_fiti(mpr *op);

	/* convert mp rational to double */
double mpr_getd(mpr *op);

	/* returns pointer to string with representation of mp rational
	 * if str is not NULL, it must have enough space to store rational
	 * representation, if NULL a newly allocated string is returned.
	 * base must be in the range 2 to 36 */
char *mpr_getstr(char *str, mpr *op, int base);

#endif /* __mp_h_ */