srawlins-gmp 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/ext/gmpz.h ADDED
@@ -0,0 +1,833 @@
1
+ /*
2
+ * gmpz.h
3
+ *
4
+ * This file contains GMP::Z method definitions.
5
+ */
6
+
7
+ /*
8
+ * call-seq: +(other)
9
+ *
10
+ * Adds this GMP::Z to other. Other can be
11
+ * * GMP::Z
12
+ * * Fixnum
13
+ * * GMP::Q
14
+ * * GMP::F
15
+ * * Bignum
16
+ */
17
+ static VALUE r_gmpz_add(VALUE self, VALUE arg)
18
+ {
19
+ MP_INT *self_val, *arg_val, *res_val;
20
+ VALUE res;
21
+
22
+ mpz_get_struct(self,self_val);
23
+
24
+ if (GMPZ_P(arg)) {
25
+ mpz_get_struct(arg,arg_val);
26
+ mpz_make_struct_init(res, res_val);
27
+ mpz_add (res_val, self_val, arg_val);
28
+ } else if (FIXNUM_P(arg)) {
29
+ mpz_make_struct_init(res, res_val);
30
+ if (FIX2INT(arg) > 0)
31
+ mpz_add_ui (res_val, self_val, FIX2INT(arg));
32
+ else
33
+ mpz_sub_ui (res_val, self_val, -FIX2INT(arg));
34
+ } else if (GMPQ_P(arg)) {
35
+ return r_gmpq_add(arg, self);
36
+ } else if (GMPF_P(arg)) {
37
+ return r_gmpf_add(arg, self);
38
+ } else if (BIGNUM_P(arg)) {
39
+ mpz_make_struct_init(res, res_val);
40
+ mpz_init (res_val);
41
+ mpz_set_bignum (res_val, arg);
42
+ mpz_add (res_val, res_val, self_val);
43
+ } else {
44
+ typeerror (ZQFXB);
45
+ }
46
+ return res;
47
+ }
48
+
49
+ static VALUE r_gmpz_add_self(VALUE self, VALUE arg)
50
+ {
51
+ MP_INT *self_val, *arg_val;
52
+
53
+ mpz_get_struct(self,self_val);
54
+
55
+ if (GMPZ_P(arg)) {
56
+ mpz_get_struct(arg,arg_val);
57
+ mpz_add (self_val, self_val, arg_val);
58
+ } else if (FIXNUM_P(arg)) {
59
+ if (FIX2INT(arg) > 0)
60
+ mpz_add_ui (self_val, self_val, FIX2INT(arg));
61
+ else
62
+ mpz_sub_ui (self_val, self_val, -FIX2INT(arg));
63
+ } else if (BIGNUM_P(arg)) {
64
+ mpz_temp_from_bignum (arg_val, arg);
65
+ mpz_add (self_val, self_val, arg_val);
66
+ mpz_temp_free (arg_val);
67
+ } else {
68
+ typeerror (ZXB);
69
+ }
70
+ return Qnil;
71
+ }
72
+
73
+ static VALUE r_gmpz_sub(VALUE self, VALUE arg)
74
+ {
75
+ MP_RAT *res_val_q, *arg_val_q;
76
+ MP_INT *self_val, *arg_val, *res_val;
77
+ MP_FLOAT *arg_val_f, *res_val_f;
78
+ VALUE res;
79
+ unsigned long prec;
80
+
81
+ mpz_get_struct(self,self_val);
82
+
83
+ if (GMPZ_P(arg)) {
84
+ mpz_make_struct_init(res, res_val);
85
+ mpz_get_struct(arg,arg_val);
86
+ mpz_sub (res_val, self_val, arg_val);
87
+ } else if (FIXNUM_P(arg)) {
88
+ mpz_make_struct_init(res, res_val);
89
+ if (FIX2INT(arg) > 0)
90
+ mpz_sub_ui (res_val, self_val, FIX2INT(arg));
91
+ else
92
+ mpz_add_ui (res_val, self_val, -FIX2INT(arg));
93
+ } else if (GMPQ_P(arg)) {
94
+ mpq_make_struct_init(res, res_val_q);
95
+ mpq_get_struct(arg,arg_val_q);
96
+ mpz_set (mpq_denref(res_val_q), mpq_denref(arg_val_q));
97
+ mpz_mul (mpq_numref(res_val_q), mpq_denref(arg_val_q), self_val);
98
+ mpz_sub (mpq_numref(res_val_q), mpq_numref(res_val_q), mpq_numref(arg_val_q));
99
+ } else if (GMPF_P(arg)) {
100
+ mpf_get_struct_prec (arg, arg_val_f, prec);
101
+ mpf_make_struct_init(res, res_val_f, prec);
102
+ mpf_set_z (res_val_f, self_val);
103
+ mpf_sub (res_val_f, res_val_f, arg_val_f);
104
+ } else if (BIGNUM_P(arg)) {
105
+ mpz_make_struct_init(res, res_val);
106
+ mpz_set_bignum (res_val, arg);
107
+ mpz_sub (res_val, self_val, res_val);
108
+ } else {
109
+ typeerror (ZQFXB);
110
+ }
111
+ return res;
112
+ }
113
+
114
+ static VALUE r_gmpz_sub_self(VALUE self, VALUE arg)
115
+ {
116
+ MP_INT *self_val, *arg_val;
117
+
118
+ mpz_get_struct(self,self_val);
119
+
120
+ if (GMPZ_P(arg)) {
121
+ mpz_get_struct(arg, arg_val);
122
+ mpz_sub (self_val, self_val, arg_val);
123
+ } else if (FIXNUM_P(arg)) {
124
+ if (FIX2INT(arg) > 0)
125
+ mpz_sub_ui (self_val, self_val, FIX2INT(arg));
126
+ else
127
+ mpz_add_ui (self_val, self_val, -FIX2INT(arg));
128
+ } else if (BIGNUM_P(arg)) {
129
+ mpz_temp_from_bignum(arg_val, arg);
130
+ mpz_sub (self_val, self_val, arg_val);
131
+ mpz_temp_free (arg_val);
132
+ } else {
133
+ typeerror (ZXB);
134
+ }
135
+ return Qnil;
136
+ }
137
+
138
+ static VALUE r_gmpz_mul(VALUE self, VALUE arg)
139
+ {
140
+ MP_INT *self_val, *arg_val, *res_val;
141
+ VALUE res;
142
+
143
+ mpz_get_struct(self,self_val);
144
+
145
+ if (GMPZ_P(arg)) {
146
+ mpz_make_struct_init(res, res_val);
147
+ mpz_get_struct(arg,arg_val);
148
+ mpz_mul (res_val, self_val, arg_val);
149
+ } else if (FIXNUM_P(arg)) {
150
+ mpz_make_struct_init(res, res_val);
151
+ mpz_mul_si (res_val, self_val, FIX2INT(arg));
152
+ } else if (GMPQ_P(arg)) {
153
+ return r_gmpq_mul(arg, self);
154
+ } else if (GMPF_P(arg)) {
155
+ return r_gmpf_mul(arg, self);
156
+ } else if (BIGNUM_P(arg)) {
157
+ mpz_make_struct_init(res, res_val);
158
+ mpz_set_bignum (res_val, arg);
159
+ mpz_mul (res_val, res_val, self_val);
160
+ } else {
161
+ typeerror (ZQFXB);
162
+ }
163
+ return res;
164
+ }
165
+
166
+ static VALUE r_gmpz_div(VALUE self, VALUE arg)
167
+ {
168
+ MP_INT *self_val, *arg_val_z, *tmp_z;
169
+ MP_RAT *arg_val_q, *res_val_q;
170
+ MP_FLOAT *arg_val_f, *res_val_f;
171
+ VALUE res;
172
+ unsigned int prec;
173
+
174
+ mpz_get_struct(self,self_val);
175
+
176
+ if (GMPZ_P(arg)) {
177
+ mpz_get_struct(arg, arg_val_z);
178
+ if (mpz_cmp_ui(arg_val_z, 0) == 0)
179
+ rb_raise (rb_eZeroDivError, "divided by 0");
180
+ mpq_make_struct_init(res, res_val_q);
181
+ mpq_set_num (res_val_q, self_val);
182
+ mpq_set_den (res_val_q, arg_val_z);
183
+ mpq_canonicalize (res_val_q);
184
+ } else if (FIXNUM_P(arg)) {
185
+ if (FIX2INT(arg) == 0)
186
+ rb_raise (rb_eZeroDivError, "divided by 0");
187
+ mpq_make_struct_init(res, res_val_q);
188
+ mpq_set_num (res_val_q, self_val);
189
+ mpz_set_ui (mpq_denref(res_val_q), FIX2INT(arg));
190
+ mpq_canonicalize (res_val_q);
191
+ } else if (GMPQ_P(arg)) {
192
+ mpq_get_struct(arg, arg_val_q);
193
+ if (mpz_cmp_ui(mpq_numref(arg_val_q), 0) == 0)
194
+ rb_raise (rb_eZeroDivError, "divided by 0");
195
+ mpz_temp_init(tmp_z);
196
+ mpq_make_struct_init(res, res_val_q);
197
+ mpz_gcd (tmp_z, mpq_numref(arg_val_q), self_val);
198
+ mpz_divexact (mpq_numref(res_val_q), self_val, tmp_z);
199
+ mpz_divexact (mpq_denref(res_val_q), mpq_numref(arg_val_q), tmp_z);
200
+ mpz_mul (mpq_numref(res_val_q), mpq_numref(res_val_q), mpq_denref(arg_val_q));
201
+ mpz_temp_free(tmp_z);
202
+ } else if (GMPF_P(arg)) {
203
+ mpf_get_struct_prec (arg, arg_val_f, prec);
204
+ mpf_make_struct_init(res, res_val_f, prec);
205
+ mpf_set_z (res_val_f, self_val);
206
+ mpf_div (res_val_f, res_val_f, arg_val_f);
207
+ } else if (BIGNUM_P(arg)) {
208
+ mpq_make_struct_init(res, res_val_q);
209
+ mpz_set_bignum (mpq_denref(res_val_q), arg);
210
+ if (mpz_cmp_ui(mpq_denref(res_val_q), 0) == 0)
211
+ rb_raise (rb_eZeroDivError, "divided by 0");
212
+ mpq_set_num (res_val_q, self_val);
213
+ mpq_canonicalize (res_val_q);
214
+ } else {
215
+ typeerror (ZQFXB);
216
+ }
217
+ return res;
218
+ }
219
+
220
+ static VALUE r_gmpz_setbit(VALUE self, VALUE bitnr, VALUE set_to)
221
+ {
222
+ MP_INT *self_val;
223
+ int bitnr_val;
224
+
225
+ mpz_get_struct(self, self_val);
226
+
227
+ if (FIXNUM_P(bitnr)) {
228
+ bitnr_val = FIX2INT (bitnr);
229
+ } else {
230
+ typeerror_as(X, "index");
231
+ }
232
+ if (RTEST(set_to)) {
233
+ mpz_setbit (self_val, bitnr_val);
234
+ } else {
235
+ mpz_clrbit (self_val, bitnr_val);
236
+ }
237
+ return Qnil;
238
+ }
239
+
240
+ static VALUE r_gmpz_getbit(VALUE self, VALUE bitnr)
241
+ {
242
+ MP_INT *self_val;
243
+ int bitnr_val;
244
+ mpz_get_struct(self, self_val);
245
+ if (FIXNUM_P(bitnr)) {
246
+ bitnr_val = FIX2INT (bitnr);
247
+ } else {
248
+ typeerror_as(X, "index");
249
+ }
250
+ return mpz_tstbit(self_val, bitnr_val)?Qtrue:Qfalse;
251
+ }
252
+
253
+ static VALUE r_gmpz_scan0(VALUE self, VALUE bitnr)
254
+ {
255
+ MP_INT *self_val;
256
+ int bitnr_val;
257
+ mpz_get_struct(self, self_val);
258
+ if (FIXNUM_P(bitnr)) {
259
+ bitnr_val = FIX2INT (bitnr);
260
+ } else {
261
+ typeerror_as(X, "index");
262
+ }
263
+ return INT2FIX(mpz_scan0(self_val, bitnr_val));
264
+ }
265
+
266
+ static VALUE r_gmpz_scan1(VALUE self, VALUE bitnr)
267
+ {
268
+ MP_INT *self_val;
269
+ int bitnr_val;
270
+
271
+ mpz_get_struct(self, self_val);
272
+
273
+ if (FIXNUM_P(bitnr)) {
274
+ bitnr_val = FIX2INT (bitnr);
275
+ } else {
276
+ typeerror_as(X, "index");
277
+ }
278
+
279
+ return INT2FIX(mpz_scan1(self_val, bitnr_val));
280
+ }
281
+
282
+ #define DEFUN_INT_COND_P(fname,mpz_fname) \
283
+ static VALUE r_gmpz_##fname(VALUE self) \
284
+ { \
285
+ MP_INT *self_val; \
286
+ mpz_get_struct(self, self_val); \
287
+ return mpz_fname(self_val)?Qtrue:Qfalse; \
288
+ }
289
+
290
+ DEFUN_INT_COND_P(is_even,mpz_even_p)
291
+ DEFUN_INT_COND_P(is_odd,mpz_odd_p)
292
+ DEFUN_INT_COND_P(is_square,mpz_perfect_square_p)
293
+ DEFUN_INT_COND_P(is_power,mpz_perfect_power_p)
294
+
295
+ static VALUE r_gmpz_sgn(VALUE self)
296
+ {
297
+ MP_INT *self_val;
298
+ mpz_get_struct(self, self_val);
299
+ return INT2FIX(mpz_sgn(self_val));
300
+ }
301
+
302
+ static VALUE r_gmpz_powm(VALUE self, VALUE exp, VALUE mod)
303
+ {
304
+ MP_INT *self_val, *res_val, *mod_val, *exp_val;
305
+ VALUE res;
306
+ int free_mod_val = 0;
307
+
308
+ if (GMPZ_P(mod)) {
309
+ mpz_get_struct(mod, mod_val);
310
+ if (mpz_sgn(mod_val) <= 0) {
311
+ rb_raise (rb_eRangeError, "modulus must be positive");
312
+ }
313
+ } else if (FIXNUM_P(mod)) {
314
+ if (FIX2INT(mod) <= 0) {
315
+ rb_raise (rb_eRangeError, "modulus must be positive");
316
+ }
317
+ mpz_temp_alloc (mod_val);
318
+ mpz_init_set_ui(mod_val, FIX2INT(mod));
319
+ free_mod_val = 1;
320
+ } else if (BIGNUM_P(mod)) {
321
+ mpz_temp_from_bignum (mod_val, mod);
322
+ if (mpz_sgn(mod_val) <= 0) {
323
+ mpz_temp_free(mod_val);
324
+ rb_raise (rb_eRangeError, "modulus must be positive");
325
+ }
326
+ free_mod_val = 1;
327
+ } else {
328
+ typeerror_as (ZXB, "modulus");
329
+ }
330
+ mpz_make_struct_init(res, res_val);
331
+ mpz_get_struct(self, self_val);
332
+
333
+ if (GMPZ_P(exp)) {
334
+ mpz_get_struct(exp, exp_val);
335
+ if (mpz_sgn(mod_val) < 0) {
336
+ rb_raise (rb_eRangeError, "exponent must be nonnegative");
337
+ }
338
+ mpz_powm (res_val, self_val, exp_val, mod_val);
339
+ } else if (FIXNUM_P(exp)) {
340
+ if (FIX2INT(exp) < 0)
341
+ {
342
+ if (free_mod_val)
343
+ mpz_temp_free(mod_val);
344
+ rb_raise (rb_eRangeError, "exponent must be nonnegative");
345
+ }
346
+ mpz_powm_ui (res_val, self_val, FIX2INT(exp), mod_val);
347
+ } else if (BIGNUM_P(exp)) {
348
+ mpz_temp_from_bignum (exp_val, exp);
349
+ mpz_powm (res_val, self_val, exp_val, mod_val);
350
+ mpz_temp_free (exp_val);
351
+ } else {
352
+ if (free_mod_val)
353
+ mpz_temp_free(mod_val);
354
+ typeerror_as (ZXB, "exponent");
355
+ }
356
+ if (free_mod_val)
357
+ mpz_temp_free(mod_val);
358
+ return res;
359
+ }
360
+
361
+ static VALUE r_gmpz_swap(VALUE self, VALUE arg)
362
+ {
363
+ MP_INT *self_val, *arg_val;
364
+ if (!GMPZ_P(arg)) {
365
+ rb_raise(rb_eTypeError, "Can't swap GMP::Z with object of other class");
366
+ }
367
+ mpz_get_struct(self, self_val);
368
+ mpz_get_struct(arg, arg_val);
369
+ mpz_swap(self_val,arg_val);
370
+ return Qnil;
371
+ }
372
+
373
+
374
+ #define DEFUN_INT_F_UL(fname,mpz_fname,argname) \
375
+ static VALUE r_gmpz_##fname(VALUE self, VALUE exp) \
376
+ { \
377
+ MP_INT *self_val, *res_val; \
378
+ VALUE res; \
379
+ unsigned long exp_val; \
380
+ \
381
+ if (FIXNUM_P(exp)) { \
382
+ if (FIX2INT (exp) < 0) \
383
+ rb_raise (rb_eRangeError, argname " out of range"); \
384
+ exp_val = FIX2INT (exp); \
385
+ } else if (GMPZ_P(exp)) {\
386
+ mpz_get_struct (exp, res_val); \
387
+ if (!mpz_fits_ulong_p (res_val)) \
388
+ rb_raise (rb_eRangeError, argname " out of range"); \
389
+ exp_val = mpz_get_ui (res_val); \
390
+ if (exp_val == 0) \
391
+ rb_raise (rb_eRangeError, argname " out of range"); \
392
+ } else { \
393
+ typeerror_as (ZX, argname); \
394
+ } \
395
+ \
396
+ mpz_make_struct_init(res, res_val); \
397
+ mpz_get_struct(self, self_val); \
398
+ mpz_fname(res_val, self_val, exp_val); \
399
+ \
400
+ return res; \
401
+ }
402
+
403
+ DEFUN_INT_F_UL(pow,mpz_pow_ui,"exponent")
404
+ DEFUN_INT_F_UL(shl,mpz_mul_2exp,"shift size")
405
+ DEFUN_INT_F_UL(fshr,mpz_fdiv_q_2exp,"shift size")
406
+ DEFUN_INT_F_UL(tshr,mpz_tdiv_q_2exp,"shift size")
407
+ DEFUN_INT_F_UL(fshrm,mpz_fdiv_r_2exp,"mark size")
408
+ DEFUN_INT_F_UL(tshrm,mpz_tdiv_r_2exp,"mark size")
409
+ DEFUN_INT_F_UL(root,mpz_root,"root number")
410
+
411
+ static int mpz_cmp_value (MP_INT *OP, VALUE arg)
412
+ {
413
+ MP_RAT *arg_val_q;
414
+ MP_INT *arg_val_z;
415
+ int res;
416
+
417
+ if (GMPZ_P(arg)) {
418
+ mpz_get_struct(arg,arg_val_z);
419
+ return mpz_cmp (OP,arg_val_z);
420
+ } else if (FIXNUM_P(arg)) {
421
+ return mpz_cmp_si (OP, FIX2INT(arg));
422
+ } else if (GMPQ_P(arg)) {
423
+ mpq_get_struct(arg,arg_val_q);
424
+ mpz_temp_alloc (arg_val_z);
425
+ mpz_init(arg_val_z);
426
+ mpz_mul(arg_val_z, OP, mpq_denref(arg_val_q));
427
+ res = mpz_cmp (arg_val_z, mpq_numref(arg_val_q));
428
+ mpz_temp_free(arg_val_z);
429
+ return res;
430
+ } else if (GMPF_P(arg)) {
431
+ not_yet;
432
+ } else if (BIGNUM_P(arg)) {
433
+ mpz_temp_from_bignum (arg_val_z, arg);
434
+ res = mpz_cmp (OP, arg_val_z);
435
+ mpz_temp_free(arg_val_z);
436
+ return res;
437
+ } else {
438
+ typeerror_as (ZQFXB, "exponent");
439
+ }
440
+ }
441
+
442
+ static VALUE r_gmpz_eq(VALUE self, VALUE arg)
443
+ {
444
+ MP_INT *self_val, *arg_val_z;
445
+ MP_RAT *arg_val_q;
446
+
447
+ mpz_get_struct (self, self_val);
448
+ if (GMPZ_P(arg)) {
449
+ mpz_get_struct(arg, arg_val_z);
450
+ return (mpz_cmp (self_val, arg_val_z)==0) ? Qtrue : Qfalse;
451
+ } else if (FIXNUM_P(arg)) {
452
+ return (mpz_cmp_si (self_val, FIX2INT(arg))==0) ? Qtrue : Qfalse;
453
+ } else if (GMPQ_P(arg)) {
454
+ mpq_get_struct(arg, arg_val_q);
455
+ if (mpz_cmp_ui(mpq_denref(arg_val_q), 1)==0)
456
+ return Qfalse;
457
+ return (mpz_cmp (self_val, mpq_numref(arg_val_q))==0) ? Qtrue : Qfalse;
458
+ } else if (BIGNUM_P(arg)) {
459
+ mpz_temp_from_bignum(arg_val_z, arg);
460
+ if (mpz_cmp (self_val, arg_val_z)==0) {
461
+ mpz_temp_free(arg_val_z);
462
+ return Qtrue;
463
+ } else {
464
+ mpz_temp_free(arg_val_z);
465
+ return Qfalse;
466
+ }
467
+ } else {
468
+ return Qfalse;
469
+ }
470
+ }
471
+
472
+ static VALUE r_gmpz_cmp(VALUE self, VALUE arg)
473
+ {
474
+ MP_INT *self_val;
475
+ int res;
476
+ mpz_get_struct (self,self_val);
477
+ res = mpz_cmp_value(self_val, arg);
478
+ if (res > 0)
479
+ return INT2FIX(1);
480
+ else if (res == 0)
481
+ return INT2FIX(0);
482
+ else
483
+ return INT2FIX(-1);
484
+ }
485
+
486
+ #define DEFUN_INT_CMP(name,CMP_OP) \
487
+ static VALUE r_gmpz_cmp_##name(VALUE self, VALUE arg) \
488
+ { \
489
+ MP_INT *self_val; \
490
+ mpz_get_struct (self,self_val); \
491
+ return (mpz_cmp_value(self_val, arg) CMP_OP 0)?Qtrue:Qfalse; \
492
+ }
493
+
494
+ DEFUN_INT_CMP(lt,<)
495
+ DEFUN_INT_CMP(le,<=)
496
+ DEFUN_INT_CMP(gt,>)
497
+ DEFUN_INT_CMP(ge,>=)
498
+
499
+ #define DEFUN_INT_DIV(fname,gmp_fname) \
500
+ static VALUE r_gmpz_##fname(VALUE self, VALUE arg) \
501
+ { \
502
+ MP_INT *self_val, *arg_val, *res_val; \
503
+ VALUE res; \
504
+ int arg_val_i; \
505
+ \
506
+ mpz_get_struct(self, self_val); \
507
+ mpz_make_struct_init(res, res_val); \
508
+ \
509
+ if (GMPZ_P(arg)) { \
510
+ mpz_get_struct(arg,arg_val); \
511
+ if (mpz_cmp_ui(arg_val, 0) == 0) \
512
+ rb_raise (rb_eZeroDivError, "divided by 0"); \
513
+ gmp_fname (res_val, self_val, arg_val); \
514
+ } else if (FIXNUM_P(arg)) { \
515
+ arg_val_i = FIX2INT(arg); \
516
+ if (arg_val_i > 0) { \
517
+ gmp_fname##_ui (res_val, self_val, arg_val_i); \
518
+ } else if (arg_val_i == 0) { \
519
+ rb_raise (rb_eZeroDivError, "divided by 0"); \
520
+ } else { \
521
+ mpz_neg (res_val, self_val); \
522
+ gmp_fname##_ui (res_val, self_val, -arg_val_i); \
523
+ } \
524
+ } else if (BIGNUM_P(arg)) { \
525
+ mpz_set_bignum (res_val, arg); \
526
+ if (mpz_cmp_ui(res_val, 0) == 0) \
527
+ rb_raise (rb_eZeroDivError, "divided by 0"); \
528
+ gmp_fname (res_val, self_val, res_val); \
529
+ } else { \
530
+ typeerror(ZXB); \
531
+ } \
532
+ return res; \
533
+ }
534
+
535
+ DEFUN_INT_DIV(tdiv, mpz_tdiv_q)
536
+ DEFUN_INT_DIV(tmod, mpz_tdiv_r)
537
+ DEFUN_INT_DIV(fdiv, mpz_fdiv_q)
538
+ DEFUN_INT_DIV(fmod, mpz_fdiv_r)
539
+ DEFUN_INT_DIV(cdiv, mpz_cdiv_q)
540
+ DEFUN_INT_DIV(cmod, mpz_cdiv_r)
541
+
542
+ #define DEFUN_INT2INT(fname,mpz_fname) \
543
+ static VALUE r_gmpz_##fname(VALUE self) \
544
+ { \
545
+ MP_INT *self_val, *res_val; \
546
+ VALUE res; \
547
+ mpz_get_struct(self, self_val); \
548
+ mpz_make_struct_init(res, res_val); \
549
+ mpz_fname(res_val, self_val); \
550
+ return res; \
551
+ } \
552
+ \
553
+ static VALUE r_gmpz_##fname##_self(VALUE self) \
554
+ { \
555
+ MP_INT *self_val; \
556
+ mpz_get_struct(self, self_val); \
557
+ mpz_fname(self_val, self_val); \
558
+ return Qnil; \
559
+ }
560
+
561
+ DEFUN_INT2INT(abs, mpz_abs)
562
+ DEFUN_INT2INT(neg, mpz_neg)
563
+ DEFUN_INT2INT(com, mpz_com)
564
+ DEFUN_INT2INT(sqrt, mpz_sqrt)
565
+ DEFUN_INT2INT(nextprime, mpz_nextprime)
566
+
567
+ /*
568
+ * call-seq: probab_prime_p(reps)
569
+ *
570
+ * Determine whether n is prime. Return 2 if n is definitely prime, return 1 if
571
+ * n is probably prime (without being certain), or return 0 if n is definitely
572
+ * composite.
573
+ *
574
+ * This function does some trial divisions, then some Miller-Rabin
575
+ * probabilistic primality tests. reps controls how many such tests are done, 5
576
+ * to 10 is a reasonable number, more will reduce the chances of a composite
577
+ * being returned as �probably prime�.
578
+ *
579
+ * Miller-Rabin and similar tests can be more properly called compositeness
580
+ * tests. Numbers which fail are known to be composite but those which pass
581
+ * might be prime or might be composite. Only a few composites pass, hence
582
+ * those which pass are considered probably prime.
583
+ */
584
+ static VALUE r_gmpz_is_probab_prime(int argc, VALUE* argv, VALUE self)
585
+ {
586
+ MP_INT *self_val;
587
+ int reps_val;
588
+ VALUE reps;
589
+ mpz_get_struct(self, self_val);
590
+ rb_scan_args(argc, argv, "01", &reps);
591
+ if(NIL_P(reps)){
592
+ reps = INT2FIX(5);
593
+ }
594
+ if (FIXNUM_P(reps)) {
595
+ reps_val = FIX2INT (reps);
596
+ } else {
597
+ typeerror_as(X, "reps");
598
+ }
599
+ return INT2FIX(mpz_probab_prime_p(self_val, reps_val));
600
+ }
601
+
602
+ static VALUE r_gmpz_popcount(VALUE self)
603
+ {
604
+ MP_INT *self_val;
605
+ mpz_get_struct(self, self_val);
606
+ return INT2FIX(mpz_popcount(self_val));
607
+ }
608
+
609
+ static VALUE r_gmpz_jacobi(VALUE self)
610
+ {
611
+ MP_INT *self_val, *res_val;
612
+ VALUE res;
613
+ mpz_get_struct(self, self_val);
614
+ if (mpz_sgn(self_val) != 1)
615
+ rb_raise(rb_eRangeError, "you can take jacobi symbol only of positive value");
616
+ if (mpz_even_p(self_val))
617
+ rb_raise(rb_eRangeError, "you can't take jacobi symbol of even value");
618
+ mpz_make_struct_init(res, res_val);
619
+ mpz_jacobi(res_val, self_val);
620
+ return res;
621
+ }
622
+
623
+ static VALUE r_gmpz_legendre(VALUE self)
624
+ {
625
+ MP_INT *self_val, *res_val;
626
+ VALUE res;
627
+ mpz_get_struct(self, self_val);
628
+ if (mpz_sgn(self_val) != 1)
629
+ rb_raise(rb_eRangeError, "you can take legendre symbol only of positive value");
630
+ if (mpz_even_p(self_val))
631
+ rb_raise(rb_eRangeError, "you can't take legendre symbol of even value");
632
+ mpz_make_struct_init(res, res_val);
633
+ mpz_legendre(res_val, self_val);
634
+ return res;
635
+ }
636
+
637
+ #define DEFUN_INT_LOGIC(fname, mpz_fname) \
638
+ static VALUE r_gmpz_##fname(VALUE self, VALUE arg) \
639
+ { \
640
+ MP_INT *self_val, *arg_val, *res_val; \
641
+ VALUE res; \
642
+ \
643
+ mpz_get_struct(self, self_val); \
644
+ \
645
+ mpz_make_struct(res, res_val); \
646
+ if (GMPZ_P(arg)) { \
647
+ mpz_get_struct(arg,arg_val); \
648
+ mpz_init (res_val); \
649
+ mpz_fname (res_val, self_val, arg_val); \
650
+ } else if (FIXNUM_P(arg)) { \
651
+ mpz_init_set_si (res_val, FIX2INT(arg)); \
652
+ mpz_fname (res_val, self_val, res_val); \
653
+ } else if (BIGNUM_P(arg)) { \
654
+ mpz_init (res_val); \
655
+ mpz_set_bignum (res_val, arg); \
656
+ mpz_fname (res_val, self_val, res_val); \
657
+ } else { \
658
+ typeerror(ZXB); \
659
+ } \
660
+ return res; \
661
+ }
662
+
663
+ DEFUN_INT_LOGIC(and, mpz_and)
664
+ DEFUN_INT_LOGIC(xor, mpz_xor)
665
+ DEFUN_INT_LOGIC(or, mpz_ior)
666
+
667
+ static VALUE r_gmpz_sqrtrem(VALUE self)
668
+ {
669
+ MP_INT *self_val, *sqrt_val, *rem_val;
670
+ VALUE sqrt, rem;
671
+
672
+ mpz_get_struct (self, self_val);
673
+ mpz_make_struct_init(sqrt, sqrt_val);
674
+ mpz_make_struct_init(rem, rem_val);
675
+ mpz_sqrtrem (sqrt_val, rem_val, self_val);
676
+ return rb_assoc_new(sqrt, rem);
677
+ }
678
+
679
+ static VALUE r_gmpz_to_d(VALUE self)
680
+ {
681
+ MP_INT *self_val;
682
+ mpz_get_struct (self, self_val);
683
+
684
+ return rb_float_new(mpz_get_d(self_val));
685
+ }
686
+
687
+ #define DEFUN_INT_SINGLETON_UI(fname,mpz_fname) \
688
+ static VALUE r_gmpzsg_##fname(VALUE klass, VALUE arg) \
689
+ { \
690
+ MP_INT *arg_val_z, *res_val; \
691
+ unsigned long arg_val_ul; \
692
+ VALUE res; \
693
+ \
694
+ (void)klass; \
695
+ \
696
+ if (FIXNUM_P(arg)) { \
697
+ arg_val_ul = FIX2INT (arg); \
698
+ } else if (GMPZ_P(arg)) { \
699
+ mpz_get_struct (arg, arg_val_z); \
700
+ if (!mpz_fits_ulong_p (arg_val_z)) \
701
+ rb_raise (rb_eRangeError, "argument out of range"); \
702
+ arg_val_ul = mpz_get_ui (arg_val_z); \
703
+ if (arg_val_ul == 0) \
704
+ rb_raise (rb_eRangeError, "argument out of range"); \
705
+ } else { \
706
+ typeerror_as (ZX, "argument"); \
707
+ } \
708
+ mpz_make_struct_init(res, res_val); \
709
+ mpz_fname (res_val, arg_val_ul); \
710
+ return res; \
711
+ }
712
+
713
+ DEFUN_INT_SINGLETON_UI(fib,mpz_fib_ui)
714
+ DEFUN_INT_SINGLETON_UI(fac,mpz_fac_ui)
715
+
716
+ static VALUE r_gmpzsg_pow(VALUE klass, VALUE base, VALUE exp)
717
+ {
718
+ MP_INT *res_val;
719
+ VALUE res;
720
+
721
+ if (FIXNUM_P(base) && FIXNUM_P(exp))
722
+ {
723
+ if (FIX2INT(base) < 0)
724
+ rb_raise (rb_eRangeError, "base must not be negative");
725
+ if (FIX2INT(exp) < 0)
726
+ rb_raise (rb_eRangeError, "exponent must not be negative");
727
+ mpz_make_struct_init (res, res_val);
728
+ mpz_ui_pow_ui (res_val, base, exp);
729
+ return res;
730
+ }
731
+ return r_gmpz_pow (r_gmpzsg_new(1, &base, klass), exp);
732
+ }
733
+
734
+ static VALUE r_gmpz_remove(VALUE self, VALUE arg)
735
+ {
736
+ MP_INT *self_val, *arg_val, *res_val;
737
+ VALUE res;
738
+ int free_arg_val = 0;
739
+
740
+ mpz_get_struct(self,self_val);
741
+
742
+ if (GMPZ_P(arg)) {
743
+ mpz_get_struct(arg,arg_val);
744
+ if (mpz_sgn(arg_val) != 1)
745
+ rb_raise(rb_eRangeError, "argument must be positive");
746
+ } else if (FIXNUM_P(arg)) {
747
+ if (FIX2INT(arg) <= 0)
748
+ rb_raise(rb_eRangeError, "argument must be positive");
749
+ mpz_temp_alloc(arg_val);
750
+ mpz_init_set_ui(arg_val, FIX2INT(arg));
751
+ } else if (BIGNUM_P(arg)) {
752
+ mpz_temp_from_bignum(arg_val, arg);
753
+ if (mpz_sgn(arg_val) != 1) {
754
+ mpz_temp_free (arg_val);
755
+ rb_raise(rb_eRangeError, "argument must be positive");
756
+ }
757
+ } else {
758
+ typeerror(ZXB);
759
+ }
760
+
761
+ mpz_make_struct_init (res, res_val);
762
+ mpz_remove (res_val, self_val, arg_val);
763
+
764
+ if (free_arg_val)
765
+ mpz_temp_free(arg_val);
766
+
767
+ return res;
768
+ }
769
+
770
+ static VALUE r_gmpz_to_i(VALUE self)
771
+ {
772
+ MP_INT *self_val;
773
+ char *str;
774
+ VALUE res;
775
+
776
+ mpz_get_struct(self, self_val);
777
+ if (mpz_fits_slong_p(self_val))
778
+ return rb_int2inum(mpz_get_si(self_val));
779
+ str = mpz_get_str(NULL, 0, self_val);
780
+ res = rb_cstr2inum (str, 10);
781
+ free (str);
782
+ return res;
783
+ }
784
+
785
+ static VALUE r_gmpz_cmpabs(VALUE self, VALUE arg)
786
+ {
787
+ MP_INT *arg_val_z, *self_val;
788
+ MP_RAT *arg_val_q;
789
+ int res;
790
+
791
+ mpz_get_struct (self, self_val);
792
+
793
+ if (GMPZ_P(arg)) {
794
+ mpz_get_struct(arg,arg_val_z);
795
+ return INT2FIX(mpz_cmpabs (self_val, arg_val_z));
796
+ } else if (FIXNUM_P(arg)) {
797
+ if (FIX2INT(arg) >= 0)
798
+ return INT2FIX(mpz_cmpabs_ui (self_val, FIX2INT(arg)));
799
+ else
800
+ return INT2FIX(mpz_cmpabs_ui (self_val, -FIX2INT(arg)));
801
+ } else if (GMPQ_P(arg)) {
802
+ mpq_get_struct(arg,arg_val_q);
803
+ mpz_temp_alloc (arg_val_z);
804
+ mpz_init(arg_val_z);
805
+ mpz_mul(arg_val_z, self_val, mpq_denref(arg_val_q));
806
+ res = mpz_cmpabs (arg_val_z, mpq_numref(arg_val_q));
807
+ mpz_temp_free(arg_val_z);
808
+ return INT2FIX(res);
809
+ } else if (GMPF_P(arg)) {
810
+ not_yet;
811
+ } else if (BIGNUM_P(arg)) {
812
+ mpz_temp_from_bignum (arg_val_z, arg);
813
+ res = mpz_cmpabs (self_val, arg_val_z);
814
+ mpz_temp_free(arg_val_z);
815
+ return INT2FIX(res);
816
+ } else {
817
+ typeerror(ZQFXB);
818
+ }
819
+ }
820
+
821
+ static VALUE r_gmpz_to_s(VALUE self)
822
+ {
823
+ MP_INT *self_val;
824
+ char *str;
825
+ VALUE res;
826
+
827
+ Data_Get_Struct(self, MP_INT, self_val);
828
+ str = mpz_get_str(NULL, 10, self_val);
829
+ res = rb_str_new2(str);
830
+ free (str);
831
+
832
+ return res;
833
+ }