srawlins-gmp 0.1.5 → 0.1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +13 -1
- data/ext/gmpf.c +423 -0
- data/ext/gmpq.c +679 -0
- data/ext/gmpz.c +1598 -0
- data/ext/ruby_gmp.h +192 -0
- metadata +5 -1
data/CHANGELOG
CHANGED
@@ -1,4 +1,16 @@
|
|
1
|
-
|
1
|
+
0.1.5:
|
2
|
+
* Merged in reorg changes: Files like gmpz.c allow for documenting the C
|
3
|
+
extension methods.
|
4
|
+
* A good portion of the documentation has been written, may not be included
|
5
|
+
yet, but can be generated with
|
6
|
+
rdoc README.rdoc ext/*.c ext/*.h
|
7
|
+
|
8
|
+
0.1.4:
|
9
|
+
* Fixed a lot of gemspec problems
|
10
|
+
* Many more tests
|
11
|
+
* Tested on OS X 10.5.8
|
12
|
+
|
13
|
+
0.1.1:
|
2
14
|
* Attempting to revitalize through GitHub
|
3
15
|
* no changes to code yet
|
4
16
|
* modernizing files, eg with new ruby standards, towards a gem
|
data/ext/gmpf.c
ADDED
@@ -0,0 +1,423 @@
|
|
1
|
+
#include <gmpz.h>
|
2
|
+
#include <gmpq.h>
|
3
|
+
#include <gmpf.h>
|
4
|
+
|
5
|
+
/*
|
6
|
+
* Document-class: GMP::F
|
7
|
+
*
|
8
|
+
* GMP Multiple Precision floating point numbers.
|
9
|
+
*
|
10
|
+
* Instances of this class can store variables of the type mpf_t. This class
|
11
|
+
* also contains many methods that act as the functions for mpf_t variables,
|
12
|
+
* as well as a few methods that attempt to make this library more Ruby-ish.
|
13
|
+
*/
|
14
|
+
|
15
|
+
/**********************************************************************
|
16
|
+
* Macros *
|
17
|
+
**********************************************************************/
|
18
|
+
|
19
|
+
#define DEFUN_FLOAT2FLOAT(fname,mpf_fname) \
|
20
|
+
static VALUE r_gmpf_##fname(VALUE self) \
|
21
|
+
{ \
|
22
|
+
MP_FLOAT *self_val, *res_val; \
|
23
|
+
VALUE res; \
|
24
|
+
mpf_get_struct(self, self_val); \
|
25
|
+
mpf_make_struct_init(res, res_val, mpf_get_prec(self_val)); \
|
26
|
+
mpf_fname(res_val, self_val); \
|
27
|
+
return res; \
|
28
|
+
} \
|
29
|
+
\
|
30
|
+
static VALUE r_gmpf_##fname##_self(VALUE self) \
|
31
|
+
{ \
|
32
|
+
MP_FLOAT *self_val; \
|
33
|
+
mpf_get_struct(self, self_val); \
|
34
|
+
mpf_fname(self_val, self_val); \
|
35
|
+
return Qnil; \
|
36
|
+
}
|
37
|
+
|
38
|
+
#define DEFUN_FLOAT_CMP(name,CMP_OP) \
|
39
|
+
static VALUE r_gmpf_cmp_##name(VALUE self, VALUE arg) \
|
40
|
+
{ \
|
41
|
+
MP_FLOAT *self_val; \
|
42
|
+
mpf_get_struct(self,self_val); \
|
43
|
+
return (mpf_cmp_value(self_val, arg) CMP_OP 0)?Qtrue:Qfalse; \
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
/**********************************************************************
|
48
|
+
* Initializing, Assigning Floats *
|
49
|
+
**********************************************************************/
|
50
|
+
|
51
|
+
|
52
|
+
/**********************************************************************
|
53
|
+
* Converting Floats *
|
54
|
+
**********************************************************************/
|
55
|
+
|
56
|
+
VALUE r_gmpf_to_d(VALUE self)
|
57
|
+
{
|
58
|
+
MP_FLOAT *self_val;
|
59
|
+
mpf_get_struct (self, self_val);
|
60
|
+
|
61
|
+
return rb_float_new(mpf_get_d(self_val));
|
62
|
+
}
|
63
|
+
|
64
|
+
VALUE r_gmpf_to_s(VALUE self)
|
65
|
+
{
|
66
|
+
MP_FLOAT *self_val;
|
67
|
+
char *str, *str2;
|
68
|
+
VALUE res;
|
69
|
+
mp_exp_t exponent;
|
70
|
+
|
71
|
+
mpf_get_struct(self, self_val);
|
72
|
+
|
73
|
+
str = mpf_get_str(NULL, &exponent, 10, 0, self_val);
|
74
|
+
if ((strcmp (str, "NaN") == 0) ||
|
75
|
+
(strcmp (str, "Inf") == 0) ||
|
76
|
+
(strcmp (str, "-Inf") == 0))
|
77
|
+
{
|
78
|
+
res = rb_str_new2(str);
|
79
|
+
}
|
80
|
+
else
|
81
|
+
{
|
82
|
+
if (str[0] == '-')
|
83
|
+
__gmp_asprintf (&str2, "-0.%se%+ld", str+1, exponent);
|
84
|
+
else
|
85
|
+
__gmp_asprintf (&str2, "0.%se%+ld", str, exponent);
|
86
|
+
res = rb_str_new2(str2);
|
87
|
+
free (str2);
|
88
|
+
}
|
89
|
+
free (str);
|
90
|
+
return res;
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
/**********************************************************************
|
95
|
+
* Float Arithmetic *
|
96
|
+
**********************************************************************/
|
97
|
+
|
98
|
+
/*
|
99
|
+
* call-seq:
|
100
|
+
* float + other
|
101
|
+
*
|
102
|
+
* Returns the sum of +float+ and +other+. +other+ can be
|
103
|
+
* * GMP::Z
|
104
|
+
* * Fixnum
|
105
|
+
* * GMP::Q
|
106
|
+
* * GMP::F
|
107
|
+
* * Bignum
|
108
|
+
*/
|
109
|
+
VALUE r_gmpf_add(VALUE self, VALUE arg)
|
110
|
+
{
|
111
|
+
MP_FLOAT *self_val, *res_val, *arg_val_f;
|
112
|
+
MP_RAT *arg_val_q;
|
113
|
+
MP_INT *arg_val_z;
|
114
|
+
VALUE res;
|
115
|
+
unsigned long prec;
|
116
|
+
|
117
|
+
mpf_get_struct_prec (self, self_val, prec);
|
118
|
+
|
119
|
+
if (GMPF_P(arg)) {
|
120
|
+
mpf_get_struct (arg, arg_val_f);
|
121
|
+
prec_max(prec, arg_val_f);
|
122
|
+
mpf_make_struct_init(res, res_val, prec);
|
123
|
+
mpf_add(res_val, self_val, arg_val_f);
|
124
|
+
} else if (GMPQ_P(arg)) {
|
125
|
+
mpq_get_struct (arg, arg_val_q);
|
126
|
+
mpf_make_struct_init(res, res_val, prec);
|
127
|
+
mpf_set_q (res_val, arg_val_q);
|
128
|
+
mpf_add (res_val, res_val, self_val);
|
129
|
+
} else if (GMPZ_P(arg)) {
|
130
|
+
mpz_get_struct (arg, arg_val_z);
|
131
|
+
mpf_make_struct_init(res, res_val, prec);
|
132
|
+
mpf_set_z (res_val, arg_val_z);
|
133
|
+
mpf_add (res_val, res_val, self_val);
|
134
|
+
} else if (FLOAT_P(arg)) {
|
135
|
+
mpf_make_struct_init(res, res_val, prec);
|
136
|
+
mpf_set_d (res_val, FLT2DBL(arg));
|
137
|
+
mpf_add (res_val, res_val, self_val);
|
138
|
+
} else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
|
139
|
+
mpf_make_struct_init(res, res_val, prec);
|
140
|
+
mpf_set_si (res_val, FIX2INT(arg));
|
141
|
+
mpf_add (res_val, res_val, self_val);
|
142
|
+
} else if (BIGNUM_P(arg)) {
|
143
|
+
mpz_temp_from_bignum(arg_val_z, arg);
|
144
|
+
mpf_make_struct_init(res, res_val, prec);
|
145
|
+
mpf_set_z (res_val, arg_val_z);
|
146
|
+
mpf_add (res_val, res_val, self_val);
|
147
|
+
mpz_temp_free(arg_val_z);
|
148
|
+
} else {
|
149
|
+
typeerror(ZQFXBD);
|
150
|
+
}
|
151
|
+
|
152
|
+
return res;
|
153
|
+
}
|
154
|
+
|
155
|
+
VALUE r_gmpf_sub(VALUE self, VALUE arg)
|
156
|
+
{
|
157
|
+
MP_FLOAT *self_val, *res_val, *arg_val_f;
|
158
|
+
MP_RAT *arg_val_q;
|
159
|
+
MP_INT *arg_val_z;
|
160
|
+
VALUE res;
|
161
|
+
unsigned long prec;
|
162
|
+
|
163
|
+
mpf_get_struct_prec (self, self_val, prec);
|
164
|
+
|
165
|
+
if (GMPF_P(arg)) {
|
166
|
+
mpf_get_struct (arg, arg_val_f);
|
167
|
+
prec_max(prec, arg_val_f);
|
168
|
+
mpf_make_struct_init(res, res_val, prec);
|
169
|
+
mpf_sub(res_val, self_val, arg_val_f);
|
170
|
+
} else if (GMPQ_P(arg)) {
|
171
|
+
mpq_get_struct (arg, arg_val_q);
|
172
|
+
mpf_make_struct_init(res, res_val, prec);
|
173
|
+
mpf_set_q (res_val, arg_val_q);
|
174
|
+
mpf_sub (res_val, self_val, res_val);
|
175
|
+
} else if (GMPZ_P(arg)) {
|
176
|
+
mpz_get_struct (arg, arg_val_z);
|
177
|
+
mpf_make_struct_init(res, res_val, prec);
|
178
|
+
mpf_set_z (res_val, arg_val_z);
|
179
|
+
mpf_sub (res_val, self_val, res_val);
|
180
|
+
} else if (FLOAT_P(arg)) {
|
181
|
+
mpf_make_struct_init(res, res_val, prec);
|
182
|
+
mpf_set_d (res_val, FLT2DBL(arg));
|
183
|
+
mpf_sub (res_val, self_val, res_val);
|
184
|
+
} else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
|
185
|
+
mpf_make_struct_init(res, res_val, prec);
|
186
|
+
mpf_set_si (res_val, FIX2INT(arg));
|
187
|
+
mpf_sub (res_val, self_val, res_val);
|
188
|
+
} else if (BIGNUM_P(arg)) {
|
189
|
+
mpz_temp_from_bignum(arg_val_z, arg);
|
190
|
+
mpf_make_struct_init(res, res_val, prec);
|
191
|
+
mpf_set_z (res_val, arg_val_z);
|
192
|
+
mpf_sub (res_val, res_val, self_val);
|
193
|
+
mpz_temp_free(arg_val_z);
|
194
|
+
} else {
|
195
|
+
typeerror(ZQFXBD);
|
196
|
+
}
|
197
|
+
|
198
|
+
return res;
|
199
|
+
}
|
200
|
+
|
201
|
+
/*
|
202
|
+
* call-seq:
|
203
|
+
* float * other
|
204
|
+
*
|
205
|
+
* Returns the product of +float+ and +other+. +other+ can be
|
206
|
+
* * GMP::Z
|
207
|
+
* * Fixnum
|
208
|
+
* * GMP::Q
|
209
|
+
* * GMP::F
|
210
|
+
* * Bignum
|
211
|
+
*/
|
212
|
+
VALUE r_gmpf_mul(VALUE self, VALUE arg)
|
213
|
+
{
|
214
|
+
MP_FLOAT *self_val, *res_val, *arg_val_f;
|
215
|
+
MP_RAT *arg_val_q;
|
216
|
+
MP_INT *arg_val_z;
|
217
|
+
VALUE res;
|
218
|
+
unsigned long prec;
|
219
|
+
|
220
|
+
mpf_get_struct_prec (self, self_val, prec);
|
221
|
+
|
222
|
+
if (GMPF_P(arg)) {
|
223
|
+
mpf_get_struct(arg, arg_val_f);
|
224
|
+
prec_max(prec, arg_val_f);
|
225
|
+
mpf_make_struct_init(res, res_val, prec);
|
226
|
+
mpf_mul(res_val, self_val, arg_val_f);
|
227
|
+
} else if (GMPQ_P(arg)) {
|
228
|
+
mpq_get_struct(arg, arg_val_q);
|
229
|
+
mpf_make_struct_init(res, res_val, prec);
|
230
|
+
mpf_set_q(res_val, arg_val_q);
|
231
|
+
mpf_mul(res_val, self_val, res_val);
|
232
|
+
} else if (GMPZ_P(arg)) {
|
233
|
+
mpz_get_struct(arg, arg_val_z);
|
234
|
+
mpf_make_struct_init(res, res_val, prec);
|
235
|
+
mpf_set_z(res_val, arg_val_z);
|
236
|
+
mpf_mul(res_val, self_val, res_val);
|
237
|
+
} else if (FLOAT_P(arg)) {
|
238
|
+
mpf_make_struct_init(res, res_val, prec);
|
239
|
+
mpf_set_d(res_val, FLT2DBL(arg));
|
240
|
+
mpf_mul(res_val, self_val, res_val);
|
241
|
+
} else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
|
242
|
+
mpf_make_struct_init(res, res_val, prec);
|
243
|
+
mpf_set_si(res_val, FIX2INT(arg));
|
244
|
+
mpf_mul(res_val, self_val, res_val);
|
245
|
+
} else if (BIGNUM_P(arg)) {
|
246
|
+
mpz_temp_from_bignum(arg_val_z, arg);
|
247
|
+
mpf_make_struct_init(res, res_val, prec);
|
248
|
+
mpf_set_z(res_val, arg_val_z);
|
249
|
+
mpf_mul(res_val, res_val, self_val);
|
250
|
+
mpz_temp_free(arg_val_z);
|
251
|
+
} else {
|
252
|
+
typeerror(ZQFXBD);
|
253
|
+
}
|
254
|
+
|
255
|
+
return res;
|
256
|
+
}
|
257
|
+
|
258
|
+
VALUE r_gmpf_div(VALUE self, VALUE arg)
|
259
|
+
{
|
260
|
+
MP_FLOAT *self_val, *res_val, *arg_val_f;
|
261
|
+
MP_RAT *arg_val_q;
|
262
|
+
MP_INT *arg_val_z;
|
263
|
+
VALUE res;
|
264
|
+
unsigned long prec;
|
265
|
+
|
266
|
+
mpf_get_struct_prec (self, self_val, prec);
|
267
|
+
|
268
|
+
if (GMPF_P(arg)) {
|
269
|
+
mpf_get_struct (arg, arg_val_f);
|
270
|
+
prec_max(prec, arg_val_f);
|
271
|
+
mpf_make_struct_init(res, res_val, prec);
|
272
|
+
mpf_div(res_val, self_val, arg_val_f);
|
273
|
+
} else if (GMPQ_P(arg)) {
|
274
|
+
mpq_get_struct (arg, arg_val_q);
|
275
|
+
mpf_make_struct_init(res, res_val, prec);
|
276
|
+
mpf_set_q (res_val, arg_val_q);
|
277
|
+
mpf_div (res_val, self_val, res_val);
|
278
|
+
} else if (GMPZ_P(arg)) {
|
279
|
+
mpz_get_struct (arg, arg_val_z);
|
280
|
+
mpf_make_struct_init(res, res_val, prec);
|
281
|
+
mpf_set_z (res_val, arg_val_z);
|
282
|
+
mpf_div (res_val, self_val, res_val);
|
283
|
+
} else if (FLOAT_P(arg)) {
|
284
|
+
mpf_make_struct_init(res, res_val, prec);
|
285
|
+
mpf_set_d (res_val, FLT2DBL(arg));
|
286
|
+
mpf_div (res_val, self_val, res_val);
|
287
|
+
} else if (FIXNUM_P(arg)) { // _ui with sign control instead ?
|
288
|
+
mpf_make_struct_init(res, res_val, prec);
|
289
|
+
mpf_set_si (res_val, FIX2INT(arg));
|
290
|
+
mpf_div (res_val, self_val, res_val);
|
291
|
+
} else if (BIGNUM_P(arg)) {
|
292
|
+
mpz_temp_from_bignum(arg_val_z, arg);
|
293
|
+
mpf_make_struct_init(res, res_val, prec);
|
294
|
+
mpf_set_z (res_val, arg_val_z);
|
295
|
+
mpf_div (res_val, res_val, self_val);
|
296
|
+
mpz_temp_free(arg_val_z);
|
297
|
+
} else {
|
298
|
+
typeerror(ZQFXBD);
|
299
|
+
}
|
300
|
+
|
301
|
+
return res;
|
302
|
+
}
|
303
|
+
|
304
|
+
DEFUN_FLOAT2FLOAT(abs,mpf_abs)
|
305
|
+
DEFUN_FLOAT2FLOAT(neg,mpf_neg)
|
306
|
+
|
307
|
+
|
308
|
+
/**********************************************************************
|
309
|
+
* Float Comparison *
|
310
|
+
**********************************************************************/
|
311
|
+
|
312
|
+
int mpf_cmp_value(MP_FLOAT *self_val, VALUE arg)
|
313
|
+
{
|
314
|
+
MP_FLOAT *arg_val;
|
315
|
+
int result;
|
316
|
+
|
317
|
+
if (GMPF_P(arg)) {
|
318
|
+
mpf_get_struct(arg,arg_val);
|
319
|
+
return mpf_cmp (self_val, arg_val);
|
320
|
+
} else {
|
321
|
+
mpf_temp_init(arg_val, mpf_get_prec (self_val));
|
322
|
+
mpf_set_value (arg_val, arg);
|
323
|
+
result = mpf_cmp (self_val, arg_val);
|
324
|
+
mpf_temp_free(arg_val);
|
325
|
+
return result;
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
/* what does really "equal" mean ? it's not obvious */
|
330
|
+
VALUE r_gmpf_eq(VALUE self, VALUE arg)
|
331
|
+
{
|
332
|
+
MP_FLOAT *self_val;
|
333
|
+
mpf_get_struct (self,self_val);
|
334
|
+
return (mpf_cmp_value(self_val, arg) == 0) ? Qtrue : Qfalse;
|
335
|
+
}
|
336
|
+
|
337
|
+
VALUE r_gmpf_cmp(VALUE self, VALUE arg)
|
338
|
+
{
|
339
|
+
MP_FLOAT *self_val;
|
340
|
+
int res;
|
341
|
+
mpf_get_struct(self,self_val);
|
342
|
+
res = mpf_cmp_value(self_val, arg);
|
343
|
+
if (res > 0)
|
344
|
+
return INT2FIX(1);
|
345
|
+
else if (res == 0)
|
346
|
+
return INT2FIX(0);
|
347
|
+
else
|
348
|
+
return INT2FIX(-1);
|
349
|
+
}
|
350
|
+
|
351
|
+
DEFUN_FLOAT_CMP(lt,<)
|
352
|
+
DEFUN_FLOAT_CMP(le,<=)
|
353
|
+
DEFUN_FLOAT_CMP(gt,>)
|
354
|
+
DEFUN_FLOAT_CMP(ge,>=)
|
355
|
+
|
356
|
+
|
357
|
+
/**********************************************************************
|
358
|
+
* _unsorted_ *
|
359
|
+
**********************************************************************/
|
360
|
+
|
361
|
+
DEFUN_FLOAT2FLOAT(floor,mpf_floor)
|
362
|
+
DEFUN_FLOAT2FLOAT(trunc,mpf_trunc)
|
363
|
+
DEFUN_FLOAT2FLOAT(ceil,mpf_ceil)
|
364
|
+
|
365
|
+
VALUE r_gmpf_sgn(VALUE self)
|
366
|
+
{
|
367
|
+
MP_FLOAT *self_val;
|
368
|
+
mpf_get_struct(self, self_val);
|
369
|
+
return INT2FIX(mpf_sgn(self_val));
|
370
|
+
}
|
371
|
+
|
372
|
+
VALUE r_gmpf_get_prec(VALUE self)
|
373
|
+
{
|
374
|
+
MP_FLOAT *self_val;
|
375
|
+
mpf_get_struct(self, self_val);
|
376
|
+
return INT2NUM(mpf_get_prec(self_val));
|
377
|
+
}
|
378
|
+
|
379
|
+
|
380
|
+
void init_gmpf()
|
381
|
+
{
|
382
|
+
mGMP = rb_define_module("GMP");
|
383
|
+
rb_define_module_function(mGMP, "Z", r_gmpmod_z, -1);
|
384
|
+
rb_define_module_function(mGMP, "Q", r_gmpmod_q, -1);
|
385
|
+
rb_define_module_function(mGMP, "F", r_gmpmod_f, -1);
|
386
|
+
|
387
|
+
cGMP_F = rb_define_class_under (mGMP, "F", rb_cNumeric);
|
388
|
+
|
389
|
+
|
390
|
+
// Initializin, Assigning Floats
|
391
|
+
|
392
|
+
// Converting Floats
|
393
|
+
rb_define_method(cGMP_F, "to_s", r_gmpf_to_s, 0);
|
394
|
+
rb_define_method(cGMP_F, "to_d", r_gmpf_to_d, 0);
|
395
|
+
|
396
|
+
// Float Arithmetic
|
397
|
+
rb_define_method(cGMP_F, "+", r_gmpf_add, 1);
|
398
|
+
rb_define_method(cGMP_F, "-", r_gmpf_sub, 1);
|
399
|
+
rb_define_method(cGMP_F, "*", r_gmpf_mul, 1);
|
400
|
+
rb_define_method(cGMP_F, "/", r_gmpf_div, 1);
|
401
|
+
rb_define_method(cGMP_F, "-@", r_gmpf_neg, 0);
|
402
|
+
rb_define_method(cGMP_F, "neg!", r_gmpf_neg_self, 0);
|
403
|
+
rb_define_method(cGMP_F, "abs", r_gmpf_abs, 0);
|
404
|
+
rb_define_method(cGMP_F, "abs!", r_gmpf_abs_self, 0);
|
405
|
+
|
406
|
+
// Float Comparison
|
407
|
+
rb_define_method(cGMP_F, "<=>", r_gmpf_cmp, 1);
|
408
|
+
rb_define_method(cGMP_F, ">", r_gmpf_cmp_gt, 1);
|
409
|
+
rb_define_method(cGMP_F, ">=", r_gmpf_cmp_ge, 1);
|
410
|
+
rb_define_method(cGMP_F, "<", r_gmpf_cmp_lt, 1);
|
411
|
+
rb_define_method(cGMP_F, "<=", r_gmpf_cmp_le, 1);
|
412
|
+
rb_define_method(cGMP_F, "==", r_gmpf_eq, 1);
|
413
|
+
|
414
|
+
// _unsorted_
|
415
|
+
rb_define_method(cGMP_F, "floor", r_gmpf_floor, 0);
|
416
|
+
rb_define_method(cGMP_F, "floor!", r_gmpf_floor_self, 0);
|
417
|
+
rb_define_method(cGMP_F, "ceil", r_gmpf_ceil, 0);
|
418
|
+
rb_define_method(cGMP_F, "ceil!", r_gmpf_ceil_self, 0);
|
419
|
+
rb_define_method(cGMP_F, "trunc", r_gmpf_trunc, 0);
|
420
|
+
rb_define_method(cGMP_F, "trunc!", r_gmpf_trunc_self, 0);
|
421
|
+
rb_define_method(cGMP_F, "sgn", r_gmpf_sgn, 0);
|
422
|
+
rb_define_method(cGMP_F, "prec", r_gmpf_get_prec, 0);
|
423
|
+
}
|
data/ext/gmpq.c
ADDED
@@ -0,0 +1,679 @@
|
|
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
|
+
|
15
|
+
/**********************************************************************
|
16
|
+
* Macros *
|
17
|
+
**********************************************************************/
|
18
|
+
|
19
|
+
#define DEFUN_RAT_CMP(name,CMP_OP) \
|
20
|
+
static VALUE r_gmpq_cmp_##name(VALUE self, VALUE arg) \
|
21
|
+
{ \
|
22
|
+
MP_RAT *self_val; \
|
23
|
+
mpq_get_struct(self,self_val); \
|
24
|
+
return (mpq_cmp_value(self_val, arg) CMP_OP 0)?Qtrue:Qfalse; \
|
25
|
+
}
|
26
|
+
|
27
|
+
#define DEFUN_RAT2INT(fname,mpz_fname) \
|
28
|
+
static VALUE r_gmpq_##fname(VALUE self) \
|
29
|
+
{ \
|
30
|
+
MP_RAT *self_val; \
|
31
|
+
MP_INT *res_val; \
|
32
|
+
VALUE res; \
|
33
|
+
\
|
34
|
+
mpq_get_struct(self, self_val); \
|
35
|
+
mpz_make_struct_init(res, res_val) \
|
36
|
+
mpz_fname(res_val, mpq_numref(self_val), mpq_denref(self_val)); \
|
37
|
+
return res; \
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
/**********************************************************************
|
42
|
+
* Initializing Rationals *
|
43
|
+
**********************************************************************/
|
44
|
+
|
45
|
+
VALUE r_gmpq_swap(VALUE self, VALUE arg)
|
46
|
+
{
|
47
|
+
MP_RAT *self_val, *arg_val;
|
48
|
+
|
49
|
+
if (!GMPQ_P(arg)) {
|
50
|
+
rb_raise(rb_eTypeError, "Can't swap GMP::Q with object of other class");
|
51
|
+
}
|
52
|
+
|
53
|
+
mpq_get_struct(self, self_val);
|
54
|
+
mpq_get_struct(arg, arg_val);
|
55
|
+
mpq_swap(self_val,arg_val);
|
56
|
+
|
57
|
+
return Qnil;
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
/**********************************************************************
|
62
|
+
* Rational Conversions *
|
63
|
+
**********************************************************************/
|
64
|
+
|
65
|
+
/*
|
66
|
+
* call-seq:
|
67
|
+
* rational.to_d
|
68
|
+
*
|
69
|
+
* Returns +rational+ as an Float if +rational+ fits in a Float.
|
70
|
+
*
|
71
|
+
* Otherwise returns the least significant part of +rational+, with the same
|
72
|
+
* sign as +rational+.
|
73
|
+
*
|
74
|
+
* If the exponent from the conversion is too big or too small to fit a double
|
75
|
+
* then the result is system dependent. For too big an infinity is returned
|
76
|
+
* when available. For too small 0.0 is normally returned. Hardware overflow,
|
77
|
+
* underflow and denorm traps may or may not occur.
|
78
|
+
*/
|
79
|
+
VALUE r_gmpq_to_d(VALUE self)
|
80
|
+
{
|
81
|
+
MP_RAT *self_val;
|
82
|
+
mpq_get_struct(self, self_val);
|
83
|
+
|
84
|
+
return rb_float_new(mpq_get_d(self_val));
|
85
|
+
}
|
86
|
+
|
87
|
+
|
88
|
+
/**********************************************************************
|
89
|
+
* Rational Arithmetic *
|
90
|
+
**********************************************************************/
|
91
|
+
|
92
|
+
/*
|
93
|
+
* call-seq:
|
94
|
+
* rat1 + rat2
|
95
|
+
*
|
96
|
+
* Adds +rat1+ to +rat2+. +rat2+ can be
|
97
|
+
* * GMP::Z
|
98
|
+
* * Fixnum
|
99
|
+
* * GMP::Q
|
100
|
+
* * GMP::F
|
101
|
+
* * Bignum
|
102
|
+
*/
|
103
|
+
VALUE r_gmpq_add(VALUE self, VALUE arg)
|
104
|
+
{
|
105
|
+
MP_RAT *self_val, *arg_val_q, *res_val;
|
106
|
+
MP_INT *arg_val_z, *res_val_num;
|
107
|
+
VALUE res;
|
108
|
+
|
109
|
+
mpq_get_struct(self, self_val);
|
110
|
+
mpq_make_struct_init(res, res_val);
|
111
|
+
|
112
|
+
if (GMPQ_P(arg)) {
|
113
|
+
mpq_get_struct(arg,arg_val_q);
|
114
|
+
mpq_add(res_val, self_val, arg_val_q);
|
115
|
+
} else if (GMPZ_P(arg)) {
|
116
|
+
res_val_num = mpq_numref(res_val);
|
117
|
+
mpz_set(mpq_denref(res_val), mpq_denref(self_val));
|
118
|
+
mpz_get_struct(arg, arg_val_z);
|
119
|
+
mpz_mul(res_val_num, mpq_denref(self_val), arg_val_z);
|
120
|
+
mpz_add(res_val_num, res_val_num, mpq_numref(self_val));
|
121
|
+
} else if (FIXNUM_P(arg)) {
|
122
|
+
res_val_num = mpq_numref(res_val);
|
123
|
+
mpz_set(mpq_denref(res_val), mpq_denref(self_val));
|
124
|
+
mpz_mul_si(res_val_num, mpq_denref(self_val), FIX2INT(arg));
|
125
|
+
mpz_add(res_val_num, res_val_num, mpq_numref(self_val));
|
126
|
+
} else if (GMPF_P(arg)) {
|
127
|
+
return r_gmpf_add(arg,self);
|
128
|
+
} else if (BIGNUM_P(arg)) {
|
129
|
+
res_val_num = mpq_numref(res_val);
|
130
|
+
mpz_set(mpq_denref(res_val), mpq_denref(self_val));
|
131
|
+
mpz_set_bignum(res_val_num, arg);
|
132
|
+
mpz_mul(res_val_num, res_val_num, mpq_denref(self_val));
|
133
|
+
mpz_add(res_val_num, res_val_num, mpq_numref(self_val));
|
134
|
+
} else {
|
135
|
+
typeerror(ZQFXB);
|
136
|
+
}
|
137
|
+
return res;
|
138
|
+
}
|
139
|
+
|
140
|
+
/*
|
141
|
+
* call-seq:
|
142
|
+
* rat1 - rat2
|
143
|
+
*
|
144
|
+
* Subtracts +rat2+ from +rat1+. +rat2+ can be
|
145
|
+
* * GMP::Z
|
146
|
+
* * Fixnum
|
147
|
+
* * GMP::Q
|
148
|
+
* * GMP::F
|
149
|
+
* * Bignum
|
150
|
+
*/
|
151
|
+
VALUE r_gmpq_sub(VALUE self, VALUE arg)
|
152
|
+
{
|
153
|
+
MP_RAT *self_val, *arg_val_q, *res_val;
|
154
|
+
MP_INT *arg_val_z, *res_val_num;
|
155
|
+
MP_FLOAT *arg_val_f, *res_val_f;
|
156
|
+
VALUE res;
|
157
|
+
unsigned int prec;
|
158
|
+
|
159
|
+
mpq_get_struct(self, self_val);
|
160
|
+
mpq_make_struct_init(res, res_val);
|
161
|
+
|
162
|
+
if (GMPQ_P(arg)) {
|
163
|
+
mpq_get_struct(arg,arg_val_q);
|
164
|
+
mpq_sub (res_val, self_val, arg_val_q);
|
165
|
+
} else if (GMPZ_P(arg)) {
|
166
|
+
res_val_num = mpq_numref(res_val);
|
167
|
+
mpz_set (mpq_denref(res_val), mpq_denref(self_val));
|
168
|
+
mpz_get_struct(arg, arg_val_z);
|
169
|
+
mpz_mul (res_val_num, mpq_denref(self_val), arg_val_z);
|
170
|
+
mpz_neg (res_val_num, res_val_num);
|
171
|
+
mpz_add (res_val_num, res_val_num, mpq_numref(self_val));
|
172
|
+
} else if (FIXNUM_P(arg)) {
|
173
|
+
res_val_num = mpq_numref(res_val);
|
174
|
+
mpz_set (mpq_denref(res_val), mpq_denref(self_val));
|
175
|
+
mpz_mul_si (res_val_num, mpq_denref(self_val), -FIX2INT(arg));
|
176
|
+
mpz_add (res_val_num, res_val_num, mpq_numref(self_val));
|
177
|
+
} else if (GMPF_P(arg)) {
|
178
|
+
mpf_get_struct_prec (arg, arg_val_f, prec);
|
179
|
+
mpf_make_struct_init(res, res_val_f, prec);
|
180
|
+
mpf_set_q (res_val_f, self_val);
|
181
|
+
mpf_sub (res_val_f, res_val_f, arg_val_f);
|
182
|
+
} else if (BIGNUM_P(arg)) {
|
183
|
+
res_val_num = mpq_numref(res_val);
|
184
|
+
mpz_set (mpq_denref(res_val), mpq_denref(self_val));
|
185
|
+
mpz_set_bignum (res_val_num, arg);
|
186
|
+
mpz_mul (res_val_num, res_val_num, mpq_denref(self_val));
|
187
|
+
mpz_neg (res_val_num, res_val_num);
|
188
|
+
mpz_add (res_val_num, res_val_num, mpq_numref(self_val));
|
189
|
+
} else {
|
190
|
+
typeerror (ZQFXB);
|
191
|
+
}
|
192
|
+
return res;
|
193
|
+
}
|
194
|
+
|
195
|
+
/*
|
196
|
+
* call-seq:
|
197
|
+
* rat1 * rat2
|
198
|
+
*
|
199
|
+
* Multiplies +rat1+ with +rat2+. +rat2+ can be
|
200
|
+
* * GMP::Z
|
201
|
+
* * Fixnum
|
202
|
+
* * GMP::Q
|
203
|
+
* * GMP::F
|
204
|
+
* * Bignum
|
205
|
+
*/
|
206
|
+
VALUE r_gmpq_mul(VALUE self, VALUE arg)
|
207
|
+
{
|
208
|
+
MP_RAT *self_val, *arg_val_q, *res_val;
|
209
|
+
MP_INT *arg_val_z, *tmp_z;
|
210
|
+
VALUE res;
|
211
|
+
#if GMP >= 4
|
212
|
+
unsigned long tmp_ui;
|
213
|
+
#endif
|
214
|
+
|
215
|
+
mpq_get_struct(self, self_val);
|
216
|
+
mpq_make_struct_init(res, res_val);
|
217
|
+
|
218
|
+
if (GMPQ_P(arg)) {
|
219
|
+
mpq_get_struct(arg,arg_val_q);
|
220
|
+
mpq_mul(res_val, self_val, arg_val_q);
|
221
|
+
} else if (GMPZ_P(arg)) {
|
222
|
+
mpz_get_struct(arg,arg_val_z);
|
223
|
+
mpz_temp_init(tmp_z);
|
224
|
+
mpz_gcd(tmp_z, mpq_denref(self_val), arg_val_z);
|
225
|
+
mpz_divexact(mpq_denref(res_val), mpq_denref(self_val), tmp_z);
|
226
|
+
mpz_divexact(mpq_numref(res_val), arg_val_z, tmp_z);
|
227
|
+
mpz_mul(mpq_numref(res_val), mpq_numref(res_val), mpq_numref(self_val));
|
228
|
+
mpz_temp_free(tmp_z);
|
229
|
+
} else if (FIXNUM_P(arg)) {
|
230
|
+
#if GMP >= 4
|
231
|
+
if (FIX2INT(arg) > 0) {
|
232
|
+
tmp_ui = mpz_gcd_ui(0, mpq_denref(self_val), FIX2INT(arg));
|
233
|
+
} else if (FIX2INT(arg) < 0) {
|
234
|
+
tmp_ui = mpz_gcd_ui(0, mpq_denref(self_val), -FIX2INT(arg));
|
235
|
+
} else {
|
236
|
+
mpz_set_ui(mpq_numref(res_val), 0);
|
237
|
+
mpz_set_ui(mpq_denref(res_val), 1);
|
238
|
+
return res;
|
239
|
+
}
|
240
|
+
mpz_divexact_ui(mpq_denref(res_val), mpq_denref(self_val), tmp_ui);
|
241
|
+
mpz_mul_ui(mpq_numref(res_val), mpq_numref(self_val), FIX2INT(arg)/tmp_ui);
|
242
|
+
#else
|
243
|
+
mpz_set(mpq_denref(res_val), mpq_denref(self_val));
|
244
|
+
mpz_mul_si(mpq_numref(res_val), mpq_numref(self_val), FIX2INT(arg));
|
245
|
+
mpq_canonicalize(res_val);
|
246
|
+
#endif
|
247
|
+
} else if (GMPF_P(arg)) {
|
248
|
+
return r_gmpf_mul(arg, self);
|
249
|
+
} else if (BIGNUM_P(arg)) {
|
250
|
+
mpz_temp_alloc(tmp_z);
|
251
|
+
mpz_set_bignum(tmp_z, arg);
|
252
|
+
mpz_gcd(mpq_denref(res_val), mpq_denref(self_val), tmp_z);
|
253
|
+
mpz_divexact(mpq_numref(res_val), tmp_z, mpq_denref(res_val));
|
254
|
+
mpz_divexact(mpq_denref(res_val), mpq_denref(self_val), mpq_denref(res_val));
|
255
|
+
mpz_mul(mpq_numref(res_val), mpq_numref(res_val), mpq_numref(self_val));
|
256
|
+
mpz_temp_free(tmp_z);
|
257
|
+
} else {
|
258
|
+
typeerror(ZQFXB);
|
259
|
+
}
|
260
|
+
return res;
|
261
|
+
}
|
262
|
+
|
263
|
+
/*
|
264
|
+
* call-seq:
|
265
|
+
* rat1 / rat2
|
266
|
+
*
|
267
|
+
* Divides +rat1+ by +rat2+. +rat2+ can be
|
268
|
+
* * GMP::Z
|
269
|
+
* * Fixnum
|
270
|
+
* * GMP::Q
|
271
|
+
* * GMP::F
|
272
|
+
* * Bignum
|
273
|
+
*/
|
274
|
+
VALUE r_gmpq_div(VALUE self, VALUE arg)
|
275
|
+
{
|
276
|
+
MP_RAT *self_val, *arg_val_q, *res_val;
|
277
|
+
MP_INT *arg_val_z, *tmp_z;
|
278
|
+
MP_FLOAT *arg_val_f, *res_val_f;
|
279
|
+
VALUE res;
|
280
|
+
unsigned long tmp_ui, prec;
|
281
|
+
|
282
|
+
mpq_get_struct(self, self_val);
|
283
|
+
mpq_make_struct_init(res, res_val);
|
284
|
+
|
285
|
+
if (GMPQ_P(arg)) {
|
286
|
+
mpq_get_struct(arg,arg_val_q);
|
287
|
+
if (mpz_sgn(mpq_numref(arg_val_q)) == 0)
|
288
|
+
rb_raise(rb_eZeroDivError, "divided by 0");
|
289
|
+
mpq_div(res_val, self_val, arg_val_q);
|
290
|
+
} else if (GMPZ_P(arg)) {
|
291
|
+
mpz_get_struct(arg,arg_val_z);
|
292
|
+
mpz_temp_init(tmp_z);
|
293
|
+
mpz_gcd(tmp_z, mpq_numref(self_val), arg_val_z);
|
294
|
+
mpz_divexact(mpq_numref(res_val), mpq_numref(self_val), tmp_z);
|
295
|
+
mpz_divexact(mpq_denref(res_val), arg_val_z, tmp_z);
|
296
|
+
mpz_mul(mpq_denref(res_val), mpq_denref(res_val), mpq_denref(self_val));
|
297
|
+
mpz_temp_free(tmp_z);
|
298
|
+
} else if (FIXNUM_P(arg)) {
|
299
|
+
if (FIX2INT(arg) == 0)
|
300
|
+
rb_raise(rb_eZeroDivError, "divided by 0");
|
301
|
+
if (FIX2INT(arg) > 0) {
|
302
|
+
tmp_ui = mpz_gcd_ui(0, mpq_numref(self_val), FIX2INT(arg));
|
303
|
+
} else {
|
304
|
+
tmp_ui = mpz_gcd_ui(0, mpq_numref(self_val), -FIX2INT(arg));
|
305
|
+
}
|
306
|
+
mpz_divexact_ui(mpq_numref(res_val), mpq_numref(self_val), tmp_ui);
|
307
|
+
mpz_mul_ui(mpq_denref(res_val), mpq_denref(self_val), FIX2INT(arg)/tmp_ui);
|
308
|
+
} else if (GMPF_P(arg)) {
|
309
|
+
mpf_get_struct_prec(arg, arg_val_f, prec);
|
310
|
+
mpf_make_struct_init(res, res_val_f, prec);
|
311
|
+
mpf_set_q(res_val_f, self_val);
|
312
|
+
mpf_div(res_val_f, res_val_f, arg_val_f);
|
313
|
+
} else if (BIGNUM_P(arg)) {
|
314
|
+
mpz_temp_alloc(tmp_z);
|
315
|
+
mpz_set_bignum(tmp_z, arg);
|
316
|
+
mpz_gcd(mpq_numref(res_val), mpq_numref(self_val), tmp_z);
|
317
|
+
mpz_divexact(mpq_denref(res_val), tmp_z, mpq_numref(res_val));
|
318
|
+
mpz_divexact(mpq_numref(res_val), mpq_numref(self_val), mpq_numref(res_val));
|
319
|
+
mpz_mul(mpq_denref(res_val), mpq_denref(res_val), mpq_denref(self_val));
|
320
|
+
mpz_temp_free(tmp_z);
|
321
|
+
} else {
|
322
|
+
typeerror(ZQFXB);
|
323
|
+
}
|
324
|
+
return res;
|
325
|
+
}
|
326
|
+
|
327
|
+
DEFUN_RAT2INT(floor,mpz_fdiv_q)
|
328
|
+
DEFUN_RAT2INT(trunc,mpz_tdiv_q)
|
329
|
+
DEFUN_RAT2INT(ceil,mpz_cdiv_q)
|
330
|
+
|
331
|
+
/*
|
332
|
+
* Document-method: neg
|
333
|
+
*
|
334
|
+
* call-seq:
|
335
|
+
* -rational
|
336
|
+
* rational.neg
|
337
|
+
*
|
338
|
+
* From the GMP Manual:
|
339
|
+
*
|
340
|
+
* Returns -+rational+.
|
341
|
+
*/
|
342
|
+
VALUE r_gmpq_neg(VALUE self)
|
343
|
+
{
|
344
|
+
MP_RAT *self_val, *res_val;
|
345
|
+
VALUE res;
|
346
|
+
mpq_get_struct(self, self_val);
|
347
|
+
mpq_make_struct_init(res, res_val);
|
348
|
+
mpq_neg (res_val, self_val);
|
349
|
+
return res;
|
350
|
+
}
|
351
|
+
|
352
|
+
/*
|
353
|
+
* Document-method: neg!
|
354
|
+
*
|
355
|
+
* call-seq:
|
356
|
+
* rational.neg!
|
357
|
+
*
|
358
|
+
* From the GMP Manual:
|
359
|
+
*
|
360
|
+
* Sets +rational+ to -+rational+.
|
361
|
+
*/
|
362
|
+
VALUE r_gmpq_neg_self(VALUE self)
|
363
|
+
{
|
364
|
+
MP_RAT *self_val;
|
365
|
+
mpq_get_struct(self, self_val);
|
366
|
+
mpz_neg (mpq_numref(self_val), mpq_numref(self_val));
|
367
|
+
return Qnil;
|
368
|
+
}
|
369
|
+
|
370
|
+
/*
|
371
|
+
* Document-method: abs
|
372
|
+
*
|
373
|
+
* call-seq:
|
374
|
+
* rational.abs
|
375
|
+
*
|
376
|
+
* From the GMP Manual:
|
377
|
+
*
|
378
|
+
* Returns the absolute value of +rational+.
|
379
|
+
*/
|
380
|
+
VALUE r_gmpq_abs(VALUE self)
|
381
|
+
{
|
382
|
+
MP_RAT *self_val, *res_val;
|
383
|
+
VALUE res;
|
384
|
+
mpq_get_struct(self, self_val);
|
385
|
+
mpq_make_struct_init(res, res_val);
|
386
|
+
mpz_abs (mpq_numref(res_val), mpq_numref(self_val));
|
387
|
+
mpz_set (mpq_denref(res_val), mpq_denref(self_val));
|
388
|
+
|
389
|
+
return res;
|
390
|
+
}
|
391
|
+
|
392
|
+
/*
|
393
|
+
* Document-method: abs!
|
394
|
+
*
|
395
|
+
* call-seq:
|
396
|
+
* rational.abs!
|
397
|
+
*
|
398
|
+
* From the GMP Manual:
|
399
|
+
*
|
400
|
+
* Sets +rational+ to its absolute value.
|
401
|
+
*/
|
402
|
+
VALUE r_gmpq_abs_self(VALUE self)
|
403
|
+
{
|
404
|
+
MP_RAT *self_val;
|
405
|
+
mpq_get_struct(self, self_val);
|
406
|
+
mpz_abs (mpq_numref(self_val), mpq_numref(self_val));
|
407
|
+
return Qnil;
|
408
|
+
}
|
409
|
+
|
410
|
+
VALUE r_gmpq_inv(VALUE self)
|
411
|
+
{
|
412
|
+
MP_RAT *self_val, *res_val;
|
413
|
+
VALUE res;
|
414
|
+
|
415
|
+
mpq_get_struct(self, self_val);
|
416
|
+
if (mpq_sgn(self_val) == 0)
|
417
|
+
rb_raise (rb_eZeroDivError, "divided by 0");
|
418
|
+
mpq_make_struct_init(res, res_val);
|
419
|
+
mpq_inv (res_val, self_val);
|
420
|
+
|
421
|
+
return res;
|
422
|
+
}
|
423
|
+
|
424
|
+
VALUE r_gmpq_inv_self(VALUE self)
|
425
|
+
{
|
426
|
+
MP_RAT *self_val;
|
427
|
+
mpq_get_struct(self, self_val);
|
428
|
+
if (mpq_sgn(self_val) == 0)
|
429
|
+
rb_raise (rb_eZeroDivError, "divided by 0");
|
430
|
+
mpq_inv (self_val, self_val);
|
431
|
+
return Qnil;
|
432
|
+
}
|
433
|
+
|
434
|
+
|
435
|
+
/**********************************************************************
|
436
|
+
* Comparing Rationals *
|
437
|
+
**********************************************************************/
|
438
|
+
|
439
|
+
int mpq_cmp_value(MP_RAT *OP, VALUE arg)
|
440
|
+
{
|
441
|
+
MP_INT *arg_val_z, *tmp_z;
|
442
|
+
MP_RAT *arg_val_q;
|
443
|
+
int res;
|
444
|
+
|
445
|
+
if (GMPQ_P(arg)) {
|
446
|
+
mpq_get_struct(arg,arg_val_q);
|
447
|
+
return mpq_cmp(OP,arg_val_q);
|
448
|
+
} else if (GMPZ_P(arg)) {
|
449
|
+
mpz_get_struct(arg, arg_val_z);
|
450
|
+
mpz_temp_alloc(tmp_z);
|
451
|
+
mpz_init(tmp_z);
|
452
|
+
mpz_mul(tmp_z, mpq_denref(OP), arg_val_z);
|
453
|
+
res = mpz_cmp(mpq_numref(OP),tmp_z);
|
454
|
+
mpz_temp_free(tmp_z);
|
455
|
+
return res;
|
456
|
+
} else if (FIXNUM_P(arg)) {
|
457
|
+
mpz_temp_alloc(tmp_z);
|
458
|
+
mpz_init(tmp_z);
|
459
|
+
mpz_mul_si(tmp_z, mpq_denref(OP), FIX2INT(arg));
|
460
|
+
res = mpz_cmp(mpq_numref(OP), tmp_z);
|
461
|
+
mpz_temp_free(tmp_z);
|
462
|
+
return res;
|
463
|
+
} else if (GMPF_P(arg)) {
|
464
|
+
not_yet;
|
465
|
+
} else if (BIGNUM_P(arg)) {
|
466
|
+
mpz_temp_from_bignum(tmp_z, arg);
|
467
|
+
mpz_mul(tmp_z, tmp_z, mpq_denref(OP));
|
468
|
+
res = mpz_cmp(mpq_numref(OP), tmp_z);
|
469
|
+
mpz_temp_free(tmp_z);
|
470
|
+
return res;
|
471
|
+
} else {
|
472
|
+
typeerror(ZQFXB);
|
473
|
+
}
|
474
|
+
}
|
475
|
+
|
476
|
+
VALUE r_gmpq_eq(VALUE self, VALUE arg)
|
477
|
+
{
|
478
|
+
MP_RAT *self_val, *arg_val_q;
|
479
|
+
MP_INT *arg_val_z;
|
480
|
+
|
481
|
+
mpq_get_struct(self,self_val);
|
482
|
+
if (GMPQ_P(arg)) {
|
483
|
+
mpq_get_struct(arg,arg_val_q);
|
484
|
+
return mpq_equal(self_val,arg_val_q)?Qtrue:Qfalse;
|
485
|
+
} else if (GMPZ_P(arg)) {
|
486
|
+
if (mpz_cmp_ui(mpq_denref(self_val), 1) != 0)
|
487
|
+
return Qfalse;
|
488
|
+
mpz_get_struct (arg, arg_val_z);
|
489
|
+
return (mpz_cmp(mpq_numref(self_val),arg_val_z)==0)?Qtrue:Qfalse;
|
490
|
+
} else if (FIXNUM_P(arg)) {
|
491
|
+
if (mpz_cmp_ui(mpq_denref(self_val), 1) != 0)
|
492
|
+
return Qfalse;
|
493
|
+
return (mpz_cmp_ui(mpq_numref(self_val),FIX2INT(arg))==0)?Qtrue:Qfalse;
|
494
|
+
} else if (BIGNUM_P(arg)) {
|
495
|
+
if (mpz_cmp_ui(mpq_denref(self_val), 1) != 0)
|
496
|
+
return Qfalse;
|
497
|
+
mpz_temp_from_bignum(arg_val_z, arg);
|
498
|
+
if (mpz_cmp (mpq_numref(self_val),arg_val_z) == 0) {
|
499
|
+
mpz_temp_free (arg_val_z);
|
500
|
+
return Qtrue;
|
501
|
+
} else {
|
502
|
+
mpz_temp_free (arg_val_z);
|
503
|
+
return Qfalse;
|
504
|
+
}
|
505
|
+
} else {
|
506
|
+
return Qfalse;
|
507
|
+
}
|
508
|
+
}
|
509
|
+
|
510
|
+
VALUE r_gmpq_cmp(VALUE self, VALUE arg)
|
511
|
+
{
|
512
|
+
MP_RAT *self_val;
|
513
|
+
int res;
|
514
|
+
mpq_get_struct (self,self_val);
|
515
|
+
res = mpq_cmp_value(self_val, arg);
|
516
|
+
if (res > 0)
|
517
|
+
return INT2FIX(1);
|
518
|
+
else if (res == 0)
|
519
|
+
return INT2FIX(0);
|
520
|
+
else
|
521
|
+
return INT2FIX(-1);
|
522
|
+
}
|
523
|
+
|
524
|
+
DEFUN_RAT_CMP(lt,<)
|
525
|
+
DEFUN_RAT_CMP(le,<=)
|
526
|
+
DEFUN_RAT_CMP(gt,>)
|
527
|
+
DEFUN_RAT_CMP(ge,>=)
|
528
|
+
|
529
|
+
static VALUE r_gmpq_cmpabs(VALUE self, VALUE arg)
|
530
|
+
{
|
531
|
+
MP_RAT *arg_val_q, *self_val;
|
532
|
+
MP_INT *arg_val_z, *tmp_z;
|
533
|
+
int res;
|
534
|
+
int sgnt;
|
535
|
+
|
536
|
+
mpq_get_struct(self, self_val);
|
537
|
+
|
538
|
+
if (GMPQ_P(arg)) {
|
539
|
+
mpq_get_struct(arg,arg_val_q);
|
540
|
+
sgnt = 3*mpz_sgn(mpq_numref(self_val)) + mpz_sgn(mpq_numref(arg_val_q));
|
541
|
+
switch (sgnt)
|
542
|
+
{
|
543
|
+
default:
|
544
|
+
case 0:
|
545
|
+
return INT2FIX(0);
|
546
|
+
case 1:
|
547
|
+
case -1:
|
548
|
+
return INT2FIX(-1);
|
549
|
+
case 2:
|
550
|
+
tmp_z = mpq_numref(arg_val_q);
|
551
|
+
mpz_neg (tmp_z, tmp_z);
|
552
|
+
res = mpq_cmp (self_val, arg_val_q);
|
553
|
+
mpz_neg (tmp_z, tmp_z);
|
554
|
+
return res;
|
555
|
+
case -2:
|
556
|
+
tmp_z = mpq_numref(arg_val_q);
|
557
|
+
mpz_neg (tmp_z, tmp_z);
|
558
|
+
res = mpq_cmp (self_val, arg_val_q);
|
559
|
+
mpz_neg (tmp_z, tmp_z);
|
560
|
+
return res;
|
561
|
+
case 3:
|
562
|
+
case -3:
|
563
|
+
return INT2FIX(1);
|
564
|
+
case 4:
|
565
|
+
case -4:
|
566
|
+
return INT2FIX(mpq_cmp (self_val,arg_val_q));
|
567
|
+
}
|
568
|
+
} else if (GMPZ_P(arg)) {
|
569
|
+
mpz_get_struct(arg, arg_val_z);
|
570
|
+
mpz_temp_alloc (tmp_z);
|
571
|
+
mpz_init (tmp_z);
|
572
|
+
mpz_mul (tmp_z, mpq_denref(self_val), arg_val_z);
|
573
|
+
res = mpz_cmpabs (mpq_numref(self_val),tmp_z);
|
574
|
+
mpz_temp_free (tmp_z);
|
575
|
+
return res;
|
576
|
+
} else if (FIXNUM_P(arg)) {
|
577
|
+
mpz_temp_alloc (tmp_z);
|
578
|
+
mpz_init (tmp_z);
|
579
|
+
mpz_mul_si (tmp_z, mpq_denref(self_val), FIX2INT(arg));
|
580
|
+
res = mpz_cmpabs (mpq_numref(self_val), tmp_z);
|
581
|
+
mpz_temp_free (tmp_z);
|
582
|
+
return res;
|
583
|
+
} else if (GMPF_P(arg)) {
|
584
|
+
not_yet;
|
585
|
+
} else if (BIGNUM_P(arg)) {
|
586
|
+
mpz_temp_from_bignum (tmp_z, arg);
|
587
|
+
mpz_mul (tmp_z, tmp_z, mpq_denref(self_val));
|
588
|
+
res = mpz_cmpabs (mpq_numref(self_val), tmp_z);
|
589
|
+
mpz_temp_free (tmp_z);
|
590
|
+
return res;
|
591
|
+
} else {
|
592
|
+
typeerror (ZQFXB);
|
593
|
+
}
|
594
|
+
}
|
595
|
+
|
596
|
+
/*
|
597
|
+
* call-seq:
|
598
|
+
* rational.sgn
|
599
|
+
*
|
600
|
+
* From the GMP Manual:
|
601
|
+
*
|
602
|
+
* Returns +1 if +rational+ > 0, 0 if +rational+ == 0, and -1 if +rational+ < 0.
|
603
|
+
*/
|
604
|
+
VALUE r_gmpq_sgn(VALUE self)
|
605
|
+
{
|
606
|
+
MP_RAT *self_val;
|
607
|
+
mpq_get_struct(self, self_val);
|
608
|
+
return INT2FIX(mpq_sgn(self_val));
|
609
|
+
}
|
610
|
+
|
611
|
+
/**********************************************************************
|
612
|
+
* Applying Integer Functions *
|
613
|
+
**********************************************************************/
|
614
|
+
|
615
|
+
VALUE r_gmpq_num(VALUE self)
|
616
|
+
{
|
617
|
+
MP_RAT *self_val;
|
618
|
+
MP_INT *res_val;
|
619
|
+
VALUE res;
|
620
|
+
mpq_get_struct(self,self_val);
|
621
|
+
mpz_make_struct(res, res_val);
|
622
|
+
mpz_init_set (res_val, mpq_numref (self_val));
|
623
|
+
return res;
|
624
|
+
}
|
625
|
+
|
626
|
+
VALUE r_gmpq_den(VALUE self)
|
627
|
+
{
|
628
|
+
MP_RAT *self_val;
|
629
|
+
MP_INT *res_val;
|
630
|
+
VALUE res;
|
631
|
+
mpq_get_struct(self,self_val);
|
632
|
+
mpz_make_struct(res, res_val);
|
633
|
+
mpz_init_set (res_val, mpq_denref (self_val));
|
634
|
+
return res;
|
635
|
+
}
|
636
|
+
|
637
|
+
|
638
|
+
void init_gmpq()
|
639
|
+
{
|
640
|
+
mGMP = rb_define_module("GMP");
|
641
|
+
rb_define_module_function(mGMP, "Z", r_gmpmod_z, -1);
|
642
|
+
rb_define_module_function(mGMP, "Q", r_gmpmod_q, -1);
|
643
|
+
rb_define_module_function(mGMP, "F", r_gmpmod_f, -1);
|
644
|
+
|
645
|
+
cGMP_Q = rb_define_class_under (mGMP, "Q", rb_cNumeric);
|
646
|
+
|
647
|
+
// Initializing Rationals
|
648
|
+
rb_define_method(cGMP_Q, "swap", r_gmpq_swap, 1);
|
649
|
+
|
650
|
+
// Rational Conversions
|
651
|
+
rb_define_method(cGMP_Q, "to_d", r_gmpq_to_d, 0);
|
652
|
+
|
653
|
+
// Rational Arithmetic
|
654
|
+
rb_define_method(cGMP_Q, "+", r_gmpq_add, 1);
|
655
|
+
rb_define_method(cGMP_Q, "-", r_gmpq_sub, 1);
|
656
|
+
rb_define_method(cGMP_Q, "*", r_gmpq_mul, 1);
|
657
|
+
rb_define_method(cGMP_Q, "/", r_gmpq_div, 1);
|
658
|
+
rb_define_method(cGMP_Q, "-@", r_gmpq_neg, 0);
|
659
|
+
rb_define_method(cGMP_Q, "neg!", r_gmpq_neg_self, 0);
|
660
|
+
rb_define_method(cGMP_Q, "inv", r_gmpq_inv, 0);
|
661
|
+
rb_define_method(cGMP_Q, "inv!", r_gmpq_inv_self, 0);
|
662
|
+
rb_define_method(cGMP_Q, "abs", r_gmpq_abs, 0);
|
663
|
+
rb_define_method(cGMP_Q, "abs!", r_gmpq_abs_self, 0);
|
664
|
+
|
665
|
+
// Comparing Rationals
|
666
|
+
rb_define_method(cGMP_Q, "<=>", r_gmpq_cmp, 1);
|
667
|
+
rb_define_method(cGMP_Q, ">", r_gmpq_cmp_gt, 1);
|
668
|
+
rb_define_method(cGMP_Q, ">=", r_gmpq_cmp_ge, 1);
|
669
|
+
rb_define_method(cGMP_Q, "<", r_gmpq_cmp_lt, 1);
|
670
|
+
rb_define_method(cGMP_Q, "<=", r_gmpq_cmp_le, 1);
|
671
|
+
rb_define_method(cGMP_Q, "==", r_gmpq_eq, 1);
|
672
|
+
rb_define_method(cGMP_Q, "sgn", r_gmpq_sgn, 0);
|
673
|
+
rb_define_method(cGMP_Q, "cmpabs", r_gmpq_cmpabs, 1);
|
674
|
+
|
675
|
+
// _unsorted_
|
676
|
+
rb_define_method(cGMP_Q, "floor", r_gmpq_floor, 0);
|
677
|
+
rb_define_method(cGMP_Q, "ceil", r_gmpq_ceil, 0);
|
678
|
+
rb_define_method(cGMP_Q, "trunc", r_gmpq_trunc, 0);
|
679
|
+
}
|