srawlins-gmp 0.1.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 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
+ }