srawlins-gmp 0.1.5 → 0.1.5.1

Sign up to get free protection for your applications and to get access to all the features.
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
+ }