srawlins-gmp 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,23 @@
1
+ 1.1.0:
2
+ * Attempting to revitalize through GitHub
3
+ * no changes to code yet
4
+ * modernizing files, eg with new ruby standards, towards a gem
5
+
6
+ 1.0:
7
+ * MPFR support
8
+ * better string conversion
9
+ * Debian package
10
+
11
+ alpha9:
12
+ * more GMP::F code
13
+ * GMP::Z division
14
+
15
+ alpha8:
16
+ * various minor changes
17
+
18
+ alpha7:
19
+ * more GMP::F code
20
+
21
+ alpha6:
22
+ * basic support for GMP::F
23
+ * various minor changes
data/INSTALL ADDED
@@ -0,0 +1,4 @@
1
+ To compile:
2
+ $ ./extconf.rb
3
+ $ make
4
+ $ make install
data/README.rdoc ADDED
@@ -0,0 +1,248 @@
1
+ =gmp
2
+
3
+ gmp is library providing Ruby bindings to GMP library. Here is the introduction
4
+ paragraph at http://gmplib.org/#WHAT :
5
+
6
+ * "GMP is a free library for arbitrary precision arithmetic, operating on
7
+ signed integers, rational numbers, and floating point numbers. There is no
8
+ practical limit to the precision except the ones implied by the available
9
+ memory in the machine GMP runs on. GMP has a rich set of functions, and the
10
+ functions have a regular interface.
11
+
12
+ * The main target applications for GMP are cryptography applications and
13
+ research, Internet security applications, algebra systems, computational
14
+ algebra research, etc.
15
+
16
+ * GMP is carefully designed to be as fast as possible, both for small operands
17
+ and for huge operands. The speed is achieved by using fullwords as the basic
18
+ arithmetic type, by using fast algorithms, with highly optimised assembly
19
+ code for the most common inner loops for a lot of CPUs, and by a general
20
+ emphasis on speed.
21
+
22
+ * GMP is faster than any other bignum library. The advantage for GMP increases
23
+ with the operand sizes for many operations, since GMP uses asymptotically
24
+ faster algorithms.
25
+
26
+ * The first GMP release was made in 1991. It is continually developed and
27
+ maintained, with a new release about once a year.
28
+
29
+ * GMP is distributed under the GNU LGPL. This license makes the library free to
30
+ use, share, and improve, and allows you to pass on the result. The license
31
+ gives freedoms, but also sets firm restrictions on the use with non-free
32
+ programs.
33
+
34
+ * GMP is part of the GNU project. For more information about the GNU project,
35
+ please see the official GNU web site.
36
+
37
+ * GMP's main target platforms are Unix-type systems, such as GNU/Linux,
38
+ Solaris, HP-UX, Mac OS X/Darwin, BSD, AIX, etc. It also is known to work on
39
+ Windoze in 32-bit mode.
40
+
41
+ * GMP is brought to you by a team listed in the manual.
42
+
43
+ * GMP is carefully developed and maintained, both technically and legally. We
44
+ of course inspect and test contributed code carefully, but equally
45
+ importantly we make sure we have the legal right to distribute the
46
+ contributions, meaning users can safely use GMP. To achieve this, we will ask
47
+ contributors to sign paperwork where they allow us to distribute their work."
48
+
49
+ Only GMP 4 or newer is supported. It has been officially tested with:
50
+ |-------------------------------------|
51
+ | Platform | Ruby | GMP |
52
+ |---------------|---------|-----------|
53
+ | Cygwin on x86 | 1.8.6 | GMP 4.3.1 |
54
+ |-------------------------------------|
55
+
56
+ I have not tested one wit on Ruby 1.9.x, but my educated guess is, no, it
57
+ does not behave. If only because of rubyio.h replacing ruby/io.h. This is on my
58
+ todo list. I intend to use RMagick as a guide.
59
+
60
+ =Authors
61
+
62
+ * Tomasz Wegrzanowski
63
+ * srawlins
64
+
65
+ =Classes
66
+
67
+ It provides module GMP with following classes:
68
+ * GMP::Z - infitite precision integer numbers
69
+ * GMP::Q - infitite precision rational numbers
70
+ * GMP::F - arbitrary precision floating point numbers
71
+
72
+ Numbers are created by using new().
73
+ Constructors can take following arguments:
74
+
75
+ GMP::Z.new()
76
+ GMP::Z.new(GMP::Z)
77
+ GMP::Z.new(FixNum)
78
+ GMP::Z.new(BigNum)
79
+ GMP::Z.new(String)
80
+ GMP::Q.new()
81
+ GMP::Q.new(GMP::Q)
82
+ GMP::Q.new(String)
83
+ GMP::Q.new(any GMP::Z initializer)
84
+ GMP::Q.new(any GMP::Z initializer, any GMP::Z initializer)
85
+ GMP::F.new()
86
+ GMP::F.new(GMP::Z, precision=0)
87
+ GMP::F.new(GMP::Q, precision=0)
88
+ GMP::F.new(GMP::F)
89
+ GMP::F.new(GMP::F, precision)
90
+ GMP::F.new(String, precision=0)
91
+ GMP::F.new(FixNum, precision=0)
92
+ GMP::F.new(BigNum, precision=0)
93
+ GMP::F.new(Float, precision=0)
94
+
95
+ You can also call them as:
96
+ GMP.Z(args)
97
+ GMP.Q(args)
98
+ todo GMP.F(args)
99
+
100
+ =Methods
101
+
102
+ GMP::Z, GMP::Q and GMP::F
103
+ + addition
104
+ - substraction
105
+ * multiplication
106
+ to_s convert to string
107
+ -@ negation
108
+ neg! in-place negation
109
+ abs absolute value
110
+ asb! in-place absolute value
111
+ coerce promotion of arguments
112
+ == equality test
113
+ <=>,>=,>,<=,< comparisions
114
+ class methods of GMP::Z
115
+ fac(n) factorial of n
116
+ fib(n) nth fibonacci number
117
+ pow(n,m) n to mth power
118
+ GMP::Z and GMP::Q
119
+ swap efficiently swap contents of two objects, there
120
+ is no GMP::F.swap because various GMP::F objects
121
+ may have different precisions, which would make
122
+ them unswapable
123
+ GMP::Z
124
+ add! in-place addition
125
+ sub! in-place subtraction
126
+ tdiv,fdiv,cdiv truncate, floor and ceil division
127
+ tmod,fmod,cmod truncate, floor and ceil modulus
128
+ [],[]= testing and setting bits (as booleans)
129
+ scan0,scan1 starting at bitnr (1st arg), scan for a 0 or 1
130
+ (respectively), then return the index of the
131
+ first instance.
132
+ com 2's complement
133
+ com! in-place 2's complement
134
+ &,|,^ logical operations: and, or, xor
135
+ ** power
136
+ powmod power modulo
137
+ even? is even
138
+ odd? is odd
139
+ << shift left
140
+ >> shift right, floor
141
+ tshr shift right, truncate
142
+ lastbits_pos(n) last n bits of object, modulo if negative
143
+ lastbits_sgn(n) last n bits of object, preserve sign
144
+ power? is perfect power
145
+ square? is perfect square
146
+ sqrt square root
147
+ sqrt! change the object into its square root
148
+ root(n) nth root
149
+ jacobi jacobi symbol
150
+ legendre legendre symbol
151
+ probab_prime? 0 if composite, 1 if probably prime, 2 if
152
+ certainly prime
153
+ nextprime next *probable* prime
154
+ nextprime! change the object into its next *probable* prime
155
+ popcount the number of bits equal to 1
156
+ to_i convert to FixNum or BigNum
157
+ remove(n) remove all occurences of factor n
158
+ GMP::Q and GMP::F
159
+ / division
160
+ GMP::Q
161
+ num numerator
162
+ den denominator
163
+ inv inversion
164
+ inv! in-place inversion
165
+ floor,ceil,trunc nearest integer
166
+ class methods of GMP::F
167
+ default_prec get default precision
168
+ default_prec= set default precision
169
+ GMP::F
170
+ prec get precision
171
+ floor,ceil,trunc nearest integer, GMP::F is returned, not GMP::Z
172
+ floor!,ceil!,trunc! in-place nearest integer
173
+ GMP::F (only if MPFR is available)
174
+ exp e^object
175
+ expm1 the same as (object.exp) - 1, with better precision
176
+ log natural logarithm of object
177
+ log2 binary logarithm of object
178
+ log10 decimal logarithm of object
179
+ log1p the same as (object + 1).log, with better precision
180
+ sqrt square root of the object
181
+ cos \
182
+ sin |
183
+ tan |
184
+ acos |
185
+ asin |
186
+ atan | trigonometric functions
187
+ cosh | of the object
188
+ sinh |
189
+ tanh |
190
+ aconh |
191
+ asinh |
192
+ atanh /
193
+ nan? \
194
+ infinite? | type of floating point number
195
+ finite? |
196
+ number? /
197
+ ** power
198
+
199
+ =Precision
200
+
201
+ Precision can be explicitely set as second argument for GMP::F.new().
202
+
203
+ If there is no explicit precision, highest precision of all GMP::F arguments is
204
+ used. That doesn't ensure that result will be exact. For details, consult any
205
+ paper about floating point arithmetics.
206
+
207
+ Default precision can be explicitely set by passing 0 to GMP::F.new(). In
208
+ particular, you can set precision of copy of GMP::F object by:
209
+ new_obj = GMP::F.new(old_obj, 0)
210
+
211
+ Precision argument, and default_precision will be rounded up to whatever GMP
212
+ thinks is appropriate.
213
+
214
+ =Todo
215
+
216
+ These are inherited from Tomasz. I will go through these and see which are
217
+ still relevant.
218
+
219
+ * ruby 1.9.x
220
+ * mpz_fits_* and 31 vs. 32 integer variables
221
+ * all appropriate module and class methods if there are any to add
222
+ * fix all sign issues
223
+ * floats with precision control
224
+ * random numbers
225
+ * to_s vs. inspect ?
226
+ * to_s_hex(), or more-ruby-ish, to_s(:hex)
227
+ * check if mpz_addmul_ui would optimize some statements
228
+ * some system that allow using denref and numref as normal ruby objects
229
+ * should we allocate global temporary variables like Perl GMP do ?
230
+ * takeover code that replaces all Bignums with GMP::Z
231
+ * better bignum parser
232
+ * zero-copy method for strings generation
233
+ * what should be ancestors of GMP::* classes ?
234
+ * division and modulo
235
+ * put rb_raise into nice macros
236
+ * benchmarks against Python GMP and Perl GMP
237
+ * dup methods
238
+ * integrate F into system
239
+ * should Z.[] bits be 0/1 or true/false, 0 is true, what might badly surprise users
240
+ * seriously investigate Ruby Makefile-making system
241
+ * any2small_integer()
242
+ * check asm output, especially local memory efficiency
243
+ * it might be better to use `register' for some local variables
244
+ * powm with negative exponents
245
+ * check if different sorting of operatations gives better cache usage,
246
+ * GMP::* op RubyFloat and RubyFloat op GMP::*
247
+ * sort checks
248
+ * check all new GMP4 operations
data/ext/extconf.rb ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mkmf'
4
+
5
+ dir_config('gmp')
6
+ dir_config('mpfr')
7
+
8
+ ok = true
9
+ unless have_header('gmp.h')
10
+ $stderr.puts "can't find gmp.h, try --with-gmp-include=<path>"
11
+ ok = false
12
+ end
13
+
14
+ unless have_library('gmp', '__gmpz_init')
15
+ $stderr.puts "can't find -lgmp, try --with-gmp-lib=<path>"
16
+ ok = false
17
+ end
18
+
19
+ if (have_header('mpfr.h') and
20
+ have_header('mpf2mpfr.h') and
21
+ have_library('mpfr', 'mpfr_init'))
22
+ $CFLAGS += ' -DMPFR'
23
+ end
24
+
25
+ $CFLAGS += ' -Wall -W -O6 -g'
26
+ if ok
27
+ create_makefile('gmp')
28
+ else
29
+ raise "Unable to build, correct above errors and rerun"
30
+ end
data/ext/gmp.c ADDED
@@ -0,0 +1,561 @@
1
+ /*
2
+ * gmp.c
3
+ *
4
+ * This file contains everything you would expect from a C extension.
5
+ */
6
+
7
+ #define _GNU_SOURCE
8
+ #include <stdio.h>
9
+
10
+ #include <ruby.h>
11
+ #include <gmp.h>
12
+
13
+ #ifdef MPFR
14
+
15
+ #ifdef HAVE_MPFR_H
16
+ #include <mpfr.h>
17
+ #endif /* HAVE_MPFR_H */
18
+
19
+ #ifdef HAVE_MPF2MPFR_H
20
+ #include <mpf2mpfr.h>
21
+ #endif /* HAVE_MPF2MPFR_H */
22
+
23
+ #endif /* MPFR */
24
+
25
+ #include <stdlib.h>
26
+
27
+ /*
28
+ MP_INT*, MP_RAT* and MP_FLOAT* are used because they don't have side-effects
29
+ of single-element arrays mp*_t
30
+
31
+ MP_FLOAT is defined here, as it's commented out in gmp.h
32
+ */
33
+ #if defined(MPFR) && defined(HAVE_MPFR_H)
34
+ typedef __mpfr_struct MP_FLOAT;
35
+ #else
36
+ typedef __mpf_struct MP_FLOAT;
37
+ #endif /* HAVE_MPF2MPFR_H */
38
+
39
+ #define mpz_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, MP_INT, c_var); }
40
+ #define mpq_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, MP_RAT, c_var); }
41
+ #define mpf_get_struct(ruby_var,c_var) { Data_Get_Struct(ruby_var, MP_FLOAT, c_var); }
42
+ #define mpf_get_struct_prec(ruby_var,c_var,prec) { mpf_get_struct(ruby_var,c_var); prec = mpf_get_prec(c_var); }
43
+ #define mpz_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_Z, MP_INT, 0, r_gmpz_free, c_var); }
44
+ #define mpq_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_Q, MP_RAT, 0, r_gmpq_free, c_var); }
45
+ #define mpf_make_struct(ruby_var,c_var) { ruby_var = Data_Make_Struct(cGMP_F, MP_FLOAT, 0, r_gmpf_free, c_var); }
46
+ #define mpz_make_struct_init(ruby_var,c_var) { mpz_make_struct(ruby_var,c_var); mpz_init (c_var); }
47
+ #define mpq_make_struct_init(ruby_var,c_var) { mpq_make_struct(ruby_var,c_var); mpq_init (c_var); }
48
+ #define mpf_make_struct_init(ruby_var,c_var,prec) { mpf_make_struct(ruby_var,c_var); mpf_init2 (c_var,prec); }
49
+ #define BIGNUM_P(value) (TYPE(value) == T_BIGNUM)
50
+ #define FLOAT_P(value) (TYPE(value) == T_FLOAT)
51
+ #define STRING_P(value) (TYPE(value) == T_STRING)
52
+ #define GMPZ_P(value) (rb_obj_is_instance_of(value, cGMP_Z) == Qtrue)
53
+ #define GMPQ_P(value) (rb_obj_is_instance_of(value, cGMP_Q) == Qtrue)
54
+ #define GMPF_P(value) (rb_obj_is_instance_of(value, cGMP_F) == Qtrue)
55
+ #define mpz_set_bignum(var_mpz,var_bignum) \
56
+ mpz_set_str (var_mpz, STR2CSTR (rb_funcall (var_bignum, rb_intern ("to_s"), 0)), 0);
57
+ #define mpz_temp_alloc(var) { var=malloc(sizeof(MP_INT)); }
58
+ #define mpz_temp_init(var) { mpz_temp_alloc(var); mpz_init(var); }
59
+ #define mpz_temp_from_bignum(var,var_bignum) \
60
+ { mpz_temp_alloc(var); mpz_init_set_str (var, STR2CSTR (rb_funcall (var_bignum, rb_intern ("to_s"), 0)), 0); }
61
+ #define mpz_temp_free(var) { mpz_clear(var); free(var); }
62
+ #define mpf_temp_alloc(var) { var=malloc(sizeof(MP_FLOAT)); }
63
+ #define mpf_temp_init(var,prec) { mpf_temp_alloc(var); mpf_init2(var,prec); }
64
+ #define mpf_temp_free(var) { mpf_clear(var); free(var); }
65
+ #define FLT2DBL(var) (RFLOAT(var)->value)
66
+ #define prec_max(prec,var) {if(mpf_get_prec(var) > prec) prec = mpf_get_prec(var); }
67
+
68
+ #define EXPECTED_ZQFXBD "Expected GMP::Z, GMP::Q, GMP::F, FixNum, BigNum or Float"
69
+ #define EXPECTED_ZQFXB "Expected GMP::Z, GMP::Q, GMP::F, FixNum or BigNum"
70
+ #define EXPECTED_ZXB "Expected GMP::Z, FixNum or BigNum"
71
+ #define EXPECTED_ZX "Expected GMP::Z or FixNum"
72
+ #define EXPECTED_X "Expected FixNum"
73
+ #define typeerror(expected) rb_raise(rb_eTypeError, EXPECTED_##expected)
74
+ #define typeerror_as(expected, argname) rb_raise(rb_eTypeError, EXPECTED_##expected " as " argname)
75
+
76
+ //should change exception type
77
+ #define not_yet rb_raise(rb_eTypeError,"Not implemented yet")
78
+
79
+ VALUE mGMP, cGMP_Z, cGMP_Q, cGMP_F;
80
+
81
+ static void r_gmpz_free(void *ptr) { mpz_clear (ptr); free (ptr); }
82
+ static void r_gmpq_free(void *ptr) { mpq_clear (ptr); free (ptr); }
83
+ static void r_gmpf_free(void *ptr) { mpf_clear (ptr); free (ptr); }
84
+
85
+ static VALUE r_gmpzsg_new(int argc, VALUE *argv, VALUE klass)
86
+ {
87
+ MP_INT *res_val;
88
+ VALUE res;
89
+
90
+ (void)klass;
91
+
92
+ if (argc > 1)
93
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 0 or 1)", argc);
94
+
95
+ mpz_make_struct (res, res_val);
96
+ mpz_init (res_val);
97
+
98
+ rb_obj_call_init(res, argc, argv);
99
+
100
+ return res;
101
+ }
102
+
103
+ static VALUE r_gmpqsg_new(int argc, VALUE *argv, VALUE klass)
104
+ {
105
+ MP_RAT *res_val;
106
+ VALUE res;
107
+
108
+ (void)klass;
109
+
110
+ if (argc > 2)
111
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 0, 1 or 2)", argc);
112
+
113
+ mpq_make_struct (res, res_val);
114
+ mpq_init (res_val);
115
+ rb_obj_call_init(res, argc, argv);
116
+
117
+ return res;
118
+ }
119
+
120
+ static VALUE r_gmpfsg_new(int argc, VALUE *argv, VALUE klass)
121
+ {
122
+ MP_FLOAT *res_val;
123
+ VALUE res;
124
+
125
+ (void)klass;
126
+
127
+ if (argc > 2)
128
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 0, 1 or 2)", argc);
129
+
130
+ mpf_make_struct (res, res_val);
131
+ rb_obj_call_init(res, argc, argv);
132
+
133
+ return res;
134
+ }
135
+
136
+ static void mpz_set_value(MP_INT *target, VALUE source)
137
+ {
138
+ MP_INT *source_val;
139
+
140
+ if (GMPZ_P(source)) {
141
+ mpz_get_struct(source, source_val);
142
+ mpz_set (target, source_val);
143
+ } else if (FIXNUM_P(source)) {
144
+ mpz_set_si (target, NUM2INT(source));
145
+ } else if (STRING_P(source)) {
146
+ mpz_set_str (target, STR2CSTR(source), 0);
147
+ } else if (BIGNUM_P(source)) {
148
+ mpz_set_bignum(target, source);
149
+ } else {
150
+ rb_raise (rb_eTypeError, "Don't know how to convert %s into GMP_Z", rb_class2name(rb_class_of(source)));
151
+ }
152
+ }
153
+
154
+ static VALUE r_gmpz_initialize(int argc, VALUE *argv, VALUE self)
155
+ {
156
+ MP_INT *self_val;
157
+
158
+ if (argc != 0) {
159
+ mpz_get_struct(self,self_val);
160
+ mpz_set_value (self_val, argv[0]);
161
+ }
162
+ return Qnil;
163
+ }
164
+
165
+ static void mpq_str_set(MP_RAT *ROP, char *str)
166
+ {
167
+ int i=0;
168
+
169
+ while (str[i] && str[i] != '/')
170
+ i++;
171
+
172
+ if (str[i])
173
+ {
174
+ str[i] = 0; /* You didn't see that :) */
175
+ mpz_set_str (mpq_numref(ROP), str, 0);
176
+ str[i] = '/';
177
+ mpz_set_str (mpq_denref(ROP), str+i+1, 0);
178
+ } else {
179
+ mpz_set_str (mpq_numref(ROP), str, 0);
180
+ mpz_set_ui (mpq_denref(ROP), 1);
181
+ }
182
+ mpq_canonicalize (ROP);
183
+ }
184
+
185
+
186
+ static VALUE r_gmpq_initialize(int argc, VALUE *argv, VALUE self)
187
+ {
188
+ MP_RAT *self_val, *arg_val;
189
+
190
+ if (argc != 0) {
191
+ mpq_get_struct(self, self_val);
192
+ if (argc == 1 && GMPQ_P(argv[0])) {
193
+ mpq_get_struct(argv[0], arg_val);
194
+ mpq_set (self_val, arg_val);
195
+ } else if (argc == 1 && STRING_P(argv[0])) {
196
+ mpq_str_set (self_val, STR2CSTR(argv[0]));
197
+ } else {
198
+ mpz_set_value (mpq_numref(self_val), argv[0]);
199
+ if (argc == 2) {
200
+ mpz_set_value (mpq_denref(self_val), argv[1]);
201
+ mpq_canonicalize(self_val);
202
+ }
203
+ }
204
+ }
205
+ return Qnil;
206
+ }
207
+
208
+ /* don't pass GMP::F here, it should be handled separately */
209
+ static void mpf_set_value(MP_FLOAT *self_val, VALUE arg)
210
+ {
211
+ MP_RAT *arg_val_q;
212
+ MP_INT *arg_val_z;
213
+
214
+ if (GMPQ_P(arg)) {
215
+ mpq_get_struct (arg, arg_val_q);
216
+ mpf_set_q(self_val, arg_val_q);
217
+ } else if (GMPZ_P(arg)) {
218
+ mpz_get_struct (arg, arg_val_z);
219
+ mpf_set_z(self_val, arg_val_z);
220
+ } else if (FLOAT_P(arg)) {
221
+ mpf_set_d(self_val, FLT2DBL(arg));
222
+ } else if (FIXNUM_P(arg)) {
223
+ mpf_set_si(self_val, FIX2INT(arg));
224
+ } else if (STRING_P(arg)) {
225
+ if (mpf_set_str(self_val, STR2CSTR(arg), 10) == -1) {
226
+ rb_raise (rb_eRuntimeError, "Badly formatted string");
227
+ }
228
+ } else if (BIGNUM_P(arg)) {
229
+ #if 1 /* GMP3 code */
230
+ mpz_temp_from_bignum(arg_val_z, arg);
231
+ mpf_set_z(self_val, arg_val_z);
232
+ mpz_temp_free(arg_val_z);
233
+ #endif
234
+ } else {
235
+ rb_raise (rb_eTypeError, "Don't know how to convert %s into GMP::F", rb_class2name(rb_class_of(arg)));
236
+ }
237
+ }
238
+
239
+ static VALUE r_gmpf_initialize(int argc, VALUE *argv, VALUE self)
240
+ {
241
+ MP_FLOAT *self_val, *arg_val_f;
242
+ unsigned long prec = 0;
243
+ VALUE arg;
244
+
245
+ mpf_get_struct (self, self_val);
246
+
247
+ if (argc==0) {
248
+ mpf_init(self_val);
249
+ mpf_set_si(self_val, 0);
250
+ return Qnil;
251
+ }
252
+
253
+ arg = argv[0];
254
+
255
+ if (argc == 2) {
256
+ if (FIXNUM_P(argv[1])) {
257
+ if (FIX2INT(argv[1]) >= 0)
258
+ prec = FIX2INT(argv[1]);
259
+ else
260
+ rb_raise(rb_eRangeError, "prec must be non-negative");
261
+ } else {
262
+ rb_raise(rb_eTypeError, "prec must be FixNum");
263
+ }
264
+ } else if (GMPF_P(arg)) {
265
+ mpf_get_struct (arg, arg_val_f);
266
+ prec = mpf_get_prec (arg_val_f);
267
+ }
268
+ if (prec == 0)
269
+ mpf_init (self_val);
270
+ else
271
+ mpf_init2 (self_val, prec);
272
+
273
+ if (GMPF_P(arg)) {
274
+ mpf_get_struct (arg, arg_val_f);
275
+ mpf_set(self_val, arg_val_f);
276
+ } else {
277
+ mpf_set_value(self_val, arg);
278
+ }
279
+
280
+ return Qnil;
281
+ }
282
+
283
+ /*
284
+ * call-seq: to_s()
285
+ *
286
+ * Converts this mpq_t object to a Ruby string.
287
+ */
288
+ static VALUE r_gmpq_to_s(VALUE self)
289
+ {
290
+ MP_RAT *self_val;
291
+ MP_INT *self_val_num, *self_val_den;
292
+ char *str;
293
+ VALUE res;
294
+ int sizeinbase;
295
+ int offset;
296
+
297
+ Data_Get_Struct(self, MP_RAT, self_val);
298
+
299
+ if (mpz_cmp_ui(mpq_denref(self_val), 1) == 0) {
300
+ str = mpz_get_str(NULL, 10, mpq_numref (self_val));
301
+ res = rb_str_new2(str);
302
+ free (str);
303
+ return res;
304
+ }
305
+
306
+ self_val_num = mpq_numref(self_val);
307
+ self_val_den = mpq_denref(self_val);
308
+
309
+ sizeinbase = mpz_sizeinbase (self_val_num, 10) + mpz_sizeinbase (self_val_den, 10) + 3;
310
+ str = malloc (sizeinbase);
311
+
312
+ mpz_get_str (str, 10, self_val_num);
313
+ offset = strlen (str);
314
+ str[offset] = '/';
315
+ mpz_get_str (str + offset + 1, 10, self_val_den);
316
+ res = rb_str_new2(str);
317
+ free (str);
318
+
319
+ return res;
320
+ }
321
+
322
+ static VALUE r_gmpz_coerce(VALUE self, VALUE arg)
323
+ {
324
+ return rb_assoc_new(r_gmpzsg_new(1, &arg, cGMP_Z), self);
325
+ }
326
+
327
+ static VALUE r_gmpq_coerce(VALUE self, VALUE arg)
328
+ {
329
+ return rb_assoc_new(r_gmpqsg_new(1, &arg, cGMP_Q), self);
330
+ }
331
+
332
+ static VALUE r_gmpf_coerce(VALUE self, VALUE arg)
333
+ {
334
+ return rb_assoc_new(r_gmpfsg_new(1, &arg, cGMP_F), self);
335
+ }
336
+
337
+ static VALUE r_gmpmod_z(int argc, VALUE *argv, VALUE module)
338
+ {
339
+ (void)module;
340
+ return r_gmpzsg_new(argc, argv, cGMP_Z);
341
+ }
342
+
343
+ static VALUE r_gmpmod_q(int argc, VALUE *argv, VALUE module)
344
+ {
345
+ (void)module;
346
+ return r_gmpqsg_new(argc, argv, cGMP_Q);
347
+ }
348
+
349
+ static VALUE r_gmpmod_f(int argc, VALUE *argv, VALUE module)
350
+ {
351
+ (void)module;
352
+ return r_gmpfsg_new(argc, argv, cGMP_F);
353
+ }
354
+
355
+ static VALUE r_gmpfsg_get_default_prec(VALUE klass)
356
+ {
357
+ (void)klass;
358
+ return INT2NUM(mpf_get_default_prec());
359
+ }
360
+
361
+ static VALUE r_gmpfsg_set_default_prec(VALUE klass, VALUE arg)
362
+ {
363
+ (void)klass;
364
+ if (FIXNUM_P(arg)) {
365
+ if (FIX2INT(arg) <= 0) {
366
+ rb_raise(rb_eRangeError, "prec must be positive");
367
+ }
368
+ mpf_set_default_prec (FIX2INT(arg));
369
+ } else {
370
+ rb_raise(rb_eTypeError, "prec must be FixNum");
371
+ }
372
+ return Qnil;
373
+ }
374
+
375
+ #include "gmpf.h"
376
+ #include "gmpq.h"
377
+ #include "gmpz.h"
378
+ #include "takeover.h"
379
+
380
+ #define REGISTER_TAKEOVER(fname, ruby_fname, old_fname) \
381
+ rb_define_alias(rb_cFixnum, old_fname, ruby_fname); \
382
+ rb_define_method(rb_cFixnum, ruby_fname, takeover_fixnum_##fname, -1); \
383
+ rb_define_alias(rb_cBignum, old_fname, ruby_fname); \
384
+ rb_define_method(rb_cBignum, ruby_fname, takeover_bignum_##fname, -1);
385
+
386
+ void Init_gmp () {
387
+ mGMP = rb_define_module("GMP");
388
+ rb_define_module_function(mGMP, "Z", r_gmpmod_z, -1);
389
+ rb_define_module_function(mGMP, "Q", r_gmpmod_q, -1);
390
+ rb_define_module_function(mGMP, "F", r_gmpmod_f, -1);
391
+
392
+ cGMP_Z = rb_define_class_under(mGMP, "Z", rb_cInteger);
393
+ rb_define_singleton_method(cGMP_Z, "new", r_gmpzsg_new, -1);
394
+ rb_define_singleton_method(cGMP_Z, "fib", r_gmpzsg_fib, 1);
395
+ rb_define_singleton_method(cGMP_Z, "fac", r_gmpzsg_fac, 1);
396
+ rb_define_singleton_method(cGMP_Z, "pow", r_gmpzsg_pow, 2);
397
+ rb_define_method(cGMP_Z, "initialize", r_gmpz_initialize, -1);
398
+ rb_define_method(cGMP_Z, "to_s", r_gmpz_to_s, 0);
399
+ rb_define_method(cGMP_Z, "coerce", r_gmpz_coerce, 1);
400
+ rb_define_method(cGMP_Z, "+", r_gmpz_add, 1);
401
+ rb_define_method(cGMP_Z, "add!", r_gmpz_add_self, 1);
402
+ rb_define_method(cGMP_Z, "-", r_gmpz_sub, 1);
403
+ rb_define_method(cGMP_Z, "sub!", r_gmpz_sub_self, 1);
404
+ rb_define_method(cGMP_Z, "*", r_gmpz_mul, 1);
405
+ rb_define_method(cGMP_Z, "/", r_gmpz_div, 1);
406
+ rb_define_method(cGMP_Z, "tdiv", r_gmpz_tdiv, 1);
407
+ rb_define_method(cGMP_Z, "tmod", r_gmpz_tmod, 1);
408
+ rb_define_method(cGMP_Z, "fdiv", r_gmpz_fdiv, 1);
409
+ rb_define_method(cGMP_Z, "fmod", r_gmpz_fmod, 1);
410
+ rb_define_method(cGMP_Z, "cdiv", r_gmpz_cdiv, 1);
411
+ rb_define_method(cGMP_Z, "cmod", r_gmpz_cmod, 1);
412
+ rb_define_method(cGMP_Z, "-@", r_gmpz_neg, 0);
413
+ rb_define_method(cGMP_Z, "neg", r_gmpz_neg, 0);
414
+ rb_define_method(cGMP_Z, "neg!", r_gmpz_neg_self, 0);
415
+ rb_define_method(cGMP_Z, "abs", r_gmpz_abs, 0);
416
+ rb_define_method(cGMP_Z, "abs!", r_gmpz_abs_self, 0);
417
+ rb_define_method(cGMP_Z, "com", r_gmpz_com, 0);
418
+ rb_define_method(cGMP_Z, "com!", r_gmpz_com_self, 0);
419
+ rb_define_method(cGMP_Z, "&", r_gmpz_and, 1);
420
+ rb_define_method(cGMP_Z, "|", r_gmpz_or, 1);
421
+ rb_define_method(cGMP_Z, "^", r_gmpz_xor, 1);
422
+ rb_define_method(cGMP_Z, "[]=", r_gmpz_setbit, 2);
423
+ rb_define_method(cGMP_Z, "[]", r_gmpz_getbit, 1);
424
+ rb_define_method(cGMP_Z, "scan0", r_gmpz_scan0, 1);
425
+ rb_define_method(cGMP_Z, "scan1", r_gmpz_scan1, 1);
426
+ rb_define_method(cGMP_Z, "**", r_gmpz_pow, 1);
427
+ rb_define_method(cGMP_Z, "powmod", r_gmpz_powm, 2);
428
+ rb_define_method(cGMP_Z, "even?", r_gmpz_is_even, 0);
429
+ rb_define_method(cGMP_Z, "odd?", r_gmpz_is_odd, 0);
430
+ rb_define_method(cGMP_Z, "sgn", r_gmpz_sgn, 0);
431
+ rb_define_method(cGMP_Z, "<=>", r_gmpz_cmp, 1);
432
+ rb_define_method(cGMP_Z, ">", r_gmpz_cmp_gt, 1);
433
+ rb_define_method(cGMP_Z, ">=", r_gmpz_cmp_ge, 1);
434
+ rb_define_method(cGMP_Z, "<", r_gmpz_cmp_lt, 1);
435
+ rb_define_method(cGMP_Z, "<=", r_gmpz_cmp_le, 1);
436
+ rb_define_method(cGMP_Z, "==", r_gmpz_eq, 1);
437
+ rb_define_method(cGMP_Z, ">>", r_gmpz_fshr, 1);
438
+ rb_define_method(cGMP_Z, "<<", r_gmpz_shl, 1);
439
+ rb_define_method(cGMP_Z, "tshr", r_gmpz_tshr, 1);
440
+ rb_define_method(cGMP_Z, "lastbits_sgn", r_gmpz_tshrm, 1);
441
+ rb_define_method(cGMP_Z, "lastbits_pos", r_gmpz_fshrm, 1);
442
+ rb_define_method(cGMP_Z, "square?", r_gmpz_is_square, 0);
443
+ rb_define_method(cGMP_Z, "power?", r_gmpz_is_power, 0);
444
+ rb_define_method(cGMP_Z, "swap", r_gmpz_swap, 1);
445
+ rb_define_method(cGMP_Z, "sqrt", r_gmpz_sqrt, 0);
446
+ rb_define_method(cGMP_Z, "sqrt!", r_gmpz_sqrt_self, 0);
447
+ rb_define_method(cGMP_Z, "sqrtrem", r_gmpz_sqrtrem, 0);
448
+ rb_define_method(cGMP_Z, "jacobi", r_gmpz_jacobi, 0);
449
+ rb_define_method(cGMP_Z, "legendre", r_gmpz_legendre, 0);
450
+ rb_define_method(cGMP_Z, "probab_prime?", r_gmpz_is_probab_prime, -1);
451
+ rb_define_method(cGMP_Z, "nextprime", r_gmpz_nextprime, 0);
452
+ rb_define_method(cGMP_Z, "nextprime!", r_gmpz_nextprime_self, 0);
453
+ rb_define_method(cGMP_Z, "popcount", r_gmpz_popcount, 0);
454
+ rb_define_method(cGMP_Z, "to_d", r_gmpz_to_d, 0);
455
+ rb_define_method(cGMP_Z, "root", r_gmpz_root, 1);
456
+ rb_define_method(cGMP_Z, "remove", r_gmpz_remove, 1);
457
+ rb_define_method(cGMP_Z, "to_i", r_gmpz_to_i, 0);
458
+ rb_define_method(cGMP_Z, "cmpabs", r_gmpz_cmpabs, 1);
459
+ /*
460
+ rb_define_method(cGMP_Z, "gcd", r_gmpz_gcd, 1);
461
+ rb_define_method(cGMP_Z, "lcm", r_gmpz_lcm, 1);
462
+ */
463
+ cGMP_Q = rb_define_class_under (mGMP, "Q", rb_cNumeric);
464
+ rb_define_singleton_method(cGMP_Q, "new", r_gmpqsg_new, -1);
465
+ rb_define_method(cGMP_Q, "initialize", r_gmpq_initialize, -1);
466
+ rb_define_method(cGMP_Q, "to_s", r_gmpq_to_s, 0);
467
+ rb_define_method(cGMP_Q, "coerce", r_gmpq_coerce, 1);
468
+ rb_define_method(cGMP_Q, "num", r_gmpq_num, 0);
469
+ rb_define_method(cGMP_Q, "den", r_gmpq_den, 0);
470
+ rb_define_method(cGMP_Q, "+", r_gmpq_add, 1);
471
+ rb_define_method(cGMP_Q, "-", r_gmpq_sub, 1);
472
+ rb_define_method(cGMP_Q, "*", r_gmpq_mul, 1);
473
+ rb_define_method(cGMP_Q, "/", r_gmpq_div, 1);
474
+ rb_define_method(cGMP_Q, "inv", r_gmpq_inv, 0);
475
+ rb_define_method(cGMP_Q, "inv!", r_gmpq_inv_self, 0);
476
+ rb_define_method(cGMP_Q, "-@", r_gmpq_neg, 0);
477
+ rb_define_method(cGMP_Q, "neg!", r_gmpq_neg_self, 0);
478
+ rb_define_method(cGMP_Q, "abs", r_gmpq_abs, 0);
479
+ rb_define_method(cGMP_Q, "abs!", r_gmpq_abs_self, 0);
480
+ rb_define_method(cGMP_Q, "sgn", r_gmpq_sgn, 0);
481
+ rb_define_method(cGMP_Q, "<=>", r_gmpq_cmp, 1);
482
+ rb_define_method(cGMP_Q, ">", r_gmpq_cmp_gt, 1);
483
+ rb_define_method(cGMP_Q, ">=", r_gmpq_cmp_ge, 1);
484
+ rb_define_method(cGMP_Q, "<", r_gmpq_cmp_lt, 1);
485
+ rb_define_method(cGMP_Q, "<=", r_gmpq_cmp_le, 1);
486
+ rb_define_method(cGMP_Q, "==", r_gmpq_eq, 1);
487
+ rb_define_method(cGMP_Q, "swap", r_gmpq_swap, 1);
488
+ rb_define_method(cGMP_Q, "floor", r_gmpq_floor, 0);
489
+ rb_define_method(cGMP_Q, "ceil", r_gmpq_ceil, 0);
490
+ rb_define_method(cGMP_Q, "trunc", r_gmpq_trunc, 0);
491
+ rb_define_method(cGMP_Q, "to_d", r_gmpq_to_d, 0);
492
+ rb_define_method(cGMP_Q, "cmpabs", r_gmpq_cmpabs, 1);
493
+
494
+ cGMP_F = rb_define_class_under (mGMP, "F", rb_cNumeric);
495
+ rb_define_singleton_method(cGMP_F, "new", r_gmpfsg_new, -1);
496
+ rb_define_singleton_method(cGMP_F, "default_prec", r_gmpfsg_get_default_prec, 0);
497
+ rb_define_singleton_method(cGMP_F, "default_prec=", r_gmpfsg_set_default_prec, 1);
498
+ rb_define_method(cGMP_F, "initialize", r_gmpf_initialize, -1);
499
+ rb_define_method(cGMP_F, "to_s", r_gmpf_to_s, 0);
500
+ rb_define_method(cGMP_F, "coerce", r_gmpf_coerce, 1); // new method - testing
501
+ rb_define_method(cGMP_F, "+", r_gmpf_add, 1);
502
+ rb_define_method(cGMP_F, "-", r_gmpf_sub, 1);
503
+ rb_define_method(cGMP_F, "*", r_gmpf_mul, 1);
504
+ rb_define_method(cGMP_F, "/", r_gmpf_div, 1);
505
+ rb_define_method(cGMP_F, "-@", r_gmpf_neg, 0);
506
+ rb_define_method(cGMP_F, "neg!", r_gmpf_neg_self, 0);
507
+ rb_define_method(cGMP_F, "abs", r_gmpf_abs, 0);
508
+ rb_define_method(cGMP_F, "abs!", r_gmpf_abs_self, 0);
509
+ rb_define_method(cGMP_F, "sgn", r_gmpf_sgn, 0);
510
+ rb_define_method(cGMP_F, "<=>", r_gmpf_cmp, 1);
511
+ rb_define_method(cGMP_F, ">", r_gmpf_cmp_gt, 1);
512
+ rb_define_method(cGMP_F, ">=", r_gmpf_cmp_ge, 1);
513
+ rb_define_method(cGMP_F, "<", r_gmpf_cmp_lt, 1);
514
+ rb_define_method(cGMP_F, "<=", r_gmpf_cmp_le, 1);
515
+ rb_define_method(cGMP_F, "==", r_gmpf_eq, 1);
516
+ rb_define_method(cGMP_F, "floor", r_gmpf_floor, 0);
517
+ rb_define_method(cGMP_F, "floor!", r_gmpf_floor_self, 0);
518
+ rb_define_method(cGMP_F, "ceil", r_gmpf_ceil, 0);
519
+ rb_define_method(cGMP_F, "ceil!", r_gmpf_ceil_self, 0);
520
+ rb_define_method(cGMP_F, "trunc", r_gmpf_trunc, 0);
521
+ rb_define_method(cGMP_F, "trunc!", r_gmpf_trunc_self, 0);
522
+ rb_define_method(cGMP_F, "to_d", r_gmpf_to_d, 0);
523
+ rb_define_method(cGMP_F, "prec", r_gmpf_get_prec, 0);
524
+
525
+ /* rb_define_method(cGMP_F, "cmpabs", r_gmpf_cmpabs, 1);*/
526
+
527
+ #ifdef MPFR
528
+ rb_define_method(cGMP_F, "exp", r_gmpfr_exp, 0);
529
+ rb_define_method(cGMP_F, "log", r_gmpfr_log, 0);
530
+ rb_define_method(cGMP_F, "sqrt", r_gmpfr_sqrt, 0);
531
+ rb_define_method(cGMP_F, "cos", r_gmpfr_cos, 0);
532
+ rb_define_method(cGMP_F, "sin", r_gmpfr_sin, 0);
533
+ rb_define_method(cGMP_F, "tan", r_gmpfr_tan, 0);
534
+ rb_define_method(cGMP_F, "acos", r_gmpfr_acos, 0);
535
+ rb_define_method(cGMP_F, "asin", r_gmpfr_asin, 0);
536
+ rb_define_method(cGMP_F, "atan", r_gmpfr_atan, 0);
537
+ rb_define_method(cGMP_F, "cosh", r_gmpfr_cosh, 0);
538
+ rb_define_method(cGMP_F, "sinh", r_gmpfr_sinh, 0);
539
+ rb_define_method(cGMP_F, "tanh", r_gmpfr_tanh, 0);
540
+ rb_define_method(cGMP_F, "acosh", r_gmpfr_acosh, 0);
541
+ rb_define_method(cGMP_F, "asinh", r_gmpfr_asinh, 0);
542
+ rb_define_method(cGMP_F, "atanh", r_gmpfr_atanh, 0);
543
+ rb_define_method(cGMP_F, "log1p", r_gmpfr_log1p, 0);
544
+ rb_define_method(cGMP_F, "expm1", r_gmpfr_expm1, 0);
545
+ rb_define_method(cGMP_F, "log2", r_gmpfr_log2, 0);
546
+ rb_define_method(cGMP_F, "log10", r_gmpfr_log10, 0);
547
+
548
+ rb_define_method(cGMP_F, "nan?", r_gmpfr_nan_p, 0);
549
+ rb_define_method(cGMP_F, "infinite?", r_gmpfr_inf_p, 0);
550
+ rb_define_method(cGMP_F, "finite?", r_gmpfr_fin_p, 0);
551
+ rb_define_method(cGMP_F, "number?", r_gmpfr_number_p, 0);
552
+
553
+ rb_define_method(cGMP_F, "**", r_gmpfr_pow, 1);
554
+ #endif /* MPFR */
555
+ // more
556
+
557
+ REGISTER_TAKEOVER(and, "&", "old_and")
558
+ REGISTER_TAKEOVER(or, "|", "old_or")
559
+ REGISTER_TAKEOVER(xor, "^", "old_xor")
560
+ /* takeover cmpabs ? */
561
+ }