gmp 0.4.0-x86-mingw32

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