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