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,144 @@
1
+ #ifndef _GMPF_H_
2
+ #define _GMPF_H_
3
+
4
+ /*
5
+ * gmpf.h
6
+ *
7
+ * This file contains GMP::F stuff.
8
+ */
9
+
10
+ #include <ruby_gmp.h>
11
+
12
+ #ifdef MPFR
13
+ #define MPFR_SINGLE_FUNCTION(name) \
14
+ static VALUE r_gmpfr_##name(VALUE self) \
15
+ { \
16
+ MP_FLOAT *self_val, *res_val; \
17
+ unsigned long prec; \
18
+ VALUE res; \
19
+ \
20
+ mpf_get_struct_prec(self, self_val, prec); \
21
+ mpf_make_struct_init(res, res_val, prec); \
22
+ mpfr_##name(res_val, self_val, __gmp_default_rounding_mode); \
23
+ \
24
+ return res; \
25
+ }
26
+
27
+ MPFR_SINGLE_FUNCTION(log)
28
+ MPFR_SINGLE_FUNCTION(exp)
29
+ MPFR_SINGLE_FUNCTION(sqrt)
30
+ MPFR_SINGLE_FUNCTION(cos)
31
+ MPFR_SINGLE_FUNCTION(sin)
32
+ MPFR_SINGLE_FUNCTION(tan)
33
+ MPFR_SINGLE_FUNCTION(acos)
34
+ MPFR_SINGLE_FUNCTION(asin)
35
+ MPFR_SINGLE_FUNCTION(atan)
36
+ MPFR_SINGLE_FUNCTION(cosh)
37
+ MPFR_SINGLE_FUNCTION(sinh)
38
+ MPFR_SINGLE_FUNCTION(tanh)
39
+ MPFR_SINGLE_FUNCTION(acosh)
40
+ MPFR_SINGLE_FUNCTION(asinh)
41
+ MPFR_SINGLE_FUNCTION(atanh)
42
+ MPFR_SINGLE_FUNCTION(log1p)
43
+ MPFR_SINGLE_FUNCTION(expm1)
44
+ MPFR_SINGLE_FUNCTION(log2)
45
+ MPFR_SINGLE_FUNCTION(log10)
46
+
47
+ static VALUE r_gmpfr_nan_p(VALUE self)
48
+ {
49
+ MP_FLOAT *self_val;
50
+
51
+ mpf_get_struct(self, self_val);
52
+ if (mpfr_nan_p(self_val)) {
53
+ return Qtrue;
54
+ }
55
+ else {
56
+ return Qfalse;
57
+ }
58
+ }
59
+
60
+ static VALUE r_gmpfr_inf_p(VALUE self)
61
+ {
62
+ MP_FLOAT *self_val;
63
+
64
+ mpf_get_struct(self, self_val);
65
+ if (mpfr_inf_p(self_val)) {
66
+ return Qtrue;
67
+ }
68
+ else {
69
+ return Qfalse;
70
+ }
71
+ }
72
+
73
+ static VALUE r_gmpfr_fin_p(VALUE self)
74
+ {
75
+ if (r_gmpfr_inf_p(self)) {
76
+ return Qfalse;
77
+ }
78
+ else {
79
+ return Qtrue;
80
+ }
81
+ }
82
+
83
+ static VALUE r_gmpfr_number_p(VALUE self)
84
+ {
85
+ MP_FLOAT *self_val;
86
+
87
+ mpf_get_struct(self, self_val);
88
+ if (mpfr_number_p(self_val)) {
89
+ return Qtrue;
90
+ }
91
+ else {
92
+ return Qfalse;
93
+ }
94
+ }
95
+
96
+ static VALUE r_gmpfr_pow(VALUE self, VALUE arg)
97
+ {
98
+ MP_FLOAT *self_val, *res_val, *arg_val_f;
99
+ MP_RAT *arg_val_q;
100
+ MP_INT *arg_val_z;
101
+ unsigned long prec;
102
+ VALUE res;
103
+
104
+ mpf_get_struct_prec(self, self_val, prec);
105
+
106
+ if (GMPF_P(arg)) {
107
+ mpf_get_struct(arg, arg_val_f);
108
+ prec_max(prec, arg_val_f);
109
+ mpf_make_struct_init(res, res_val, prec);
110
+ mpfr_pow(res_val, self_val, arg_val_f, __gmp_default_rounding_mode);
111
+ } else {
112
+ mpf_make_struct_init(res, res_val, prec);
113
+
114
+ if (GMPZ_P(arg)) {
115
+ mpz_get_struct(arg, arg_val_z);
116
+ mpf_set_z(res_val, arg_val_z);
117
+ mpfr_pow(res_val, self_val, res_val, __gmp_default_rounding_mode);
118
+ } else if (GMPQ_P(arg)) {
119
+ mpq_get_struct(arg, arg_val_q);
120
+ mpf_set_q(res_val, arg_val_q);
121
+ mpfr_pow(res_val, self_val, res_val, __gmp_default_rounding_mode);
122
+ } else if (FLOAT_P(arg)) {
123
+ mpf_set_d(res_val, FLT2DBL(arg));
124
+ mpfr_pow(res_val, self_val, res_val, __gmp_default_rounding_mode);
125
+ } else if (FIXNUM_P(arg)) {
126
+ mpfr_pow_si(res_val, self_val, FIX2INT(arg), __gmp_default_rounding_mode);
127
+ } else if (BIGNUM_P(arg)) {
128
+ mpz_temp_from_bignum(arg_val_z, arg);
129
+ mpf_set_z(res_val, arg_val_z);
130
+ mpz_temp_free(arg_val_z);
131
+ mpfr_pow(res_val, self_val, res_val, __gmp_default_rounding_mode);
132
+ } else {
133
+ typeerror(ZQFXBD);
134
+ }
135
+
136
+ }
137
+
138
+ return res;
139
+ }
140
+
141
+ #endif
142
+
143
+
144
+ #endif
@@ -0,0 +1,780 @@
1
+ #include <gmpz.h>
2
+ #include <gmpq.h>
3
+ #include <gmpf.h>
4
+
5
+ /*
6
+ * Document-class: GMP::Q
7
+ *
8
+ * GMP Multiple Precision Rational Number.
9
+ *
10
+ * Instances of this class can store variables of the type mpq_t. This class
11
+ * also contains many methods that act as the functions for mpq_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_gmpq_to_d mpq_get_d
19
+ * to_s r_gmpq_to_s ?
20
+ * add r_gmpq_add mpq_add
21
+ * sub r_gmpq_sub mpq_sub
22
+ * mul r_gmpq_mul mpq_mul
23
+ * div r_gmpq_div mpq_div
24
+ * -@ r_gmpq_neg mpq_neg
25
+ * neg r_gmpq_neg mpq_neg
26
+ * neg! r_gmpq_neg_self mpq_neg
27
+ * abs r_gmpq_abs mpq_abs
28
+ * abs! r_gmpq_abs_self mpq_abs
29
+ */
30
+
31
+ /**********************************************************************
32
+ * Macros *
33
+ **********************************************************************/
34
+
35
+ #define DEFUN_RAT_CMP(name,CMP_OP) \
36
+ static VALUE r_gmpq_cmp_##name(VALUE self, VALUE arg) \
37
+ { \
38
+ MP_RAT *self_val; \
39
+ mpq_get_struct(self,self_val); \
40
+ return (mpq_cmp_value(self_val, arg) CMP_OP 0)?Qtrue:Qfalse; \
41
+ }
42
+
43
+ #define DEFUN_RAT2INT(fname,mpz_fname) \
44
+ static VALUE r_gmpq_##fname(VALUE self) \
45
+ { \
46
+ MP_RAT *self_val; \
47
+ MP_INT *res_val; \
48
+ VALUE res; \
49
+ \
50
+ mpq_get_struct(self, self_val); \
51
+ mpz_make_struct_init(res, res_val) \
52
+ mpz_fname(res_val, mpq_numref(self_val), mpq_denref(self_val)); \
53
+ return res; \
54
+ }
55
+
56
+
57
+ /**********************************************************************
58
+ * Initializing Rationals *
59
+ **********************************************************************/
60
+
61
+ /*
62
+ * call-seq:
63
+ * GMP::Q.new(arg)
64
+ *
65
+ * Creates a new GMP::Q rational, with arg as its value, converting where
66
+ * necessary.
67
+ */
68
+ VALUE r_gmpqsg_new(int argc, VALUE *argv, VALUE klass)
69
+ {
70
+ MP_RAT *res_val;
71
+ VALUE res;
72
+
73
+ (void)klass;
74
+
75
+ if (argc > 2)
76
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 0, 1 or 2)", argc);
77
+
78
+ mpq_make_struct (res, res_val);
79
+ mpq_init (res_val);
80
+ rb_obj_call_init(res, argc, argv);
81
+
82
+ return res;
83
+ }
84
+
85
+ /*
86
+ * call-seq:
87
+ * GMP::Q(arg)
88
+ *
89
+ * A convenience method for +GMP::Q.new(arg)+.
90
+ */
91
+ VALUE r_gmpmod_q(int argc, VALUE *argv, VALUE module)
92
+ {
93
+ (void)module;
94
+ return r_gmpqsg_new(argc, argv, cGMP_Q);
95
+ }
96
+
97
+ /*
98
+ * call-seq:
99
+ * rat1.swap rat2
100
+ *
101
+ * Efficiently swaps the contents of +rat1+ with +rat2+.
102
+ */
103
+ VALUE r_gmpq_swap(VALUE self, VALUE arg)
104
+ {
105
+ MP_RAT *self_val, *arg_val;
106
+
107
+ if (!GMPQ_P(arg)) {
108
+ rb_raise(rb_eTypeError, "Can't swap GMP::Q with object of other class");
109
+ }
110
+
111
+ mpq_get_struct(self, self_val);
112
+ mpq_get_struct(arg, arg_val);
113
+ mpq_swap(self_val,arg_val);
114
+
115
+ return Qnil;
116
+ }
117
+
118
+
119
+ /**********************************************************************
120
+ * Rational Conversions *
121
+ **********************************************************************/
122
+
123
+ /*
124
+ * call-seq:
125
+ * rational.to_d
126
+ *
127
+ * Returns +rational+ as an Float if +rational+ fits in a Float.
128
+ *
129
+ * Otherwise returns the least significant part of +rational+, with the same
130
+ * sign as +rational+.
131
+ *
132
+ * If the exponent from the conversion is too big or too small to fit a double
133
+ * then the result is system dependent. For too big an infinity is returned
134
+ * when available. For too small 0.0 is normally returned. Hardware overflow,
135
+ * underflow and denorm traps may or may not occur.
136
+ */
137
+ VALUE r_gmpq_to_d(VALUE self)
138
+ {
139
+ MP_RAT *self_val;
140
+ mpq_get_struct(self, self_val);
141
+
142
+ return rb_float_new(mpq_get_d(self_val));
143
+ }
144
+
145
+ /*
146
+ * Document-method: to_s
147
+ *
148
+ * call-seq:
149
+ * rational.to_s
150
+ *
151
+ * Returns the decimal representation of +rational+, as a Ruby string.
152
+ */
153
+ VALUE r_gmpq_to_s(VALUE self)
154
+ {
155
+ MP_RAT *self_val;
156
+ MP_INT *self_val_num, *self_val_den;
157
+ char *str;
158
+ VALUE res;
159
+ int sizeinbase;
160
+ int offset;
161
+
162
+ Data_Get_Struct(self, MP_RAT, self_val);
163
+
164
+ if (mpz_cmp_ui(mpq_denref(self_val), 1) == 0) {
165
+ str = mpz_get_str(NULL, 10, mpq_numref (self_val));
166
+ res = rb_str_new2(str);
167
+ free (str);
168
+ return res;
169
+ }
170
+
171
+ self_val_num = mpq_numref(self_val);
172
+ self_val_den = mpq_denref(self_val);
173
+
174
+ sizeinbase = mpz_sizeinbase (self_val_num, 10) + mpz_sizeinbase (self_val_den, 10) + 3;
175
+ str = malloc (sizeinbase);
176
+
177
+ mpz_get_str (str, 10, self_val_num);
178
+ offset = strlen (str);
179
+ str[offset] = '/';
180
+ mpz_get_str (str + offset + 1, 10, self_val_den);
181
+ res = rb_str_new2(str);
182
+ free (str);
183
+
184
+ return res;
185
+ }
186
+
187
+
188
+ /**********************************************************************
189
+ * Rational Arithmetic *
190
+ **********************************************************************/
191
+
192
+ /*
193
+ * call-seq:
194
+ * rat1 + rat2
195
+ *
196
+ * Adds +rat1+ to +rat2+. +rat2+ can be
197
+ * * GMP::Z
198
+ * * Fixnum
199
+ * * GMP::Q
200
+ * * GMP::F
201
+ * * Bignum
202
+ */
203
+ VALUE r_gmpq_add(VALUE self, VALUE arg)
204
+ {
205
+ MP_RAT *self_val, *arg_val_q, *res_val;
206
+ MP_INT *arg_val_z, *res_val_num;
207
+ VALUE res;
208
+
209
+ mpq_get_struct(self, self_val);
210
+ mpq_make_struct_init(res, res_val);
211
+
212
+ if (GMPQ_P(arg)) {
213
+ mpq_get_struct(arg,arg_val_q);
214
+ mpq_add(res_val, self_val, arg_val_q);
215
+ } else if (GMPZ_P(arg)) {
216
+ res_val_num = mpq_numref(res_val);
217
+ mpz_set(mpq_denref(res_val), mpq_denref(self_val));
218
+ mpz_get_struct(arg, arg_val_z);
219
+ mpz_mul(res_val_num, mpq_denref(self_val), arg_val_z);
220
+ mpz_add(res_val_num, res_val_num, mpq_numref(self_val));
221
+ } else if (FIXNUM_P(arg)) {
222
+ res_val_num = mpq_numref(res_val);
223
+ mpz_set(mpq_denref(res_val), mpq_denref(self_val));
224
+ mpz_mul_si(res_val_num, mpq_denref(self_val), FIX2INT(arg));
225
+ mpz_add(res_val_num, res_val_num, mpq_numref(self_val));
226
+ } else if (GMPF_P(arg)) {
227
+ return r_gmpf_add(arg,self);
228
+ } else if (BIGNUM_P(arg)) {
229
+ res_val_num = mpq_numref(res_val);
230
+ mpz_set(mpq_denref(res_val), mpq_denref(self_val));
231
+ mpz_set_bignum(res_val_num, arg);
232
+ mpz_mul(res_val_num, res_val_num, mpq_denref(self_val));
233
+ mpz_add(res_val_num, res_val_num, mpq_numref(self_val));
234
+ } else {
235
+ typeerror(ZQFXB);
236
+ }
237
+ return res;
238
+ }
239
+
240
+ /*
241
+ * call-seq:
242
+ * rat1 - rat2
243
+ *
244
+ * Subtracts +rat2+ from +rat1+. +rat2+ can be
245
+ * * GMP::Z
246
+ * * Fixnum
247
+ * * GMP::Q
248
+ * * GMP::F
249
+ * * Bignum
250
+ */
251
+ VALUE r_gmpq_sub(VALUE self, VALUE arg)
252
+ {
253
+ MP_RAT *self_val, *arg_val_q, *res_val;
254
+ MP_INT *arg_val_z, *res_val_num;
255
+ MP_FLOAT *arg_val_f, *res_val_f;
256
+ VALUE res;
257
+ unsigned int prec;
258
+
259
+ mpq_get_struct(self, self_val);
260
+ mpq_make_struct_init(res, res_val);
261
+
262
+ if (GMPQ_P(arg)) {
263
+ mpq_get_struct(arg,arg_val_q);
264
+ mpq_sub (res_val, self_val, arg_val_q);
265
+ } else if (GMPZ_P(arg)) {
266
+ res_val_num = mpq_numref(res_val);
267
+ mpz_set (mpq_denref(res_val), mpq_denref(self_val));
268
+ mpz_get_struct(arg, arg_val_z);
269
+ mpz_mul (res_val_num, mpq_denref(self_val), arg_val_z);
270
+ mpz_neg (res_val_num, res_val_num);
271
+ mpz_add (res_val_num, res_val_num, mpq_numref(self_val));
272
+ } else if (FIXNUM_P(arg)) {
273
+ res_val_num = mpq_numref(res_val);
274
+ mpz_set (mpq_denref(res_val), mpq_denref(self_val));
275
+ mpz_mul_si (res_val_num, mpq_denref(self_val), -FIX2INT(arg));
276
+ mpz_add (res_val_num, res_val_num, mpq_numref(self_val));
277
+ } else if (GMPF_P(arg)) {
278
+ mpf_get_struct_prec (arg, arg_val_f, prec);
279
+ mpf_make_struct_init(res, res_val_f, prec);
280
+ mpf_set_q (res_val_f, self_val);
281
+ mpf_sub (res_val_f, res_val_f, arg_val_f);
282
+ } else if (BIGNUM_P(arg)) {
283
+ res_val_num = mpq_numref(res_val);
284
+ mpz_set (mpq_denref(res_val), mpq_denref(self_val));
285
+ mpz_set_bignum (res_val_num, arg);
286
+ mpz_mul (res_val_num, res_val_num, mpq_denref(self_val));
287
+ mpz_neg (res_val_num, res_val_num);
288
+ mpz_add (res_val_num, res_val_num, mpq_numref(self_val));
289
+ } else {
290
+ typeerror (ZQFXB);
291
+ }
292
+ return res;
293
+ }
294
+
295
+ /*
296
+ * call-seq:
297
+ * rat1 * rat2
298
+ *
299
+ * Multiplies +rat1+ with +rat2+. +rat2+ can be
300
+ * * GMP::Z
301
+ * * Fixnum
302
+ * * GMP::Q
303
+ * * GMP::F
304
+ * * Bignum
305
+ */
306
+ VALUE r_gmpq_mul(VALUE self, VALUE arg)
307
+ {
308
+ MP_RAT *self_val, *arg_val_q, *res_val;
309
+ MP_INT *arg_val_z, *tmp_z;
310
+ VALUE res;
311
+ #if GMP >= 4
312
+ unsigned long tmp_ui;
313
+ #endif
314
+
315
+ mpq_get_struct(self, self_val);
316
+ mpq_make_struct_init(res, res_val);
317
+
318
+ if (GMPQ_P(arg)) {
319
+ mpq_get_struct(arg,arg_val_q);
320
+ mpq_mul(res_val, self_val, arg_val_q);
321
+ } else if (GMPZ_P(arg)) {
322
+ mpz_get_struct(arg,arg_val_z);
323
+ mpz_temp_init(tmp_z);
324
+ mpz_gcd(tmp_z, mpq_denref(self_val), arg_val_z);
325
+ mpz_divexact(mpq_denref(res_val), mpq_denref(self_val), tmp_z);
326
+ mpz_divexact(mpq_numref(res_val), arg_val_z, tmp_z);
327
+ mpz_mul(mpq_numref(res_val), mpq_numref(res_val), mpq_numref(self_val));
328
+ mpz_temp_free(tmp_z);
329
+ } else if (FIXNUM_P(arg)) {
330
+ #if GMP >= 4
331
+ if (FIX2INT(arg) > 0) {
332
+ tmp_ui = mpz_gcd_ui(0, mpq_denref(self_val), FIX2INT(arg));
333
+ } else if (FIX2INT(arg) < 0) {
334
+ tmp_ui = mpz_gcd_ui(0, mpq_denref(self_val), -FIX2INT(arg));
335
+ } else {
336
+ mpz_set_ui(mpq_numref(res_val), 0);
337
+ mpz_set_ui(mpq_denref(res_val), 1);
338
+ return res;
339
+ }
340
+ mpz_divexact_ui(mpq_denref(res_val), mpq_denref(self_val), tmp_ui);
341
+ mpz_mul_ui(mpq_numref(res_val), mpq_numref(self_val), FIX2INT(arg)/tmp_ui);
342
+ #else
343
+ mpz_set(mpq_denref(res_val), mpq_denref(self_val));
344
+ mpz_mul_si(mpq_numref(res_val), mpq_numref(self_val), FIX2INT(arg));
345
+ mpq_canonicalize(res_val);
346
+ #endif
347
+ } else if (GMPF_P(arg)) {
348
+ return r_gmpf_mul(arg, self);
349
+ } else if (BIGNUM_P(arg)) {
350
+ mpz_temp_alloc(tmp_z);
351
+ mpz_set_bignum(tmp_z, arg);
352
+ mpz_gcd(mpq_denref(res_val), mpq_denref(self_val), tmp_z);
353
+ mpz_divexact(mpq_numref(res_val), tmp_z, mpq_denref(res_val));
354
+ mpz_divexact(mpq_denref(res_val), mpq_denref(self_val), mpq_denref(res_val));
355
+ mpz_mul(mpq_numref(res_val), mpq_numref(res_val), mpq_numref(self_val));
356
+ mpz_temp_free(tmp_z);
357
+ } else {
358
+ typeerror(ZQFXB);
359
+ }
360
+ return res;
361
+ }
362
+
363
+ /*
364
+ * call-seq:
365
+ * rat1 / rat2
366
+ *
367
+ * Divides +rat1+ by +rat2+. +rat2+ can be
368
+ * * GMP::Z
369
+ * * Fixnum
370
+ * * GMP::Q
371
+ * * GMP::F
372
+ * * Bignum
373
+ */
374
+ VALUE r_gmpq_div(VALUE self, VALUE arg)
375
+ {
376
+ MP_RAT *self_val, *arg_val_q, *res_val;
377
+ MP_INT *arg_val_z, *tmp_z;
378
+ MP_FLOAT *arg_val_f, *res_val_f;
379
+ VALUE res;
380
+ unsigned long tmp_ui, prec;
381
+
382
+ mpq_get_struct(self, self_val);
383
+ mpq_make_struct_init(res, res_val);
384
+
385
+ if (GMPQ_P(arg)) {
386
+ mpq_get_struct(arg,arg_val_q);
387
+ if (mpz_sgn(mpq_numref(arg_val_q)) == 0)
388
+ rb_raise(rb_eZeroDivError, "divided by 0");
389
+ mpq_div(res_val, self_val, arg_val_q);
390
+ } else if (GMPZ_P(arg)) {
391
+ mpz_get_struct(arg,arg_val_z);
392
+ mpz_temp_init(tmp_z);
393
+ mpz_gcd(tmp_z, mpq_numref(self_val), arg_val_z);
394
+ mpz_divexact(mpq_numref(res_val), mpq_numref(self_val), tmp_z);
395
+ mpz_divexact(mpq_denref(res_val), arg_val_z, tmp_z);
396
+ mpz_mul(mpq_denref(res_val), mpq_denref(res_val), mpq_denref(self_val));
397
+ mpz_temp_free(tmp_z);
398
+ } else if (FIXNUM_P(arg)) {
399
+ if (FIX2INT(arg) == 0)
400
+ rb_raise(rb_eZeroDivError, "divided by 0");
401
+ if (FIX2INT(arg) > 0) {
402
+ tmp_ui = mpz_gcd_ui(0, mpq_numref(self_val), FIX2INT(arg));
403
+ } else {
404
+ tmp_ui = mpz_gcd_ui(0, mpq_numref(self_val), -FIX2INT(arg));
405
+ }
406
+ mpz_divexact_ui(mpq_numref(res_val), mpq_numref(self_val), tmp_ui);
407
+ mpz_mul_ui(mpq_denref(res_val), mpq_denref(self_val), FIX2INT(arg)/tmp_ui);
408
+ } else if (GMPF_P(arg)) {
409
+ mpf_get_struct_prec(arg, arg_val_f, prec);
410
+ mpf_make_struct_init(res, res_val_f, prec);
411
+ mpf_set_q(res_val_f, self_val);
412
+ mpf_div(res_val_f, res_val_f, arg_val_f);
413
+ } else if (BIGNUM_P(arg)) {
414
+ mpz_temp_alloc(tmp_z);
415
+ mpz_set_bignum(tmp_z, arg);
416
+ mpz_gcd(mpq_numref(res_val), mpq_numref(self_val), tmp_z);
417
+ mpz_divexact(mpq_denref(res_val), tmp_z, mpq_numref(res_val));
418
+ mpz_divexact(mpq_numref(res_val), mpq_numref(self_val), mpq_numref(res_val));
419
+ mpz_mul(mpq_denref(res_val), mpq_denref(res_val), mpq_denref(self_val));
420
+ mpz_temp_free(tmp_z);
421
+ } else {
422
+ typeerror(ZQFXB);
423
+ }
424
+ return res;
425
+ }
426
+
427
+ DEFUN_RAT2INT(floor,mpz_fdiv_q)
428
+ DEFUN_RAT2INT(trunc,mpz_tdiv_q)
429
+ DEFUN_RAT2INT(ceil,mpz_cdiv_q)
430
+
431
+ /*
432
+ * Document-method: neg
433
+ *
434
+ * call-seq:
435
+ * -rational
436
+ * rational.neg
437
+ *
438
+ * From the GMP Manual:
439
+ *
440
+ * Returns -+rational+.
441
+ */
442
+ VALUE r_gmpq_neg(VALUE self)
443
+ {
444
+ MP_RAT *self_val, *res_val;
445
+ VALUE res;
446
+ mpq_get_struct(self, self_val);
447
+ mpq_make_struct_init(res, res_val);
448
+ mpq_neg (res_val, self_val);
449
+ return res;
450
+ }
451
+
452
+ /*
453
+ * Document-method: neg!
454
+ *
455
+ * call-seq:
456
+ * rational.neg!
457
+ *
458
+ * From the GMP Manual:
459
+ *
460
+ * Sets +rational+ to -+rational+.
461
+ */
462
+ VALUE r_gmpq_neg_self(VALUE self)
463
+ {
464
+ MP_RAT *self_val;
465
+ mpq_get_struct(self, self_val);
466
+ mpz_neg (mpq_numref(self_val), mpq_numref(self_val));
467
+ return Qnil;
468
+ }
469
+
470
+ /*
471
+ * Document-method: abs
472
+ *
473
+ * call-seq:
474
+ * rational.abs
475
+ *
476
+ * From the GMP Manual:
477
+ *
478
+ * Returns the absolute value of +rational+.
479
+ */
480
+ VALUE r_gmpq_abs(VALUE self)
481
+ {
482
+ MP_RAT *self_val, *res_val;
483
+ VALUE res;
484
+ mpq_get_struct(self, self_val);
485
+ mpq_make_struct_init(res, res_val);
486
+ mpz_abs (mpq_numref(res_val), mpq_numref(self_val));
487
+ mpz_set (mpq_denref(res_val), mpq_denref(self_val));
488
+
489
+ return res;
490
+ }
491
+
492
+ /*
493
+ * Document-method: abs!
494
+ *
495
+ * call-seq:
496
+ * rational.abs!
497
+ *
498
+ * From the GMP Manual:
499
+ *
500
+ * Sets +rational+ to its absolute value.
501
+ */
502
+ VALUE r_gmpq_abs_self(VALUE self)
503
+ {
504
+ MP_RAT *self_val;
505
+ mpq_get_struct(self, self_val);
506
+ mpz_abs (mpq_numref(self_val), mpq_numref(self_val));
507
+ return Qnil;
508
+ }
509
+
510
+ VALUE r_gmpq_inv(VALUE self)
511
+ {
512
+ MP_RAT *self_val, *res_val;
513
+ VALUE res;
514
+
515
+ mpq_get_struct(self, self_val);
516
+ if (mpq_sgn(self_val) == 0)
517
+ rb_raise (rb_eZeroDivError, "divided by 0");
518
+ mpq_make_struct_init(res, res_val);
519
+ mpq_inv (res_val, self_val);
520
+
521
+ return res;
522
+ }
523
+
524
+ VALUE r_gmpq_inv_self(VALUE self)
525
+ {
526
+ MP_RAT *self_val;
527
+ mpq_get_struct(self, self_val);
528
+ if (mpq_sgn(self_val) == 0)
529
+ rb_raise (rb_eZeroDivError, "divided by 0");
530
+ mpq_inv (self_val, self_val);
531
+ return Qnil;
532
+ }
533
+
534
+
535
+ /**********************************************************************
536
+ * Comparing Rationals *
537
+ **********************************************************************/
538
+
539
+ int mpq_cmp_value(MP_RAT *OP, VALUE arg)
540
+ {
541
+ MP_INT *arg_val_z, *tmp_z;
542
+ MP_RAT *arg_val_q;
543
+ int res;
544
+
545
+ if (GMPQ_P(arg)) {
546
+ mpq_get_struct(arg,arg_val_q);
547
+ return mpq_cmp(OP,arg_val_q);
548
+ } else if (GMPZ_P(arg)) {
549
+ mpz_get_struct(arg, arg_val_z);
550
+ mpz_temp_alloc(tmp_z);
551
+ mpz_init(tmp_z);
552
+ mpz_mul(tmp_z, mpq_denref(OP), arg_val_z);
553
+ res = mpz_cmp(mpq_numref(OP),tmp_z);
554
+ mpz_temp_free(tmp_z);
555
+ return res;
556
+ } else if (FIXNUM_P(arg)) {
557
+ mpz_temp_alloc(tmp_z);
558
+ mpz_init(tmp_z);
559
+ mpz_mul_si(tmp_z, mpq_denref(OP), FIX2INT(arg));
560
+ res = mpz_cmp(mpq_numref(OP), tmp_z);
561
+ mpz_temp_free(tmp_z);
562
+ return res;
563
+ } else if (GMPF_P(arg)) {
564
+ not_yet;
565
+ } else if (BIGNUM_P(arg)) {
566
+ mpz_temp_from_bignum(tmp_z, arg);
567
+ mpz_mul(tmp_z, tmp_z, mpq_denref(OP));
568
+ res = mpz_cmp(mpq_numref(OP), tmp_z);
569
+ mpz_temp_free(tmp_z);
570
+ return res;
571
+ } else {
572
+ typeerror(ZQFXB);
573
+ }
574
+ }
575
+
576
+ VALUE r_gmpq_eq(VALUE self, VALUE arg)
577
+ {
578
+ MP_RAT *self_val, *arg_val_q;
579
+ MP_INT *arg_val_z;
580
+
581
+ mpq_get_struct(self,self_val);
582
+ if (GMPQ_P(arg)) {
583
+ mpq_get_struct(arg,arg_val_q);
584
+ return mpq_equal(self_val,arg_val_q)?Qtrue:Qfalse;
585
+ } else if (GMPZ_P(arg)) {
586
+ if (mpz_cmp_ui(mpq_denref(self_val), 1) != 0)
587
+ return Qfalse;
588
+ mpz_get_struct (arg, arg_val_z);
589
+ return (mpz_cmp(mpq_numref(self_val),arg_val_z)==0)?Qtrue:Qfalse;
590
+ } else if (FIXNUM_P(arg)) {
591
+ if (mpz_cmp_ui(mpq_denref(self_val), 1) != 0)
592
+ return Qfalse;
593
+ return (mpz_cmp_ui(mpq_numref(self_val),FIX2INT(arg))==0)?Qtrue:Qfalse;
594
+ } else if (BIGNUM_P(arg)) {
595
+ if (mpz_cmp_ui(mpq_denref(self_val), 1) != 0)
596
+ return Qfalse;
597
+ mpz_temp_from_bignum(arg_val_z, arg);
598
+ if (mpz_cmp (mpq_numref(self_val),arg_val_z) == 0) {
599
+ mpz_temp_free (arg_val_z);
600
+ return Qtrue;
601
+ } else {
602
+ mpz_temp_free (arg_val_z);
603
+ return Qfalse;
604
+ }
605
+ } else {
606
+ return Qfalse;
607
+ }
608
+ }
609
+
610
+ VALUE r_gmpq_cmp(VALUE self, VALUE arg)
611
+ {
612
+ MP_RAT *self_val;
613
+ int res;
614
+ mpq_get_struct (self,self_val);
615
+ res = mpq_cmp_value(self_val, arg);
616
+ if (res > 0)
617
+ return INT2FIX(1);
618
+ else if (res == 0)
619
+ return INT2FIX(0);
620
+ else
621
+ return INT2FIX(-1);
622
+ }
623
+
624
+ DEFUN_RAT_CMP(lt,<)
625
+ DEFUN_RAT_CMP(le,<=)
626
+ DEFUN_RAT_CMP(gt,>)
627
+ DEFUN_RAT_CMP(ge,>=)
628
+
629
+ static VALUE r_gmpq_cmpabs(VALUE self, VALUE arg)
630
+ {
631
+ MP_RAT *arg_val_q, *self_val;
632
+ MP_INT *arg_val_z, *tmp_z;
633
+ int res;
634
+ int sgnt;
635
+
636
+ mpq_get_struct(self, self_val);
637
+
638
+ if (GMPQ_P(arg)) {
639
+ mpq_get_struct(arg,arg_val_q);
640
+ sgnt = 3*mpz_sgn(mpq_numref(self_val)) + mpz_sgn(mpq_numref(arg_val_q));
641
+ switch (sgnt)
642
+ {
643
+ default:
644
+ case 0:
645
+ return INT2FIX(0);
646
+ case 1:
647
+ case -1:
648
+ return INT2FIX(-1);
649
+ case 2:
650
+ tmp_z = mpq_numref(arg_val_q);
651
+ mpz_neg (tmp_z, tmp_z);
652
+ res = mpq_cmp (self_val, arg_val_q);
653
+ mpz_neg (tmp_z, tmp_z);
654
+ return res;
655
+ case -2:
656
+ tmp_z = mpq_numref(arg_val_q);
657
+ mpz_neg (tmp_z, tmp_z);
658
+ res = mpq_cmp (self_val, arg_val_q);
659
+ mpz_neg (tmp_z, tmp_z);
660
+ return res;
661
+ case 3:
662
+ case -3:
663
+ return INT2FIX(1);
664
+ case 4:
665
+ case -4:
666
+ return INT2FIX(mpq_cmp (self_val,arg_val_q));
667
+ }
668
+ } else if (GMPZ_P(arg)) {
669
+ mpz_get_struct(arg, arg_val_z);
670
+ mpz_temp_alloc (tmp_z);
671
+ mpz_init (tmp_z);
672
+ mpz_mul (tmp_z, mpq_denref(self_val), arg_val_z);
673
+ res = mpz_cmpabs (mpq_numref(self_val),tmp_z);
674
+ mpz_temp_free (tmp_z);
675
+ return res;
676
+ } else if (FIXNUM_P(arg)) {
677
+ mpz_temp_alloc (tmp_z);
678
+ mpz_init (tmp_z);
679
+ mpz_mul_si (tmp_z, mpq_denref(self_val), FIX2INT(arg));
680
+ res = mpz_cmpabs (mpq_numref(self_val), tmp_z);
681
+ mpz_temp_free (tmp_z);
682
+ return res;
683
+ } else if (GMPF_P(arg)) {
684
+ not_yet;
685
+ } else if (BIGNUM_P(arg)) {
686
+ mpz_temp_from_bignum (tmp_z, arg);
687
+ mpz_mul (tmp_z, tmp_z, mpq_denref(self_val));
688
+ res = mpz_cmpabs (mpq_numref(self_val), tmp_z);
689
+ mpz_temp_free (tmp_z);
690
+ return res;
691
+ } else {
692
+ typeerror (ZQFXB);
693
+ }
694
+ }
695
+
696
+ /*
697
+ * call-seq:
698
+ * rational.sgn
699
+ *
700
+ * From the GMP Manual:
701
+ *
702
+ * Returns +1 if +rational+ > 0, 0 if +rational+ == 0, and -1 if +rational+ < 0.
703
+ */
704
+ VALUE r_gmpq_sgn(VALUE self)
705
+ {
706
+ MP_RAT *self_val;
707
+ mpq_get_struct(self, self_val);
708
+ return INT2FIX(mpq_sgn(self_val));
709
+ }
710
+
711
+ /**********************************************************************
712
+ * Applying Integer Functions *
713
+ **********************************************************************/
714
+
715
+ VALUE r_gmpq_num(VALUE self)
716
+ {
717
+ MP_RAT *self_val;
718
+ MP_INT *res_val;
719
+ VALUE res;
720
+ mpq_get_struct(self,self_val);
721
+ mpz_make_struct(res, res_val);
722
+ mpz_init_set (res_val, mpq_numref (self_val));
723
+ return res;
724
+ }
725
+
726
+ VALUE r_gmpq_den(VALUE self)
727
+ {
728
+ MP_RAT *self_val;
729
+ MP_INT *res_val;
730
+ VALUE res;
731
+ mpq_get_struct(self,self_val);
732
+ mpz_make_struct(res, res_val);
733
+ mpz_init_set (res_val, mpq_denref (self_val));
734
+ return res;
735
+ }
736
+
737
+
738
+ void init_gmpq()
739
+ {
740
+ mGMP = rb_define_module("GMP");
741
+ rb_define_module_function(mGMP, "Q", r_gmpmod_q, -1);
742
+
743
+ cGMP_Q = rb_define_class_under (mGMP, "Q", rb_cNumeric);
744
+
745
+ // Initializing Rationals
746
+ rb_define_singleton_method(cGMP_Q, "new", r_gmpqsg_new, -1);
747
+ rb_define_method(cGMP_Q, "swap", r_gmpq_swap, 1);
748
+
749
+ // Rational Conversions
750
+ rb_define_method(cGMP_Q, "to_d", r_gmpq_to_d, 0);
751
+ rb_define_alias(cGMP_Q, "to_f", "to_d");
752
+ rb_define_method(cGMP_Q, "to_s", r_gmpq_to_s, 0);
753
+
754
+ // Rational Arithmetic
755
+ rb_define_method(cGMP_Q, "+", r_gmpq_add, 1);
756
+ rb_define_method(cGMP_Q, "-", r_gmpq_sub, 1);
757
+ rb_define_method(cGMP_Q, "*", r_gmpq_mul, 1);
758
+ rb_define_method(cGMP_Q, "/", r_gmpq_div, 1);
759
+ rb_define_method(cGMP_Q, "-@", r_gmpq_neg, 0);
760
+ rb_define_method(cGMP_Q, "neg!", r_gmpq_neg_self, 0);
761
+ rb_define_method(cGMP_Q, "inv", r_gmpq_inv, 0);
762
+ rb_define_method(cGMP_Q, "inv!", r_gmpq_inv_self, 0);
763
+ rb_define_method(cGMP_Q, "abs", r_gmpq_abs, 0);
764
+ rb_define_method(cGMP_Q, "abs!", r_gmpq_abs_self, 0);
765
+
766
+ // Comparing Rationals
767
+ rb_define_method(cGMP_Q, "<=>", r_gmpq_cmp, 1);
768
+ rb_define_method(cGMP_Q, ">", r_gmpq_cmp_gt, 1);
769
+ rb_define_method(cGMP_Q, ">=", r_gmpq_cmp_ge, 1);
770
+ rb_define_method(cGMP_Q, "<", r_gmpq_cmp_lt, 1);
771
+ rb_define_method(cGMP_Q, "<=", r_gmpq_cmp_le, 1);
772
+ rb_define_method(cGMP_Q, "==", r_gmpq_eq, 1);
773
+ rb_define_method(cGMP_Q, "sgn", r_gmpq_sgn, 0);
774
+ rb_define_method(cGMP_Q, "cmpabs", r_gmpq_cmpabs, 1);
775
+
776
+ // _unsorted_
777
+ rb_define_method(cGMP_Q, "floor", r_gmpq_floor, 0);
778
+ rb_define_method(cGMP_Q, "ceil", r_gmpq_ceil, 0);
779
+ rb_define_method(cGMP_Q, "trunc", r_gmpq_trunc, 0);
780
+ }