srawlins-gmp 0.1.5 → 0.1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. data/CHANGELOG +13 -1
  2. data/ext/gmpf.c +423 -0
  3. data/ext/gmpq.c +679 -0
  4. data/ext/gmpz.c +1598 -0
  5. data/ext/ruby_gmp.h +192 -0
  6. metadata +5 -1
@@ -0,0 +1,1598 @@
1
+ #include <gmpz.h>
2
+ #include <gmpq.h>
3
+ #include <gmpf.h>
4
+
5
+ /*
6
+ * Document-class: GMP::Z
7
+ *
8
+ * GMP Multiple Precision Integer.
9
+ *
10
+ * Instances of this class can store variables of the type mpz_t. This class
11
+ * also contains many methods that act as the functions for mpz_t variables,
12
+ * as well as a few methods that attempt to make this library more Ruby-ish.
13
+ *
14
+ * The following list is just a simple checklist for me, really. A better
15
+ * reference should be found in the rdocs.
16
+ *
17
+ * Ruby method C Extension function GMP function
18
+ * + r_gmpz_add mpz_add
19
+ * add! r_gmpz_add_self mpz_add
20
+ * - r_gmpz_sub mpz_sub
21
+ * sub! r_gmpz_sub_self mpz_sub
22
+ * * r_gmpz_mul mpz_mul
23
+ * / r_gmpz_div ...
24
+ * tdiv r_gmpz_tdiv mpz_tdiv_q
25
+ * tmod r_gmpz_tmod mpz_tdiv_r
26
+ * fdiv r_gmpz_fdiv mpz_fdiv_q
27
+ * fmod r_gmpz_fmod mpz_fdiv_r
28
+ * cdiv r_gmpz_cdiv mpz_cdiv_q
29
+ * cmod r_gmpz_cmod mpz_cdiv_r
30
+ * abs r_gmpz_abs mpz_abs
31
+ * abs! r_gmpz_abs_self mpz_abs
32
+ * -@ r_gmpz_neg mpz_neg
33
+ * neg r_gmpz_neg mpz_neg
34
+ * neg! r_gmpz_neg_self mpz_neg
35
+ * com r_gmpz_com mpz_com
36
+ * com! r_gmpz_com_self mpz_com
37
+ * []= r_gmpz_setbit mpz_setbit
38
+ * [] r_gmpz_getbit mpz_tstbit
39
+ * scan0 r_gmpz_scan0 mpz_scan0
40
+ * scan1 r_gmpz_scan1 mpz_scan1
41
+ * even? r_gmpz_is_even mpz_even
42
+ * odd? r_gmpz_is_odd mpz_odd
43
+ * ...
44
+ */
45
+
46
+ /*
47
+ * The goal is to organize this file in the same order that the GMP Manual
48
+ * is organized.
49
+ */
50
+
51
+ /**********************************************************************
52
+ * Macros *
53
+ **********************************************************************/
54
+
55
+ #define DEFUN_INT2INT(fname,mpz_fname) \
56
+ static VALUE r_gmpz_##fname(VALUE self) \
57
+ { \
58
+ MP_INT *self_val, *res_val; \
59
+ VALUE res; \
60
+ mpz_get_struct(self, self_val); \
61
+ mpz_make_struct_init(res, res_val); \
62
+ mpz_fname(res_val, self_val); \
63
+ return res; \
64
+ } \
65
+ \
66
+ static VALUE r_gmpz_##fname##_self(VALUE self) \
67
+ { \
68
+ MP_INT *self_val; \
69
+ mpz_get_struct(self, self_val); \
70
+ mpz_fname(self_val, self_val); \
71
+ return Qnil; \
72
+ }
73
+
74
+ #define DEFUN_INT_F_UL(fname,mpz_fname,argname) \
75
+ static VALUE r_gmpz_##fname(VALUE self, VALUE exp) \
76
+ { \
77
+ MP_INT *self_val, *res_val; \
78
+ VALUE res; \
79
+ unsigned long exp_val; \
80
+ \
81
+ if (FIXNUM_P(exp)) { \
82
+ if (FIX2INT(exp) < 0) \
83
+ rb_raise(rb_eRangeError, argname " out of range"); \
84
+ exp_val = FIX2INT(exp); \
85
+ } else if (GMPZ_P(exp)) { \
86
+ mpz_get_struct(exp, res_val); \
87
+ if (!mpz_fits_ulong_p(res_val)) \
88
+ rb_raise(rb_eRangeError, argname " out of range"); \
89
+ exp_val = mpz_get_ui(res_val); \
90
+ if (exp_val == 0) \
91
+ rb_raise(rb_eRangeError, argname " out of range"); \
92
+ } else { \
93
+ typeerror_as(ZX, argname); \
94
+ } \
95
+ \
96
+ mpz_make_struct_init(res, res_val); \
97
+ mpz_get_struct(self, self_val); \
98
+ mpz_fname(res_val, self_val, exp_val); \
99
+ \
100
+ return res; \
101
+ }
102
+
103
+ #define DEFUN_INT_CMP(name,CMP_OP) \
104
+ static VALUE r_gmpz_cmp_##name(VALUE self, VALUE arg) \
105
+ { \
106
+ MP_INT *self_val; \
107
+ mpz_get_struct(self,self_val); \
108
+ return (mpz_cmp_value(self_val, arg) CMP_OP 0)?Qtrue:Qfalse; \
109
+ }
110
+
111
+ #define DEFUN_INT_DIV(fname,gmp_fname) \
112
+ static VALUE r_gmpz_##fname(VALUE self, VALUE arg) \
113
+ { \
114
+ MP_INT *self_val, *arg_val, *res_val; \
115
+ VALUE res; \
116
+ int arg_val_i; \
117
+ \
118
+ mpz_get_struct(self, self_val); \
119
+ mpz_make_struct_init(res, res_val); \
120
+ \
121
+ if (GMPZ_P(arg)) { \
122
+ mpz_get_struct(arg,arg_val); \
123
+ if (mpz_cmp_ui(arg_val, 0) == 0) \
124
+ rb_raise (rb_eZeroDivError, "divided by 0"); \
125
+ gmp_fname (res_val, self_val, arg_val); \
126
+ } else if (FIXNUM_P(arg)) { \
127
+ arg_val_i = FIX2INT(arg); \
128
+ if (arg_val_i > 0) { \
129
+ gmp_fname##_ui (res_val, self_val, arg_val_i); \
130
+ } else if (arg_val_i == 0) { \
131
+ rb_raise (rb_eZeroDivError, "divided by 0"); \
132
+ } else { \
133
+ mpz_neg (res_val, self_val); \
134
+ gmp_fname##_ui (res_val, self_val, -arg_val_i); \
135
+ } \
136
+ } else if (BIGNUM_P(arg)) { \
137
+ mpz_set_bignum (res_val, arg); \
138
+ if (mpz_cmp_ui(res_val, 0) == 0) \
139
+ rb_raise (rb_eZeroDivError, "divided by 0"); \
140
+ gmp_fname (res_val, self_val, res_val); \
141
+ } else { \
142
+ typeerror(ZXB); \
143
+ } \
144
+ return res; \
145
+ }
146
+
147
+ #define DEFUN_INT_LOGIC(fname, mpz_fname) \
148
+ static VALUE r_gmpz_##fname(VALUE self, VALUE arg) \
149
+ { \
150
+ MP_INT *self_val, *arg_val, *res_val; \
151
+ VALUE res; \
152
+ \
153
+ mpz_get_struct(self, self_val); \
154
+ \
155
+ mpz_make_struct(res, res_val); \
156
+ if (GMPZ_P(arg)) { \
157
+ mpz_get_struct(arg,arg_val); \
158
+ mpz_init(res_val); \
159
+ mpz_fname(res_val, self_val, arg_val); \
160
+ } else if (FIXNUM_P(arg)) { \
161
+ mpz_init_set_si(res_val, FIX2INT(arg)); \
162
+ mpz_fname(res_val, self_val, res_val); \
163
+ } else if (BIGNUM_P(arg)) { \
164
+ mpz_init(res_val); \
165
+ mpz_set_bignum(res_val, arg); \
166
+ mpz_fname(res_val, self_val, res_val); \
167
+ } else { \
168
+ typeerror(ZXB); \
169
+ } \
170
+ return res; \
171
+ }
172
+
173
+ #define DEFUN_INT_SINGLETON_UI(fname,mpz_fname) \
174
+ static VALUE r_gmpzsg_##fname(VALUE klass, VALUE arg) \
175
+ { \
176
+ MP_INT *arg_val_z, *res_val; \
177
+ unsigned long arg_val_ul; \
178
+ VALUE res; \
179
+ \
180
+ (void)klass; \
181
+ \
182
+ if (FIXNUM_P(arg)) { \
183
+ arg_val_ul = FIX2INT (arg); \
184
+ } else if (GMPZ_P(arg)) { \
185
+ mpz_get_struct(arg, arg_val_z); \
186
+ if (!mpz_fits_ulong_p (arg_val_z)) \
187
+ rb_raise(rb_eRangeError, "argument out of range"); \
188
+ arg_val_ul = mpz_get_ui(arg_val_z); \
189
+ if (arg_val_ul == 0) \
190
+ rb_raise(rb_eRangeError, "argument out of range"); \
191
+ } else { \
192
+ typeerror_as(ZX, "argument"); \
193
+ } \
194
+ mpz_make_struct_init(res, res_val); \
195
+ mpz_fname(res_val, arg_val_ul); \
196
+ return res; \
197
+ }
198
+
199
+ /**********************************************************************
200
+ * Initializing, Assigning Integers *
201
+ **********************************************************************/
202
+
203
+ void mpz_set_value(MP_INT *target, VALUE source)
204
+ {
205
+ MP_INT *source_val;
206
+
207
+ if (GMPZ_P(source)) {
208
+ mpz_get_struct(source, source_val);
209
+ mpz_set (target, source_val);
210
+ } else if (FIXNUM_P(source)) {
211
+ mpz_set_si (target, NUM2INT(source));
212
+ } else if (STRING_P(source)) {
213
+ mpz_set_str (target, STR2CSTR(source), 0);
214
+ } else if (BIGNUM_P(source)) {
215
+ mpz_set_bignum(target, source);
216
+ } else {
217
+ rb_raise (rb_eTypeError, "Don't know how to convert %s into GMP_Z", rb_class2name(rb_class_of(source)));
218
+ }
219
+ }
220
+
221
+ VALUE r_gmpmod_z(int argc, VALUE *argv, VALUE module)
222
+ {
223
+ (void)module;
224
+ return r_gmpzsg_new(argc, argv, cGMP_Z);
225
+ }
226
+
227
+ VALUE r_gmpz_swap(VALUE self, VALUE arg)
228
+ {
229
+ MP_INT *self_val, *arg_val;
230
+ if (!GMPZ_P(arg)) {
231
+ rb_raise(rb_eTypeError, "Can't swap GMP::Z with object of other class");
232
+ }
233
+ mpz_get_struct(self, self_val);
234
+ mpz_get_struct(arg, arg_val);
235
+ mpz_swap(self_val,arg_val);
236
+ return Qnil;
237
+ }
238
+
239
+
240
+ /**********************************************************************
241
+ * Converting Integers *
242
+ **********************************************************************/
243
+
244
+ /*
245
+ * call-seq:
246
+ * integer.to_i
247
+ *
248
+ * Returns +integer+ as an Fixnum if +integer+ fits in a Fixnum.
249
+ *
250
+ * Otherwise returns the least significant part of +integer+, with the same
251
+ * sign as +integer+.
252
+ *
253
+ * If +integer+ is too big to fit in a Fixnum, the returned result is probably
254
+ * not very useful. To find out if the value will fit, use the function
255
+ * mpz_fits_slong_p (<b>Unimplemented</b>).
256
+ */
257
+ VALUE r_gmpz_to_i(VALUE self)
258
+ {
259
+ MP_INT *self_val;
260
+ char *str;
261
+ VALUE res;
262
+
263
+ mpz_get_struct(self, self_val);
264
+ if (mpz_fits_slong_p(self_val))
265
+ return rb_int2inum(mpz_get_si(self_val));
266
+ str = mpz_get_str(NULL, 0, self_val);
267
+ res = rb_cstr2inum(str, 10);
268
+ free(str);
269
+ return res;
270
+ }
271
+
272
+ /*
273
+ * call-seq:
274
+ * integer.to_d
275
+ *
276
+ * Returns +integer+ as an Float if +integer+ fits in a Float.
277
+ *
278
+ * Otherwise returns the least significant part of +integer+, with the same
279
+ * sign as +integer+.
280
+ *
281
+ * If +integer+ is too big to fit in a Float, the returned result is probably
282
+ * not very useful. To find out if the value will fit, use the function
283
+ * mpz_fits_slong_p (<b>Unimplemented</b>).
284
+ */
285
+ VALUE r_gmpz_to_d(VALUE self)
286
+ {
287
+ MP_INT *self_val;
288
+ mpz_get_struct(self, self_val);
289
+
290
+ return rb_float_new(mpz_get_d(self_val));
291
+ }
292
+
293
+
294
+ /**********************************************************************
295
+ * Integer Arithmetic *
296
+ **********************************************************************/
297
+
298
+ /*
299
+ * call-seq:
300
+ * +(other)
301
+ *
302
+ * Adds this GMP::Z to other. Other can be
303
+ * * GMP::Z
304
+ * * Fixnum
305
+ * * GMP::Q
306
+ * * GMP::F
307
+ * * Bignum
308
+ */
309
+ VALUE r_gmpz_add(VALUE self, VALUE arg)
310
+ {
311
+ MP_INT *self_val, *arg_val, *res_val;
312
+ VALUE res;
313
+
314
+ mpz_get_struct(self,self_val);
315
+
316
+ if (GMPZ_P(arg)) {
317
+ mpz_get_struct(arg,arg_val);
318
+ mpz_make_struct_init(res, res_val);
319
+ mpz_add(res_val, self_val, arg_val);
320
+ } else if (FIXNUM_P(arg)) {
321
+ mpz_make_struct_init(res, res_val);
322
+ if (FIX2INT(arg) > 0)
323
+ mpz_add_ui(res_val, self_val, FIX2INT(arg));
324
+ else
325
+ mpz_sub_ui(res_val, self_val, -FIX2INT(arg));
326
+ } else if (GMPQ_P(arg)) {
327
+ return r_gmpq_add(arg, self);
328
+ } else if (GMPF_P(arg)) {
329
+ return r_gmpf_add(arg, self);
330
+ } else if (BIGNUM_P(arg)) {
331
+ mpz_make_struct_init(res, res_val);
332
+ mpz_init(res_val);
333
+ mpz_set_bignum (res_val, arg);
334
+ mpz_add(res_val, res_val, self_val);
335
+ } else {
336
+ typeerror(ZQFXB);
337
+ }
338
+ return res;
339
+ }
340
+
341
+ /*
342
+ * call-seq:
343
+ * add!(other)
344
+ *
345
+ * Adds this GMP::Z to other, and sets this GMP::Z's value to the result. Other
346
+ * can be
347
+ * * GMP::Z
348
+ * * Fixnum
349
+ * * GMP::Q
350
+ * * GMP::F
351
+ * * Bignum
352
+ */
353
+ VALUE r_gmpz_add_self(VALUE self, VALUE arg)
354
+ {
355
+ MP_INT *self_val, *arg_val;
356
+
357
+ mpz_get_struct(self,self_val);
358
+
359
+ if (GMPZ_P(arg)) {
360
+ mpz_get_struct(arg,arg_val);
361
+ mpz_add(self_val, self_val, arg_val);
362
+ } else if (FIXNUM_P(arg)) {
363
+ if (FIX2INT(arg) > 0)
364
+ mpz_add_ui(self_val, self_val, FIX2INT(arg));
365
+ else
366
+ mpz_sub_ui(self_val, self_val, -FIX2INT(arg));
367
+ } else if (BIGNUM_P(arg)) {
368
+ mpz_temp_from_bignum(arg_val, arg);
369
+ mpz_add(self_val, self_val, arg_val);
370
+ mpz_temp_free(arg_val);
371
+ } else {
372
+ typeerror(ZXB);
373
+ }
374
+ return Qnil;
375
+ }
376
+
377
+ /*
378
+ * call-seq:
379
+ * -(other)
380
+ *
381
+ * Subtracts other from this GMP::Z. Other can be
382
+ * * GMP::Z
383
+ * * Fixnum
384
+ * * GMP::Q
385
+ * * GMP::F
386
+ * * Bignum
387
+ */
388
+ VALUE r_gmpz_sub(VALUE self, VALUE arg)
389
+ {
390
+ MP_RAT *res_val_q, *arg_val_q;
391
+ MP_INT *self_val, *arg_val, *res_val;
392
+ MP_FLOAT *arg_val_f, *res_val_f;
393
+ VALUE res;
394
+ unsigned long prec;
395
+
396
+ mpz_get_struct(self,self_val);
397
+
398
+ if (GMPZ_P(arg)) {
399
+ mpz_make_struct_init(res, res_val);
400
+ mpz_get_struct(arg,arg_val);
401
+ mpz_sub (res_val, self_val, arg_val);
402
+ } else if (FIXNUM_P(arg)) {
403
+ mpz_make_struct_init(res, res_val);
404
+ if (FIX2INT(arg) > 0)
405
+ mpz_sub_ui (res_val, self_val, FIX2INT(arg));
406
+ else
407
+ mpz_add_ui (res_val, self_val, -FIX2INT(arg));
408
+ } else if (GMPQ_P(arg)) {
409
+ mpq_make_struct_init(res, res_val_q);
410
+ mpq_get_struct(arg,arg_val_q);
411
+ mpz_set (mpq_denref(res_val_q), mpq_denref(arg_val_q));
412
+ mpz_mul (mpq_numref(res_val_q), mpq_denref(arg_val_q), self_val);
413
+ mpz_sub (mpq_numref(res_val_q), mpq_numref(res_val_q), mpq_numref(arg_val_q));
414
+ } else if (GMPF_P(arg)) {
415
+ mpf_get_struct_prec (arg, arg_val_f, prec);
416
+ mpf_make_struct_init(res, res_val_f, prec);
417
+ mpf_set_z (res_val_f, self_val);
418
+ mpf_sub (res_val_f, res_val_f, arg_val_f);
419
+ } else if (BIGNUM_P(arg)) {
420
+ mpz_make_struct_init(res, res_val);
421
+ mpz_set_bignum (res_val, arg);
422
+ mpz_sub (res_val, self_val, res_val);
423
+ } else {
424
+ typeerror (ZQFXB);
425
+ }
426
+ return res;
427
+ }
428
+
429
+ /*
430
+ * call-seq:
431
+ * sub!(other)
432
+ *
433
+ * Subtracts other from this GMP::Z, and sets this GMP::Z's value to the
434
+ * result. Other can be
435
+ * * GMP::Z
436
+ * * Fixnum
437
+ * * GMP::Q
438
+ * * GMP::F
439
+ * * Bignum
440
+ */
441
+ VALUE r_gmpz_sub_self(VALUE self, VALUE arg)
442
+ {
443
+ MP_INT *self_val, *arg_val;
444
+
445
+ mpz_get_struct(self,self_val);
446
+
447
+ if (GMPZ_P(arg)) {
448
+ mpz_get_struct(arg, arg_val);
449
+ mpz_sub (self_val, self_val, arg_val);
450
+ } else if (FIXNUM_P(arg)) {
451
+ if (FIX2INT(arg) > 0)
452
+ mpz_sub_ui (self_val, self_val, FIX2INT(arg));
453
+ else
454
+ mpz_add_ui (self_val, self_val, -FIX2INT(arg));
455
+ } else if (BIGNUM_P(arg)) {
456
+ mpz_temp_from_bignum(arg_val, arg);
457
+ mpz_sub (self_val, self_val, arg_val);
458
+ mpz_temp_free (arg_val);
459
+ } else {
460
+ typeerror (ZXB);
461
+ }
462
+ return Qnil;
463
+ }
464
+
465
+ /*
466
+ * call-seq:
467
+ * *(other)
468
+ *
469
+ * Multiplies this GMP::Z with other. Other can be
470
+ * * GMP::Z
471
+ * * Fixnum
472
+ * * GMP::Q
473
+ * * GMP::F
474
+ * * Bignum
475
+ */
476
+ VALUE r_gmpz_mul(VALUE self, VALUE arg)
477
+ {
478
+ MP_INT *self_val, *arg_val, *res_val;
479
+ VALUE res;
480
+
481
+ mpz_get_struct(self,self_val);
482
+
483
+ if (GMPZ_P(arg)) {
484
+ mpz_make_struct_init(res, res_val);
485
+ mpz_get_struct(arg,arg_val);
486
+ mpz_mul(res_val, self_val, arg_val);
487
+ } else if (FIXNUM_P(arg)) {
488
+ mpz_make_struct_init(res, res_val);
489
+ mpz_mul_si(res_val, self_val, FIX2INT(arg));
490
+ } else if (GMPQ_P(arg)) {
491
+ return r_gmpq_mul(arg, self);
492
+ } else if (GMPF_P(arg)) {
493
+ return r_gmpf_mul(arg, self);
494
+ } else if (BIGNUM_P(arg)) {
495
+ mpz_make_struct_init(res, res_val);
496
+ mpz_set_bignum(res_val, arg);
497
+ mpz_mul(res_val, res_val, self_val);
498
+ } else {
499
+ typeerror(ZQFXB);
500
+ }
501
+ return res;
502
+ }
503
+
504
+ /*
505
+ * Document-method: neg
506
+ *
507
+ * call-seq:
508
+ * -integer
509
+ * integer.neg
510
+ *
511
+ * From the GMP Manual:
512
+ *
513
+ * Returns -+integer+.
514
+ */
515
+ /*
516
+ * Document-method: neg!
517
+ *
518
+ * call-seq:
519
+ * integer.neg!
520
+ *
521
+ * From the GMP Manual:
522
+ *
523
+ * Sets +integer+ to -+integer+.
524
+ */
525
+ DEFUN_INT2INT(neg, mpz_neg)
526
+ /*
527
+ * Document-method: abs
528
+ *
529
+ * call-seq:
530
+ * integer.abs
531
+ *
532
+ * From the GMP Manual:
533
+ *
534
+ * Returns the absolute value of +integer+.
535
+ */
536
+ /*
537
+ * Document-method: abs!
538
+ *
539
+ * call-seq:
540
+ * integer.abs!
541
+ *
542
+ * From the GMP Manual:
543
+ *
544
+ * Sets +integer+ to its absolute value.
545
+ */
546
+ DEFUN_INT2INT(abs, mpz_abs)
547
+
548
+
549
+ /**********************************************************************
550
+ * Integer Division *
551
+ **********************************************************************/
552
+
553
+ /**********************************************************************
554
+ * Integer Exponentiation *
555
+ **********************************************************************/
556
+
557
+ /**********************************************************************
558
+ * Integer Roots *
559
+ **********************************************************************/
560
+
561
+ DEFUN_INT_F_UL(root,mpz_root,"root number")
562
+
563
+ /*
564
+ * Document-method: sqrt
565
+ *
566
+ * call-seq:
567
+ * integer.sqrt
568
+ *
569
+ * From the GMP Manual:
570
+ *
571
+ * Returns the truncated integer part of the square root of +integer+.
572
+ */
573
+ /*
574
+ * Document-method: sqrt!
575
+ *
576
+ * call-seq:
577
+ * integer.sqrt!
578
+ *
579
+ * From the GMP Manual:
580
+ *
581
+ * Sets +integer+ to the truncated integer part of its square root.
582
+ */
583
+ DEFUN_INT2INT(sqrt, mpz_sqrt)
584
+
585
+
586
+ /**********************************************************************
587
+ * Number Theoretic Functions *
588
+ **********************************************************************/
589
+
590
+ /*
591
+ * Document-method: remove
592
+ *
593
+ * call-seq:
594
+ * integer.remove(factor)
595
+ *
596
+ * From the GMP Manual:
597
+ *
598
+ * Remove all occurrences of the factor +factor+ from +integer+. The return
599
+ * value is how many such occurrences were removed.
600
+ */
601
+ VALUE r_gmpz_remove(VALUE self, VALUE arg)
602
+ {
603
+ MP_INT *self_val, *arg_val, *res_val;
604
+ VALUE res;
605
+ int free_arg_val = 0;
606
+
607
+ mpz_get_struct(self,self_val);
608
+
609
+ if (GMPZ_P(arg)) {
610
+ mpz_get_struct(arg,arg_val);
611
+ if (mpz_sgn(arg_val) != 1)
612
+ rb_raise(rb_eRangeError, "argument must be positive");
613
+ } else if (FIXNUM_P(arg)) {
614
+ if (FIX2INT(arg) <= 0)
615
+ rb_raise(rb_eRangeError, "argument must be positive");
616
+ mpz_temp_alloc(arg_val);
617
+ mpz_init_set_ui(arg_val, FIX2INT(arg));
618
+ } else if (BIGNUM_P(arg)) {
619
+ mpz_temp_from_bignum(arg_val, arg);
620
+ if (mpz_sgn(arg_val) != 1) {
621
+ mpz_temp_free (arg_val);
622
+ rb_raise(rb_eRangeError, "argument must be positive");
623
+ }
624
+ } else {
625
+ typeerror(ZXB);
626
+ }
627
+
628
+ mpz_make_struct_init (res, res_val);
629
+ mpz_remove (res_val, self_val, arg_val);
630
+
631
+ if (free_arg_val)
632
+ mpz_temp_free(arg_val);
633
+
634
+ return res;
635
+ }
636
+
637
+ /*
638
+ * Document-method: GMP::Z.fac
639
+ *
640
+ * call-seq:
641
+ * GMP::Z.fac(n)
642
+ *
643
+ * From the GMP Manual:
644
+ *
645
+ * Returns <tt>n!</tt>, the factorial of +n+.
646
+ *
647
+ * Examples:
648
+ *
649
+ * GMP::Z.fac(0) #=> 1
650
+ * GMP::Z.fac(1) #=> 1
651
+ * GMP::Z.fac(2) #=> 2
652
+ * GMP::Z.fac(3) #=> 6
653
+ * GMP::Z.fac(4) #=> 24
654
+ */
655
+ DEFUN_INT_SINGLETON_UI(fac,mpz_fac_ui)
656
+ /*
657
+ * Document-method: GMP::Z.fib
658
+ *
659
+ * call-seq:
660
+ * GMP::Z.fib(n)
661
+ *
662
+ * From the GMP Manual:
663
+ *
664
+ * Returns <tt>F[n]</tt>, the +n+th Fibonacci number.
665
+ *
666
+ * Examples:
667
+ *
668
+ * GMP::Z.fib(1) #=> 1
669
+ * GMP::Z.fib(2) #=> 1
670
+ * GMP::Z.fib(3) #=> 2
671
+ * GMP::Z.fac(4) #=> 3
672
+ * GMP::Z.fac(5) #=> 5
673
+ * GMP::Z.fac(6) #=> 8
674
+ * GMP::Z.fac(7) #=> 13
675
+ */
676
+ DEFUN_INT_SINGLETON_UI(fib,mpz_fib_ui)
677
+
678
+
679
+ /**********************************************************************
680
+ * Integer Comparisons *
681
+ **********************************************************************/
682
+
683
+ VALUE r_gmpz_eq(VALUE self, VALUE arg)
684
+ {
685
+ MP_INT *self_val, *arg_val_z;
686
+ MP_RAT *arg_val_q;
687
+
688
+ mpz_get_struct (self, self_val);
689
+ if (GMPZ_P(arg)) {
690
+ mpz_get_struct(arg, arg_val_z);
691
+ return (mpz_cmp (self_val, arg_val_z)==0) ? Qtrue : Qfalse;
692
+ } else if (FIXNUM_P(arg)) {
693
+ return (mpz_cmp_si (self_val, FIX2INT(arg))==0) ? Qtrue : Qfalse;
694
+ } else if (GMPQ_P(arg)) {
695
+ mpq_get_struct(arg, arg_val_q);
696
+ if (mpz_cmp_ui(mpq_denref(arg_val_q), 1)==0)
697
+ return Qfalse;
698
+ return (mpz_cmp (self_val, mpq_numref(arg_val_q))==0) ? Qtrue : Qfalse;
699
+ } else if (BIGNUM_P(arg)) {
700
+ mpz_temp_from_bignum(arg_val_z, arg);
701
+ if (mpz_cmp (self_val, arg_val_z)==0) {
702
+ mpz_temp_free(arg_val_z);
703
+ return Qtrue;
704
+ } else {
705
+ mpz_temp_free(arg_val_z);
706
+ return Qfalse;
707
+ }
708
+ } else {
709
+ return Qfalse;
710
+ }
711
+ }
712
+
713
+ VALUE r_gmpz_cmpabs(VALUE self, VALUE arg)
714
+ {
715
+ MP_INT *arg_val_z, *self_val;
716
+ MP_RAT *arg_val_q;
717
+ int res;
718
+
719
+ mpz_get_struct(self, self_val);
720
+
721
+ if (GMPZ_P(arg)) {
722
+ mpz_get_struct(arg,arg_val_z);
723
+ return INT2FIX(mpz_cmpabs(self_val, arg_val_z));
724
+ } else if (FIXNUM_P(arg)) {
725
+ if (FIX2INT(arg) >= 0)
726
+ return INT2FIX(mpz_cmpabs_ui(self_val, FIX2INT(arg)));
727
+ else
728
+ return INT2FIX(mpz_cmpabs_ui(self_val, -FIX2INT(arg)));
729
+ } else if (GMPQ_P(arg)) {
730
+ mpq_get_struct(arg,arg_val_q);
731
+ mpz_temp_alloc(arg_val_z);
732
+ mpz_init(arg_val_z);
733
+ mpz_mul(arg_val_z, self_val, mpq_denref(arg_val_q));
734
+ res = mpz_cmpabs(arg_val_z, mpq_numref(arg_val_q));
735
+ mpz_temp_free(arg_val_z);
736
+ return INT2FIX(res);
737
+ } else if (GMPF_P(arg)) {
738
+ not_yet;
739
+ } else if (BIGNUM_P(arg)) {
740
+ mpz_temp_from_bignum(arg_val_z, arg);
741
+ res = mpz_cmpabs(self_val, arg_val_z);
742
+ mpz_temp_free(arg_val_z);
743
+ return INT2FIX(res);
744
+ } else {
745
+ typeerror(ZQFXB);
746
+ }
747
+ }
748
+
749
+
750
+ /**********************************************************************
751
+ * Integer Logic and Bit Fiddling *
752
+ **********************************************************************/
753
+
754
+ /*
755
+ * Document-method: &
756
+ *
757
+ * call-seq:
758
+ * integer & other
759
+ *
760
+ * From the GMP Manual:
761
+ *
762
+ * Returns +integer+ bitwise-and +other+.
763
+ */
764
+ DEFUN_INT_LOGIC(and, mpz_and)
765
+ /*
766
+ * Document-method: |
767
+ *
768
+ * call-seq:
769
+ * integer | other
770
+ *
771
+ * From the GMP Manual:
772
+ *
773
+ * Returns +integer+ bitwise inclusive-or +other+.
774
+ */
775
+ DEFUN_INT_LOGIC(or, mpz_ior)
776
+ /*
777
+ * Document-method: ^
778
+ *
779
+ * call-seq:
780
+ * integer ^ other
781
+ *
782
+ * From the GMP Manual:
783
+ *
784
+ * Returns +integer+ bitwise exclusive-or +other+.
785
+ */
786
+ DEFUN_INT_LOGIC(xor, mpz_xor)
787
+
788
+ /*
789
+ * call-seq:
790
+ * integer.scan0(starting_bit)
791
+ *
792
+ * From the GMP Manual:
793
+ *
794
+ * Scan integer, starting from bit starting_bit, towards more significant bits,
795
+ * until the first 0 bit is found. Return the index of the found bit.
796
+ *
797
+ * If the bit at starting_bit is already what's sought, then starting_bit is
798
+ * returned.
799
+ *
800
+ * If there's no bit found, then INT2FIX(ULONG_MAX) is returned. This will
801
+ * happen in scan0 past the end of a negative number.
802
+ */
803
+ VALUE r_gmpz_scan0(VALUE self, VALUE bitnr)
804
+ {
805
+ MP_INT *self_val;
806
+ int bitnr_val;
807
+ mpz_get_struct(self, self_val);
808
+ if (FIXNUM_P(bitnr)) {
809
+ bitnr_val = FIX2INT (bitnr);
810
+ } else {
811
+ typeerror_as(X, "index");
812
+ }
813
+ return INT2FIX(mpz_scan0(self_val, bitnr_val));
814
+ }
815
+
816
+ /*
817
+ * call-seq:
818
+ * integer.scan1(starting_bit)
819
+ *
820
+ * From the GMP Manual:
821
+ *
822
+ * Scan integer, starting from bit starting_bit, towards more significant bits,
823
+ * until the first 1 bit is found. Return the index of the found bit.
824
+ *
825
+ * If the bit at starting_bit is already what's sought, then starting_bit is
826
+ * returned.
827
+ *
828
+ * If there's no bit found, then INT2FIX(ULONG_MAX) is returned. This will
829
+ * happen in mpz_scan1 past the end of a nonnegative number.
830
+ */
831
+ VALUE r_gmpz_scan1(VALUE self, VALUE bitnr)
832
+ {
833
+ MP_INT *self_val;
834
+ int bitnr_val;
835
+
836
+ mpz_get_struct(self, self_val);
837
+
838
+ if (FIXNUM_P(bitnr)) {
839
+ bitnr_val = FIX2INT (bitnr);
840
+ } else {
841
+ typeerror_as(X, "index");
842
+ }
843
+
844
+ return INT2FIX(mpz_scan1(self_val, bitnr_val));
845
+ }
846
+
847
+
848
+ /**********************************************************************
849
+ * Integer Random Numbers *
850
+ **********************************************************************/
851
+
852
+ /**********************************************************************
853
+ * Miscellaneous Integer Functions *
854
+ **********************************************************************/
855
+
856
+ /**********************************************************************
857
+ * Integer Special Functions *
858
+ **********************************************************************/
859
+
860
+
861
+ /**********************************************************************
862
+ * _unsorted_ *
863
+ **********************************************************************/
864
+
865
+ /*
866
+ * call-seq:
867
+ * /(other)
868
+ *
869
+ * Divides this GMP::Z by other. Other can be
870
+ * * GMP::Z
871
+ * * Fixnum
872
+ * * GMP::Q
873
+ * * GMP::F
874
+ * * Bignum
875
+ */
876
+ VALUE r_gmpz_div(VALUE self, VALUE arg)
877
+ {
878
+ MP_INT *self_val, *arg_val_z, *tmp_z;
879
+ MP_RAT *arg_val_q, *res_val_q;
880
+ MP_FLOAT *arg_val_f, *res_val_f;
881
+ VALUE res;
882
+ unsigned int prec;
883
+
884
+ mpz_get_struct(self,self_val);
885
+
886
+ if (GMPZ_P(arg)) {
887
+ mpz_get_struct(arg, arg_val_z);
888
+ if (mpz_cmp_ui(arg_val_z, 0) == 0)
889
+ rb_raise(rb_eZeroDivError, "divided by 0");
890
+ mpq_make_struct_init(res, res_val_q);
891
+ mpq_set_num(res_val_q, self_val);
892
+ mpq_set_den(res_val_q, arg_val_z);
893
+ mpq_canonicalize (res_val_q);
894
+ } else if (FIXNUM_P(arg)) {
895
+ if (FIX2INT(arg) == 0)
896
+ rb_raise(rb_eZeroDivError, "divided by 0");
897
+ mpq_make_struct_init(res, res_val_q);
898
+ mpq_set_num(res_val_q, self_val);
899
+ mpz_set_ui(mpq_denref(res_val_q), FIX2INT(arg));
900
+ mpq_canonicalize (res_val_q);
901
+ } else if (GMPQ_P(arg)) {
902
+ mpq_get_struct(arg, arg_val_q);
903
+ if (mpz_cmp_ui(mpq_numref(arg_val_q), 0) == 0)
904
+ rb_raise(rb_eZeroDivError, "divided by 0");
905
+ mpz_temp_init(tmp_z);
906
+ mpq_make_struct_init(res, res_val_q);
907
+ mpz_gcd(tmp_z, mpq_numref(arg_val_q), self_val);
908
+ mpz_divexact(mpq_numref(res_val_q), self_val, tmp_z);
909
+ mpz_divexact(mpq_denref(res_val_q), mpq_numref(arg_val_q), tmp_z);
910
+ mpz_mul(mpq_numref(res_val_q), mpq_numref(res_val_q), mpq_denref(arg_val_q));
911
+ mpz_temp_free(tmp_z);
912
+ } else if (GMPF_P(arg)) {
913
+ mpf_get_struct_prec(arg, arg_val_f, prec);
914
+ mpf_make_struct_init(res, res_val_f, prec);
915
+ mpf_set_z(res_val_f, self_val);
916
+ mpf_div(res_val_f, res_val_f, arg_val_f);
917
+ } else if (BIGNUM_P(arg)) {
918
+ mpq_make_struct_init(res, res_val_q);
919
+ mpz_set_bignum(mpq_denref(res_val_q), arg);
920
+ if (mpz_cmp_ui(mpq_denref(res_val_q), 0) == 0)
921
+ rb_raise(rb_eZeroDivError, "divided by 0");
922
+ mpq_set_num(res_val_q, self_val);
923
+ mpq_canonicalize(res_val_q);
924
+ } else {
925
+ typeerror(ZQFXB);
926
+ }
927
+ return res;
928
+ }
929
+
930
+ /*
931
+ * Document-method: tdiv
932
+ *
933
+ * call-seq:
934
+ * n.tdiv d
935
+ *
936
+ * From the GMP Manual:
937
+ *
938
+ * Divides +n+ by +d+, forming a quotient +q+. tdiv rounds +q+ towards zero.
939
+ * The +t+ stands for "truncate".
940
+ *
941
+ * +q+ will satisfy <tt>n=q*d+r</tt>, and +r+ will satisfy
942
+ * <tt>0<=abs(r)<abs(d)</tt>.
943
+ *
944
+ * This function calculates only the quotient.
945
+ */
946
+ DEFUN_INT_DIV(tdiv, mpz_tdiv_q)
947
+ /*
948
+ * Document-method: tmod
949
+ *
950
+ * call-seq:
951
+ * n.tmod d
952
+ *
953
+ * From the GMP Manual:
954
+ *
955
+ * Divides +n+ by +d+, forming a remainder +r+. +r+ will have the same sign as
956
+ * +n+. The +t+ stands for �truncate�.
957
+ *
958
+ * +r+ will satisfy <tt>n=q*d+r</tt>, and +r+ will satisfy
959
+ * <tt>0<=abs(r)<abs(d)</tt>.
960
+ *
961
+ * This function calculates only the remainder.
962
+ *
963
+ * The remainder can be negative, so the return value is the absolute value of
964
+ * the remainder.
965
+ */
966
+ DEFUN_INT_DIV(tmod, mpz_tdiv_r)
967
+ /*
968
+ * Document-method: fdiv
969
+ *
970
+ * call-seq:
971
+ * n.fdiv d
972
+ *
973
+ * From the GMP Manual:
974
+ *
975
+ * Divide n by d, forming a quotient q. fdiv rounds q down towards -infinity.
976
+ * The f stands for �floor�.
977
+ *
978
+ * q will satisfy n=q*d+r.
979
+ *
980
+ * This function calculates only the quotient.
981
+ */
982
+ DEFUN_INT_DIV(fdiv, mpz_fdiv_q)
983
+ /*
984
+ * Document-method: fmod
985
+ *
986
+ * call-seq:
987
+ * n.fmod d
988
+ *
989
+ * From the GMP Manual:
990
+ *
991
+ * Divides n by d, forming a remainder r. r will have the same sign as d. The f
992
+ * stands for �floor�.
993
+ *
994
+ * r will satisfy n=q*d+r, and r will satisfy 0<=abs(r)<abs(d).
995
+ *
996
+ * This function calculates only the remainder.
997
+ *
998
+ * The remainder can be negative, so the return value is the absolute value of
999
+ * the remainder.
1000
+ */
1001
+ DEFUN_INT_DIV(fmod, mpz_fdiv_r)
1002
+ DEFUN_INT_DIV(cdiv, mpz_cdiv_q)
1003
+ DEFUN_INT_DIV(cmod, mpz_cdiv_r)
1004
+
1005
+ /*
1006
+ * Document-method: com
1007
+ *
1008
+ * call-seq:
1009
+ * integer.com
1010
+ *
1011
+ * From the GMP Manual:
1012
+ *
1013
+ * Returns the one's complement of +integer+.
1014
+ */
1015
+ /*
1016
+ * Document-method: com!
1017
+ *
1018
+ * call-seq:
1019
+ * integer.com!
1020
+ *
1021
+ * From the GMP Manual:
1022
+ *
1023
+ * Sets +integer+ to its one's complement.
1024
+ */
1025
+ DEFUN_INT2INT(com, mpz_com)
1026
+ /*
1027
+ * Document-method: nextprime
1028
+ *
1029
+ * call-seq:
1030
+ * integer.nextprime
1031
+ *
1032
+ * From the GMP Manual:
1033
+ *
1034
+ * Returns the next prime greater than +integer+.
1035
+ *
1036
+ * This function uses a probabilistic algorithm to identify primes. For
1037
+ * practical purposes it's adequate, the chance of a composite passing will be
1038
+ * extremely small.
1039
+ */
1040
+ /*
1041
+ * Document-method: nextprime!
1042
+ *
1043
+ * call-seq:
1044
+ * integer.nextprime!
1045
+ *
1046
+ * From the GMP Manual:
1047
+ *
1048
+ * Sets +integer+ to the next prime greater than +integer+.
1049
+ *
1050
+ * This function uses a probabilistic algorithm to identify primes. For
1051
+ * practical purposes it's adequate, the chance of a composite passing will be
1052
+ * extremely small.
1053
+ */
1054
+ DEFUN_INT2INT(nextprime, mpz_nextprime)
1055
+
1056
+ /*
1057
+ * call-seq: probab_prime?([reps])
1058
+ *
1059
+ * Determine whether +n+ is prime. Returns 2 if +n+ is definitely prime,
1060
+ * returns 1 if +n+ is probably prime (without being certain), or return 0 if
1061
+ * +n+ is definitely composite.
1062
+ *
1063
+ * This function does some trial divisions, then some Miller-Rabin
1064
+ * probabilistic primality tests. +reps+ controls how many such tests are done,
1065
+ * 5 to 10 is a reasonable number, more will reduce the chances of a composite
1066
+ * being returned as �probably prime�.
1067
+ *
1068
+ * Miller-Rabin and similar tests can be more properly called compositeness
1069
+ * tests. Numbers which fail are known to be composite but those which pass
1070
+ * might be prime or might be composite. Only a few composites pass, hence
1071
+ * those which pass are considered probably prime.
1072
+ */
1073
+ VALUE r_gmpz_is_probab_prime(int argc, VALUE* argv, VALUE self)
1074
+ {
1075
+ MP_INT *self_val;
1076
+ int reps_val;
1077
+ VALUE reps;
1078
+ mpz_get_struct(self, self_val);
1079
+ rb_scan_args(argc, argv, "01", &reps);
1080
+ if(NIL_P(reps)){
1081
+ reps = INT2FIX(5);
1082
+ }
1083
+ if (FIXNUM_P(reps)) {
1084
+ reps_val = FIX2INT (reps);
1085
+ } else {
1086
+ typeerror_as(X, "reps");
1087
+ }
1088
+ return INT2FIX(mpz_probab_prime_p(self_val, reps_val));
1089
+ }
1090
+
1091
+ /*
1092
+ * Document-method: popcount
1093
+ *
1094
+ * call-seq:
1095
+ * integer.popcount
1096
+ *
1097
+ * From the GMP Manual:
1098
+ *
1099
+ * If <tt>integer>=0</tt>, return the population count of <tt>integer</tt>,
1100
+ * which is the number of 1 bits in the binary representation. If
1101
+ * <tt>op<0</tt>, the number of 1s is infinite, and the return value is
1102
+ * INT2FIX(ULONG_MAX), the largest possible unsigned long.
1103
+ */
1104
+ VALUE r_gmpz_popcount(VALUE self)
1105
+ {
1106
+ MP_INT *self_val;
1107
+ mpz_get_struct(self, self_val);
1108
+ return INT2FIX(mpz_popcount(self_val));
1109
+ }
1110
+
1111
+ /*
1112
+ * Document-method: jacobi
1113
+ *
1114
+ * call-seq:
1115
+ * a.jacobi
1116
+ *
1117
+ * <b>90% sure this is incorrectly implemented. Todo.</b>
1118
+ *
1119
+ * From the GMP Manual:
1120
+ *
1121
+ * Calculate the Jacobi symbol <tt>(a/b)</tt>. This is defined only for +b+
1122
+ * odd.
1123
+ */
1124
+ VALUE r_gmpz_jacobi(VALUE self)
1125
+ {
1126
+ MP_INT *self_val, *res_val;
1127
+ VALUE res;
1128
+ mpz_get_struct(self, self_val);
1129
+ if (mpz_sgn(self_val) != 1)
1130
+ rb_raise(rb_eRangeError, "you can take jacobi symbol only of positive value");
1131
+ if (mpz_even_p(self_val))
1132
+ rb_raise(rb_eRangeError, "you can't take jacobi symbol of even value");
1133
+ mpz_make_struct_init(res, res_val);
1134
+ mpz_jacobi(res_val, self_val);
1135
+ return res;
1136
+ }
1137
+
1138
+ /*
1139
+ * Document-method: legendre
1140
+ *
1141
+ * call-seq:
1142
+ * a.legendre
1143
+ *
1144
+ * <b>90% sure this is incorrectly implemented. Todo.</b>
1145
+ *
1146
+ * From the GMP Manual:
1147
+ *
1148
+ * Calculate the Legendre symbol <tt>(a/p)</tt>. This is defined only for +p+
1149
+ * an odd positive prime, and for such +p+ it's identical to the Jacobi symbol.
1150
+ */
1151
+ VALUE r_gmpz_legendre(VALUE self)
1152
+ {
1153
+ MP_INT *self_val, *res_val;
1154
+ VALUE res;
1155
+ mpz_get_struct(self, self_val);
1156
+ if (mpz_sgn(self_val) != 1)
1157
+ rb_raise(rb_eRangeError, "you can take legendre symbol only of positive value");
1158
+ if (mpz_even_p(self_val))
1159
+ rb_raise(rb_eRangeError, "you can't take legendre symbol of even value");
1160
+ mpz_make_struct_init(res, res_val);
1161
+ mpz_legendre(res_val, self_val);
1162
+ return res;
1163
+ }
1164
+
1165
+ static VALUE r_gmpz_sqrtrem(VALUE self)
1166
+ {
1167
+ MP_INT *self_val, *sqrt_val, *rem_val;
1168
+ VALUE sqrt, rem;
1169
+
1170
+ mpz_get_struct (self, self_val);
1171
+ mpz_make_struct_init(sqrt, sqrt_val);
1172
+ mpz_make_struct_init(rem, rem_val);
1173
+ mpz_sqrtrem (sqrt_val, rem_val, self_val);
1174
+ return rb_assoc_new(sqrt, rem);
1175
+ }
1176
+
1177
+ /*
1178
+ * call-seq:
1179
+ * integer[index] = x &rarr; nil
1180
+ *
1181
+ * Sets the bit at index to x.
1182
+ */
1183
+ VALUE r_gmpz_setbit(VALUE self, VALUE bitnr, VALUE set_to)
1184
+ {
1185
+ MP_INT *self_val;
1186
+ int bitnr_val;
1187
+
1188
+ mpz_get_struct(self, self_val);
1189
+
1190
+ if (FIXNUM_P(bitnr)) {
1191
+ bitnr_val = FIX2INT (bitnr);
1192
+ } else {
1193
+ typeerror_as(X, "index");
1194
+ }
1195
+ if (RTEST(set_to)) {
1196
+ mpz_setbit(self_val, bitnr_val);
1197
+ } else {
1198
+ mpz_clrbit(self_val, bitnr_val);
1199
+ }
1200
+ return Qnil;
1201
+ }
1202
+
1203
+ /*
1204
+ * call-seq:
1205
+ * integer[index] &rarr; boolean
1206
+ *
1207
+ * Gets the bit at index, returned as either true or false.
1208
+ */
1209
+ VALUE r_gmpz_getbit(VALUE self, VALUE bitnr)
1210
+ {
1211
+ MP_INT *self_val;
1212
+ int bitnr_val;
1213
+ mpz_get_struct(self, self_val);
1214
+ if (FIXNUM_P(bitnr)) {
1215
+ bitnr_val = FIX2INT (bitnr);
1216
+ } else {
1217
+ typeerror_as(X, "index");
1218
+ }
1219
+ return mpz_tstbit(self_val, bitnr_val)?Qtrue:Qfalse;
1220
+ }
1221
+
1222
+ /*
1223
+ * Document-method: even?
1224
+ *
1225
+ * call-seq:
1226
+ * integer.even?
1227
+ *
1228
+ * From the GMP Manual:
1229
+ *
1230
+ * Determines whether integer is even. Returns true or false.
1231
+ */
1232
+ DEFUN_INT_COND_P(is_even,mpz_even_p)
1233
+ /*
1234
+ * Document-method: odd?
1235
+ *
1236
+ * call-seq:
1237
+ * integer.odd?
1238
+ *
1239
+ * From the GMP Manual:
1240
+ *
1241
+ * Determines whether integer is odd. Returns true or false.
1242
+ */
1243
+ DEFUN_INT_COND_P(is_odd,mpz_odd_p)
1244
+ /*
1245
+ * Document-method: square?
1246
+ *
1247
+ * call-seq:
1248
+ * integer.square?
1249
+ *
1250
+ * From the GMP Manual:
1251
+ *
1252
+ * Returns true if integer is a perfect square, i.e., if the square root of
1253
+ * integer is an integer. Under this definition both 0 and 1 are considered to
1254
+ * be perfect squares.
1255
+ */
1256
+ DEFUN_INT_COND_P(is_square,mpz_perfect_square_p)
1257
+ /*
1258
+ * Document-method: power?
1259
+ *
1260
+ * call-seq:
1261
+ * integer.square?
1262
+ *
1263
+ * From the GMP Manual:
1264
+ *
1265
+ * Returns true if integer is a perfect power, i.e., if there exist integers a
1266
+ * and b, with b>1, such that integer equals a raised to the power b.
1267
+ *
1268
+ * Under this definition both 0 and 1 are considered to be perfect powers.
1269
+ * Negative values of integers are accepted, but of course can only be odd
1270
+ * perfect powers.
1271
+ */
1272
+ DEFUN_INT_COND_P(is_power,mpz_perfect_power_p)
1273
+
1274
+ /*
1275
+ * call-seq:
1276
+ * integer.sgn
1277
+ *
1278
+ * From the GMP Manual:
1279
+ *
1280
+ * Returns +1 if +integer+ > 0, 0 if +integer+ == 0, and -1 if +integer+ < 0.
1281
+ */
1282
+ VALUE r_gmpz_sgn(VALUE self)
1283
+ {
1284
+ MP_INT *self_val;
1285
+ mpz_get_struct(self, self_val);
1286
+ return INT2FIX(mpz_sgn(self_val));
1287
+ }
1288
+
1289
+ /*
1290
+ * call-seq:
1291
+ * integer.powmod(exp, mod)
1292
+ *
1293
+ * From the GMP Manual:
1294
+ *
1295
+ * Returns +integer+ raised to +exp+ modulo +mod+.
1296
+ *
1297
+ * Negative +exp+ is supported if an inverse <tt>integer^-1</tt> mod
1298
+ * <tt>mod</tt> exists. If an inverse doesn't exist then a divide by zero is
1299
+ * raised.
1300
+ */
1301
+ VALUE r_gmpz_powm(VALUE self, VALUE exp, VALUE mod)
1302
+ {
1303
+ MP_INT *self_val, *res_val, *mod_val, *exp_val;
1304
+ VALUE res;
1305
+ int free_mod_val = 0;
1306
+
1307
+ if (GMPZ_P(mod)) {
1308
+ mpz_get_struct(mod, mod_val);
1309
+ if (mpz_sgn(mod_val) <= 0) {
1310
+ rb_raise (rb_eRangeError, "modulus must be positive");
1311
+ }
1312
+ } else if (FIXNUM_P(mod)) {
1313
+ if (FIX2INT(mod) <= 0) {
1314
+ rb_raise (rb_eRangeError, "modulus must be positive");
1315
+ }
1316
+ mpz_temp_alloc (mod_val);
1317
+ mpz_init_set_ui(mod_val, FIX2INT(mod));
1318
+ free_mod_val = 1;
1319
+ } else if (BIGNUM_P(mod)) {
1320
+ mpz_temp_from_bignum (mod_val, mod);
1321
+ if (mpz_sgn(mod_val) <= 0) {
1322
+ mpz_temp_free(mod_val);
1323
+ rb_raise (rb_eRangeError, "modulus must be positive");
1324
+ }
1325
+ free_mod_val = 1;
1326
+ } else {
1327
+ typeerror_as (ZXB, "modulus");
1328
+ }
1329
+ mpz_make_struct_init(res, res_val);
1330
+ mpz_get_struct(self, self_val);
1331
+
1332
+ if (GMPZ_P(exp)) {
1333
+ mpz_get_struct(exp, exp_val);
1334
+ if (mpz_sgn(mod_val) < 0) {
1335
+ rb_raise (rb_eRangeError, "exponent must be nonnegative");
1336
+ }
1337
+ mpz_powm (res_val, self_val, exp_val, mod_val);
1338
+ } else if (FIXNUM_P(exp)) {
1339
+ if (FIX2INT(exp) < 0)
1340
+ {
1341
+ if (free_mod_val)
1342
+ mpz_temp_free(mod_val);
1343
+ rb_raise (rb_eRangeError, "exponent must be nonnegative");
1344
+ }
1345
+ mpz_powm_ui (res_val, self_val, FIX2INT(exp), mod_val);
1346
+ } else if (BIGNUM_P(exp)) {
1347
+ mpz_temp_from_bignum (exp_val, exp);
1348
+ mpz_powm (res_val, self_val, exp_val, mod_val);
1349
+ mpz_temp_free (exp_val);
1350
+ } else {
1351
+ if (free_mod_val)
1352
+ mpz_temp_free(mod_val);
1353
+ typeerror_as (ZXB, "exponent");
1354
+ }
1355
+ if (free_mod_val)
1356
+ mpz_temp_free(mod_val);
1357
+ return res;
1358
+ }
1359
+
1360
+ /*
1361
+ * Document-method: **
1362
+ *
1363
+ * call-seq:
1364
+ * integer ** exp
1365
+ *
1366
+ * From the GMP Manual:
1367
+ *
1368
+ * Returns +integer+ raised to +exp+. The case 0^0 yields 1.
1369
+ */
1370
+ DEFUN_INT_F_UL(pow,mpz_pow_ui,"exponent")
1371
+ /*
1372
+ * Document-method: <<
1373
+ *
1374
+ * call-seq:
1375
+ * integer << n
1376
+ *
1377
+ * From the GMP Manual:
1378
+ *
1379
+ * Returns +integer+ times 2 raised to +n+. This operation can also be defined
1380
+ * as a left shift by +n+ bits.
1381
+ */
1382
+ DEFUN_INT_F_UL(shl,mpz_mul_2exp,"shift size")
1383
+ DEFUN_INT_F_UL(fshr,mpz_fdiv_q_2exp,"shift size")
1384
+ DEFUN_INT_F_UL(tshr,mpz_tdiv_q_2exp,"shift size")
1385
+ DEFUN_INT_F_UL(fshrm,mpz_fdiv_r_2exp,"mark size")
1386
+ DEFUN_INT_F_UL(tshrm,mpz_tdiv_r_2exp,"mark size")
1387
+
1388
+ int mpz_cmp_value(MP_INT *OP, VALUE arg)
1389
+ {
1390
+ MP_RAT *arg_val_q;
1391
+ MP_INT *arg_val_z;
1392
+ int res;
1393
+
1394
+ if (GMPZ_P(arg)) {
1395
+ mpz_get_struct(arg,arg_val_z);
1396
+ return mpz_cmp(OP,arg_val_z);
1397
+ } else if (FIXNUM_P(arg)) {
1398
+ return mpz_cmp_si(OP, FIX2INT(arg));
1399
+ } else if (GMPQ_P(arg)) {
1400
+ mpq_get_struct(arg,arg_val_q);
1401
+ mpz_temp_alloc(arg_val_z);
1402
+ mpz_init(arg_val_z);
1403
+ mpz_mul(arg_val_z, OP, mpq_denref(arg_val_q));
1404
+ res = mpz_cmp(arg_val_z, mpq_numref(arg_val_q));
1405
+ mpz_temp_free(arg_val_z);
1406
+ return res;
1407
+ } else if (GMPF_P(arg)) {
1408
+ not_yet;
1409
+ } else if (BIGNUM_P(arg)) {
1410
+ mpz_temp_from_bignum(arg_val_z, arg);
1411
+ res = mpz_cmp(OP, arg_val_z);
1412
+ mpz_temp_free(arg_val_z);
1413
+ return res;
1414
+ } else {
1415
+ typeerror_as(ZQFXB, "exponent");
1416
+ }
1417
+ }
1418
+
1419
+ VALUE r_gmpz_cmp(VALUE self, VALUE arg)
1420
+ {
1421
+ MP_INT *self_val;
1422
+ int res;
1423
+ mpz_get_struct(self,self_val);
1424
+ res = mpz_cmp_value(self_val, arg);
1425
+ if (res > 0)
1426
+ return INT2FIX(1);
1427
+ else if (res == 0)
1428
+ return INT2FIX(0);
1429
+ else
1430
+ return INT2FIX(-1);
1431
+ }
1432
+
1433
+ /*
1434
+ * Document-method: <
1435
+ *
1436
+ * call-seq:
1437
+ * int1 < int2
1438
+ *
1439
+ * Returns whether +int1+ is strictly less than +int2+.
1440
+ */
1441
+ DEFUN_INT_CMP(lt,<)
1442
+ /*
1443
+ * Document-method: <=
1444
+ *
1445
+ * call-seq:
1446
+ * int1 <= int2
1447
+ *
1448
+ * Returns whether +int1+ is less than or equal to +int2+.
1449
+ */
1450
+ DEFUN_INT_CMP(le,<=)
1451
+ /*
1452
+ * Document-method: >
1453
+ *
1454
+ * call-seq:
1455
+ * int1 > int2
1456
+ *
1457
+ * Returns whether +int1+ is strictly greater than +int2+.
1458
+ */
1459
+ DEFUN_INT_CMP(gt,>)
1460
+ /*
1461
+ * Document-method: >=
1462
+ *
1463
+ * call-seq:
1464
+ * int1 >= int2
1465
+ *
1466
+ * Returns whether +int1+ is greater than or equal to +int2+.
1467
+ */
1468
+ DEFUN_INT_CMP(ge,>=)
1469
+
1470
+ VALUE r_gmpzsg_pow(VALUE klass, VALUE base, VALUE exp)
1471
+ {
1472
+ MP_INT *res_val;
1473
+ VALUE res;
1474
+
1475
+ if (FIXNUM_P(base) && FIXNUM_P(exp))
1476
+ {
1477
+ if (FIX2INT(base) < 0)
1478
+ rb_raise (rb_eRangeError, "base must not be negative");
1479
+ if (FIX2INT(exp) < 0)
1480
+ rb_raise (rb_eRangeError, "exponent must not be negative");
1481
+ mpz_make_struct_init (res, res_val);
1482
+ mpz_ui_pow_ui (res_val, base, exp);
1483
+ return res;
1484
+ }
1485
+ return r_gmpz_pow (r_gmpzsg_new(1, &base, klass), exp);
1486
+ }
1487
+
1488
+ /*
1489
+ * Document-method: to_s
1490
+ *
1491
+ * call-seq:
1492
+ * integer.to_s
1493
+ *
1494
+ * Returns the decimal representation of +integer+, as a string.
1495
+ */
1496
+ VALUE r_gmpz_to_s(VALUE self)
1497
+ {
1498
+ MP_INT *self_val;
1499
+ char *str;
1500
+ VALUE res;
1501
+
1502
+ Data_Get_Struct(self, MP_INT, self_val);
1503
+ str = mpz_get_str(NULL, 10, self_val);
1504
+ res = rb_str_new2(str);
1505
+ free (str);
1506
+
1507
+ return res;
1508
+ }
1509
+
1510
+ void init_gmpz()
1511
+ {
1512
+ mGMP = rb_define_module("GMP");
1513
+ rb_define_module_function(mGMP, "Z", r_gmpmod_z, -1);
1514
+ rb_define_module_function(mGMP, "Q", r_gmpmod_q, -1);
1515
+ rb_define_module_function(mGMP, "F", r_gmpmod_f, -1);
1516
+
1517
+ cGMP_Z = rb_define_class_under(mGMP, "Z", rb_cInteger);
1518
+
1519
+ // Initializing, Assigning Integers
1520
+ rb_define_method(cGMP_Z, "swap", r_gmpz_swap, 1);
1521
+
1522
+ // Converting Integers
1523
+ rb_define_method(cGMP_Z, "to_i", r_gmpz_to_i, 0);
1524
+ rb_define_method(cGMP_Z, "to_d", r_gmpz_to_d, 0);
1525
+
1526
+ // Integer Arithmetic
1527
+ rb_define_method(cGMP_Z, "+", r_gmpz_add, 1);
1528
+ rb_define_method(cGMP_Z, "add!", r_gmpz_add_self, 1);
1529
+ rb_define_method(cGMP_Z, "-", r_gmpz_sub, 1);
1530
+ rb_define_method(cGMP_Z, "sub!", r_gmpz_sub_self, 1);
1531
+ rb_define_method(cGMP_Z, "*", r_gmpz_mul, 1);
1532
+
1533
+ // Integer Division
1534
+ rb_define_method(cGMP_Z, "/", r_gmpz_div, 1);
1535
+ rb_define_method(cGMP_Z, "tdiv", r_gmpz_tdiv, 1);
1536
+ rb_define_method(cGMP_Z, "tmod", r_gmpz_tmod, 1);
1537
+ rb_define_method(cGMP_Z, "fdiv", r_gmpz_fdiv, 1);
1538
+ rb_define_method(cGMP_Z, "fmod", r_gmpz_fmod, 1);
1539
+ rb_define_method(cGMP_Z, "cdiv", r_gmpz_cdiv, 1);
1540
+ rb_define_method(cGMP_Z, "cmod", r_gmpz_cmod, 1);
1541
+
1542
+ // Integer Roots
1543
+ rb_define_method(cGMP_Z, "root", r_gmpz_root, 1);
1544
+
1545
+ // Number Theoretic Functions
1546
+ rb_define_method(cGMP_Z, "remove", r_gmpz_remove, 1);
1547
+ rb_define_singleton_method(cGMP_Z, "fac", r_gmpzsg_fac, 1);
1548
+ rb_define_singleton_method(cGMP_Z, "fib", r_gmpzsg_fib, 1);
1549
+
1550
+ // Integer Comparisons
1551
+ rb_define_method(cGMP_Z, "<=>", r_gmpz_cmp, 1);
1552
+ rb_define_method(cGMP_Z, ">", r_gmpz_cmp_gt, 1);
1553
+ rb_define_method(cGMP_Z, ">=", r_gmpz_cmp_ge, 1);
1554
+ rb_define_method(cGMP_Z, "<", r_gmpz_cmp_lt, 1);
1555
+ rb_define_method(cGMP_Z, "<=", r_gmpz_cmp_le, 1);
1556
+ rb_define_method(cGMP_Z, "cmpabs", r_gmpz_cmpabs, 1);
1557
+
1558
+ // _unsorted_
1559
+ rb_define_method(cGMP_Z, "-@", r_gmpz_neg, 0);
1560
+ rb_define_method(cGMP_Z, "neg", r_gmpz_neg, 0);
1561
+ rb_define_method(cGMP_Z, "neg!", r_gmpz_neg_self, 0);
1562
+ rb_define_method(cGMP_Z, "abs", r_gmpz_abs, 0);
1563
+ rb_define_method(cGMP_Z, "abs!", r_gmpz_abs_self, 0);
1564
+ rb_define_method(cGMP_Z, "com", r_gmpz_com, 0);
1565
+ rb_define_method(cGMP_Z, "com!", r_gmpz_com_self, 0);
1566
+ rb_define_method(cGMP_Z, "&", r_gmpz_and, 1);
1567
+ rb_define_method(cGMP_Z, "|", r_gmpz_or, 1);
1568
+ rb_define_method(cGMP_Z, "^", r_gmpz_xor, 1);
1569
+ rb_define_method(cGMP_Z, "[]=", r_gmpz_setbit, 2);
1570
+ rb_define_method(cGMP_Z, "[]", r_gmpz_getbit, 1);
1571
+ rb_define_method(cGMP_Z, "scan0", r_gmpz_scan0, 1);
1572
+ rb_define_method(cGMP_Z, "scan1", r_gmpz_scan1, 1);
1573
+ rb_define_method(cGMP_Z, "even?", r_gmpz_is_even, 0);
1574
+ rb_define_method(cGMP_Z, "odd?", r_gmpz_is_odd, 0);
1575
+ rb_define_method(cGMP_Z, "sgn", r_gmpz_sgn, 0);
1576
+
1577
+ rb_define_method(cGMP_Z, "**", r_gmpz_pow, 1);
1578
+ rb_define_method(cGMP_Z, "powmod", r_gmpz_powm, 2);
1579
+
1580
+ rb_define_method(cGMP_Z, "==", r_gmpz_eq, 1);
1581
+ rb_define_method(cGMP_Z, ">>", r_gmpz_fshr, 1);
1582
+ rb_define_method(cGMP_Z, "<<", r_gmpz_shl, 1);
1583
+ rb_define_method(cGMP_Z, "tshr", r_gmpz_tshr, 1);
1584
+ rb_define_method(cGMP_Z, "lastbits_sgn", r_gmpz_tshrm, 1);
1585
+ rb_define_method(cGMP_Z, "lastbits_pos", r_gmpz_fshrm, 1);
1586
+ rb_define_method(cGMP_Z, "square?", r_gmpz_is_square, 0);
1587
+ rb_define_method(cGMP_Z, "power?", r_gmpz_is_power, 0);
1588
+ rb_define_method(cGMP_Z, "sqrt", r_gmpz_sqrt, 0);
1589
+ rb_define_method(cGMP_Z, "sqrt!", r_gmpz_sqrt_self, 0);
1590
+ rb_define_method(cGMP_Z, "sqrtrem", r_gmpz_sqrtrem, 0);
1591
+ rb_define_method(cGMP_Z, "jacobi", r_gmpz_jacobi, 0);
1592
+ rb_define_method(cGMP_Z, "legendre", r_gmpz_legendre, 0);
1593
+ rb_define_method(cGMP_Z, "probab_prime?", r_gmpz_is_probab_prime, -1);
1594
+ rb_define_method(cGMP_Z, "nextprime", r_gmpz_nextprime, 0);
1595
+ rb_define_method(cGMP_Z, "nextprime!", r_gmpz_nextprime_self, 0);
1596
+ rb_define_method(cGMP_Z, "popcount", r_gmpz_popcount, 0);
1597
+
1598
+ }