gnu_mpc 0.8.0

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.
@@ -0,0 +1,13 @@
1
+ Copyright 2012 Sam Rawlins
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'gmp'
4
+
5
+ group :test do
6
+ gem 'rspec'
7
+ end
8
+
9
+ group :development do
10
+ gem 'yard'
11
+ gem 'redcarpet'
12
+ if RUBY_PLATFORM =~ /darwin/i
13
+ gem 'rb-fsevent', :require => false
14
+ end
15
+ gem 'guard-rspec'
16
+ gem 'guard-shell'
17
+ end
@@ -0,0 +1,18 @@
1
+ require 'fileutils'
2
+
3
+ guard 'rspec' do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
8
+
9
+ guard 'shell' do
10
+ watch(/ext\/(.*)\.[c|h]$/) do |m|
11
+ system("cd ext && make; cd ..")
12
+ FileUtils.touch Dir.glob(File.join('spec', 'spec_helper.rb')).first # force the rspec guard to fire
13
+ end
14
+
15
+ watch("manual.md") do |m|
16
+ system("make")
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ .PHONY : manual
2
+ manual: manual.pdf manual.html
3
+
4
+ manual.latex: manual.md
5
+ gpp -T manual.md |pandoc --template manual_template.latex -o manual.latex
6
+
7
+ manual.pdf: manual.md
8
+ gpp -T manual.md |pandoc --template manual_template.latex -o manual.pdf
9
+
10
+ manual.html: manual.md
11
+ gpp -T -DHTML manual.md |pandoc --mathjax -o manual.html
12
+
@@ -0,0 +1,47 @@
1
+ GNU MPC
2
+ =======
3
+
4
+ This gem provides Ruby bindings to the GNU MPC library.
5
+
6
+ Methods
7
+ =======
8
+
9
+ Trigonometric Methods
10
+ ---------------------
11
+
12
+ The GNU MPC gem provides bindings to the following functions from MPC:
13
+
14
+ ```ruby
15
+ MPC#sin # sine
16
+ MPC#cos # cosine
17
+ MPC#tan # tangent
18
+ MPC#sinh # hyperbolic sine
19
+ MPC#cosh # hyperbolic cosine
20
+ MPC#tanh # hyperbolic tangent
21
+ MPC#asin # inverse sine
22
+ MPC#acos # inverse cosine
23
+ MPC#atan # inverse tangent
24
+ ```
25
+
26
+ Each of these methods accepts optional arguments to specify the rounding mode, and precision, in the following fashions:
27
+
28
+ ```
29
+ z = MPC.new(0, 1)
30
+ z.sin() # default rounding mode; precision of the receiver is applied to the return value
31
+ z.sin(MPC::MPC_RNDZZ) # MPC_RNDZZ rounding mode; precision of the receiver is applied to the return value
32
+ z.sin(MPC::MPC_RNDNN, 64) # MPC_RNDNN rounding mode; precision of both real and imaginary parts of return value is 64
33
+ z.sin(MPC::MPC_RNDNN, 64, 128) # MPC_RNDNN rounding mode; precision
34
+ # of real part of return value is 64,
35
+ # imaginary part is 128
36
+ z.sin(:rounding => MPC::MPC_RNDZZ) # MPC_RNDZZ rounding mode; precision
37
+ # of the receiver is applied to the
38
+ # return value
39
+ z.sin(:prec => 64) # default rounding mode; precision of
40
+ # both real and imaginary parts of
41
+ # return value is 64
42
+ z.sin(:pre_real => 64, :prec_imag => 128) # default rounding mode; precision of
43
+ # real part of return value is 64,
44
+ # imaginary part is 128
45
+ ```
46
+
47
+ Either the ordered list of arguments, or the options Hash may be passed; they cannot be mixed.
@@ -0,0 +1,54 @@
1
+ require "rspec/core/rake_task"
2
+
3
+ # Dependencies base directory. I have to figure out how to... not hard code this?
4
+ DEPENDENCIES_DIR = '/usr/local'
5
+
6
+ task :clean do
7
+ sh "cd ext && make clean"
8
+ end
9
+
10
+ task :extconf => [:clean] do
11
+ sh "cd ext && ruby extconf.rb #{gmp_opt} #{mpfr_opt}"
12
+ end
13
+
14
+ task :make => [:extconf] do
15
+ sh "cd ext && make"
16
+ end
17
+
18
+ task :default => [:spec]
19
+
20
+ desc "Run all specs"
21
+ RSpec::Core::RakeTask.new(:spec) do |t|
22
+ end
23
+
24
+ namespace :dependencies do
25
+ task :list do
26
+ suffix = (DEPENDENCIES_DIR.size+1)..-1
27
+ puts "GMP packages installed into #{DEPENDENCIES_DIR}:"
28
+ Dir.glob(File.join(DEPENDENCIES_DIR, 'gmp') + '*').each do |dir|
29
+ puts dir[suffix]
30
+ end
31
+ puts ""
32
+
33
+ puts "MPFR packages installed #{DEPENDENCIES_DIR}:"
34
+ Dir.glob(File.join(DEPENDENCIES_DIR, 'mpfr') + '*').each do |dir|
35
+ puts dir[suffix]
36
+ end
37
+ end
38
+ end
39
+
40
+ def gmp_opt
41
+ version = ENV['GMP'] || '5.0.5'
42
+ '--with-gmp-dir='+File.join(DEPENDENCIES_DIR, "gmp-#{version}")
43
+ end
44
+
45
+ def mpfr_opt
46
+ version = ENV['MPFR'] || '3.1.1'
47
+ if version == 'no-mpfr'
48
+ return '--no-mpfr'
49
+ else
50
+ return '--with-mpfr-dir='+File.join(DEPENDENCIES_DIR, "mpfr-#{version}")
51
+ end
52
+ end
53
+
54
+
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mkmf'
4
+
5
+ dir_config('mpc')
6
+
7
+ ok = true
8
+
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
+ unless (have_header('mpfr.h') and
20
+ have_header('mpf2mpfr.h') and
21
+ have_library('mpfr', 'mpfr_init'))
22
+ ok = false
23
+ end
24
+ $CFLAGS += ' -DMPFR'
25
+
26
+ unless have_header('mpc.h')
27
+ $stderr.puts "can't find mpc.h, try --with-mpc-include=<path>"
28
+ ok = false
29
+ end
30
+
31
+ unless have_library('mpc', 'mpc_init2')
32
+ $stderr.puts "can't find -lmpc, try --with-mpc-lib=<path>"
33
+ ok = false
34
+ end
35
+
36
+ unless have_macro('SIZEOF_INTPTR_T')
37
+ check_sizeof('intptr_t')
38
+ end
39
+
40
+ $CFLAGS += ' -Wall -W -O6 -g'
41
+
42
+ if not ok
43
+ raise "Unable to build, correct above errors and rerun"
44
+ end
45
+
46
+ create_makefile('mpc')
@@ -0,0 +1,1010 @@
1
+ /*
2
+ * mpc.c
3
+ *
4
+ * This file contains everything you would expect from a C extension.
5
+ */
6
+
7
+ #include <ruby_mpc.h>
8
+
9
+ /*
10
+ * Document-class: MPC
11
+ *
12
+ * GMP Multiple Precision Complex numbers
13
+ *
14
+ * Instances of this class can store variables of the type mpc_t. This class
15
+ * also contains many methods that act as the functions for mpc_t variables,
16
+ * as well as a few methods that attempt to make this library more Ruby-ish.
17
+ */
18
+
19
+ /*
20
+ * Macros
21
+ */
22
+
23
+ #define MPC_SINGLE_FUNCTION(name) \
24
+ VALUE r_mpc_##name(int argc, VALUE *argv, VALUE self_val) \
25
+ { \
26
+ MP_COMPLEX *self, *res; \
27
+ VALUE rnd_mode_val; \
28
+ VALUE res_real_prec_val, res_imag_prec_val; \
29
+ VALUE res_val; \
30
+ \
31
+ mpfr_prec_t real_prec, imag_prec; \
32
+ mpfr_prec_t res_real_prec, res_imag_prec; \
33
+ mpc_rnd_t rnd_mode; \
34
+ \
35
+ mpc_get_struct(self_val,self); \
36
+ real_prec = mpfr_get_prec(mpc_realref(self)); \
37
+ imag_prec = mpfr_get_prec(mpc_imagref(self)); \
38
+ \
39
+ if (argc > 0 && TYPE(argv[0]) == T_HASH) { \
40
+ rb_mpc_get_hash_arguments (&rnd_mode, &real_prec, &imag_prec, argv[0]); \
41
+ res_real_prec = real_prec; \
42
+ res_imag_prec = imag_prec; \
43
+ } else { \
44
+ rb_scan_args (argc, argv, "03", &rnd_mode_val, &res_real_prec_val, &res_imag_prec_val); \
45
+ \
46
+ r_mpc_set_default_args (rnd_mode_val, res_real_prec_val, res_imag_prec_val, \
47
+ &rnd_mode, &res_real_prec, &res_imag_prec, \
48
+ real_prec, imag_prec); \
49
+ } \
50
+ \
51
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec); \
52
+ mpc_##name (res, self, rnd_mode); \
53
+ \
54
+ return res_val; \
55
+ }
56
+
57
+ /*
58
+ * Helper Methods
59
+ */
60
+ void r_mpc_set_default_args (VALUE rnd_mode_val, VALUE res_real_prec_val, VALUE res_imag_prec_val,
61
+ mpc_rnd_t *rnd_mode, mpfr_prec_t *res_real_prec, mpfr_prec_t *res_imag_prec,
62
+ mpfr_prec_t real_prec, mpfr_prec_t imag_prec) {
63
+ if (NIL_P (rnd_mode_val)) { *rnd_mode = __gmp_default_rounding_mode; }
64
+ else { *rnd_mode = r_mpc_get_rounding_mode(rnd_mode_val); }
65
+
66
+ if (NIL_P (res_real_prec_val) && NIL_P (res_imag_prec_val)) {
67
+ *res_real_prec = real_prec;
68
+ *res_imag_prec = imag_prec;
69
+ } else if (NIL_P (res_imag_prec_val)) {
70
+ *res_real_prec = FIX2INT( res_real_prec_val);
71
+ *res_imag_prec = FIX2INT( res_real_prec_val);
72
+ } else {
73
+ *res_real_prec = FIX2INT( res_real_prec_val);
74
+ *res_imag_prec = FIX2INT( res_imag_prec_val);
75
+ }
76
+ }
77
+
78
+ void rb_mpc_get_hash_arguments(mpc_rnd_t *rnd_mode, mpfr_prec_t *real_prec, mpfr_prec_t *imag_prec, VALUE hash) {
79
+ VALUE rnd_mode_val;
80
+ VALUE real_prec_val;
81
+ VALUE rounding_mode_sym, rounding_sym, round_sym, rnd_sym;
82
+ VALUE precision_sym, prec_sym;
83
+ rounding_mode_sym = ID2SYM(rb_intern("rounding_mode"));
84
+ rounding_sym = ID2SYM(rb_intern("rounding"));
85
+ round_sym = ID2SYM(rb_intern("round"));
86
+ rnd_sym = ID2SYM(rb_intern("rnd"));
87
+ precision_sym = ID2SYM(rb_intern("precision"));
88
+ prec_sym = ID2SYM(rb_intern("prec"));
89
+
90
+ rnd_mode_val = rb_hash_aref(hash, rounding_mode_sym);
91
+ if (rnd_mode_val == Qnil) { rnd_mode_val = rb_hash_aref(hash, rounding_sym); }
92
+ if (rnd_mode_val == Qnil) { rnd_mode_val = rb_hash_aref(hash, round_sym); }
93
+ if (rnd_mode_val == Qnil) { rnd_mode_val = rb_hash_aref(hash, rnd_sym); }
94
+ if (rnd_mode_val != Qnil) {
95
+ *rnd_mode = r_mpc_get_rounding_mode(rnd_mode_val);
96
+ } else {
97
+ *rnd_mode = __gmp_default_rounding_mode;
98
+ }
99
+
100
+ /* TODO: allow prec */
101
+ /* TODO: allow real_prec, imag_prec */
102
+ real_prec_val = rb_hash_aref(hash, precision_sym);
103
+ if (real_prec_val == Qnil) { real_prec_val = rb_hash_aref(hash, prec_sym); }
104
+ if (real_prec_val != Qnil) {
105
+ *real_prec = FIX2INT (real_prec_val);
106
+ *imag_prec = FIX2INT (real_prec_val);
107
+ } else {
108
+ }
109
+
110
+ /* TODO: disallow any other args. Throw a fit. */
111
+ }
112
+
113
+ /*
114
+ * Internal helper functions
115
+ ***/
116
+
117
+ int rb_base_type_range_check(VALUE base)
118
+ {
119
+ int base_val;
120
+ if (NIL_P (base)) { base_val = 10; }
121
+ else {
122
+ if (FIXNUM_P (base))
123
+ if (FIX2NUM (base) >= 2 && FIX2NUM (base) <= 36)
124
+ base_val = FIX2NUM (base);
125
+ else
126
+ rb_raise (rb_eRangeError, "base must be between 2 and 36.");
127
+ else
128
+ rb_raise (rb_eTypeError, "base must be a Fixnum.");
129
+ }
130
+ return base_val;
131
+ }
132
+
133
+ size_t rb_sig_figs_type_range_check(VALUE sig_figs)
134
+ {
135
+ size_t sig_figs_val;
136
+ if (NIL_P (sig_figs)) { sig_figs_val = (size_t)(0); }
137
+ else {
138
+ if (FIXNUM_P (sig_figs))
139
+ if (FIX2NUM (sig_figs) >= 0)
140
+ sig_figs_val = (size_t)(FIX2NUM (sig_figs));
141
+ else
142
+ rb_raise (rb_eRangeError, "significant figures must be greater than or equal to 0.");
143
+ else
144
+ rb_raise (rb_eTypeError, "significant figures must be a Fixnum.");
145
+ }
146
+ return sig_figs_val;
147
+ }
148
+
149
+
150
+ /*********************************************************************
151
+ * Initialization Functions *
152
+ *********************************************************************/
153
+
154
+ VALUE cMPC;
155
+ VALUE cMPC_Rnd;
156
+ void r_mpc_free(void *ptr) { mpc_clear (ptr); free (ptr); }
157
+
158
+ mpc_rnd_t r_get_mpc_rounding_mode(VALUE rnd)
159
+ {
160
+ VALUE mode;
161
+
162
+ if (MPCRND_P (rnd)) {
163
+ mode = rb_funcall (rnd, rb_intern ("mode"), 0);
164
+ if (FIX2INT (mode) < 0 || FIX2INT (mode) > 63) {
165
+ rb_raise (rb_eRangeError, "rounding mode must be one of the MPC rounding mode constants.");
166
+ }
167
+ } else {
168
+ rb_raise (rb_eTypeError, "rounding mode must be one of the MPC rounding mode constants.");
169
+ }
170
+
171
+ switch (FIX2INT (mode)) {
172
+ case 0:
173
+ return MPC_RNDNN;
174
+ case 1:
175
+ return MPC_RNDZN;
176
+ case 2:
177
+ return MPC_RNDUN;
178
+ case 3:
179
+ return MPC_RNDDN;
180
+ case 16:
181
+ return MPC_RNDNZ;
182
+ case 17:
183
+ return MPC_RNDZZ;
184
+ case 18:
185
+ return MPC_RNDUZ;
186
+ case 19:
187
+ return MPC_RNDDZ;
188
+ case 32:
189
+ return MPC_RNDNU;
190
+ case 33:
191
+ return MPC_RNDZU;
192
+ case 34:
193
+ return MPC_RNDUU;
194
+ case 35:
195
+ return MPC_RNDDU;
196
+ case 48:
197
+ return MPC_RNDND;
198
+ case 49:
199
+ return MPC_RNDZD;
200
+ case 50:
201
+ return MPC_RNDUD;
202
+ case 51:
203
+ return MPC_RNDDD;
204
+ default:
205
+ return MPC_RNDNN;
206
+ }
207
+ }
208
+
209
+ /*
210
+ * call-seq:
211
+ * MPC.new(value = 0)
212
+ *
213
+ * Creates a new MPC complex number, with _value_ as its value, converting where necessary.
214
+ * _value_ must be an instance of one of the following classes:
215
+ *
216
+ * * MPC
217
+ * * GMP::Z
218
+ * * GMP::F
219
+ * * Fixnum
220
+ * * String
221
+ * * Bignum
222
+ *
223
+ * @example
224
+ * MPC.new(5) #=> 5
225
+ *
226
+ * @todo support #new(c, prec)
227
+ * @todo support #new(c, prec_r, prec_i)
228
+ */
229
+ VALUE r_mpcsg_new(int argc, VALUE *argv, VALUE klass)
230
+ {
231
+ MP_COMPLEX *res_val;
232
+ VALUE res;
233
+ (void)klass;
234
+
235
+ if (argc > 3)
236
+ rb_raise (rb_eArgError, "wrong # of arguments (%d for 0, 1, 2, or 3)", argc);
237
+
238
+ mpc_make_struct (res, res_val);
239
+ rb_obj_call_init (res, argc, argv);
240
+
241
+ return res;
242
+ }
243
+
244
+ VALUE r_mpc_initialize(int argc, VALUE *argv, VALUE self)
245
+ {
246
+ MP_COMPLEX *self_val;
247
+ MP_FLOAT *arg_val_f;
248
+ MP_COMPLEX *arg_val_c;
249
+ unsigned long prec = 0;
250
+ mpfr_prec_t prec_re = 0;
251
+ mpfr_prec_t prec_im = 0;
252
+ mpc_rnd_t rnd_mode_val = r_mpc_default_rounding_mode;
253
+ VALUE arg;
254
+
255
+ mpc_get_struct (self, self_val);
256
+
257
+ if (argc==0) {
258
+ mpc_init2 (self_val, mpfr_get_default_prec());
259
+ mpc_set_si (self_val, 0, rnd_mode_val);
260
+ return Qnil;
261
+ }
262
+
263
+ arg = argv[0];
264
+
265
+ // argc = 2 ==> argv[0] is value, argv[1] is prec
266
+ // OR argv[0] is value, argv[1] is rnd
267
+ if (argc >= 2) {
268
+ if (FIXNUM_P (argv[1])) {
269
+ if (FIX2INT (argv[1]) >= 0)
270
+ prec = FIX2INT (argv[1]);
271
+ else {
272
+ mpc_init2 (self_val, mpfr_get_default_prec());
273
+ rb_raise (rb_eRangeError, "prec must be non-negative");
274
+ }
275
+ } else if (MPCRND_P (argv[1])) {
276
+ rnd_mode_val = r_get_mpc_rounding_mode(argv[1]);
277
+ } else {
278
+ mpc_init2 (self_val, mpfr_get_default_prec());
279
+ rb_raise (rb_eTypeError, "don't know how to interpret argument 1, a %s", rb_class2name (rb_class_of (argv[1])));
280
+ }
281
+ // if no precision provided, but an mpfr_t is passed as value, use its prec
282
+ } else if (GMPF_P (arg)) {
283
+ mpf_get_struct (arg, arg_val_f);
284
+ prec = mpf_get_prec (arg_val_f);
285
+ // if no precision provided, but an mpc_t is passed as value, use its prec
286
+ } else if (MPC_P (arg)) {
287
+ mpc_get_struct (arg, arg_val_c);
288
+ mpc_get_prec2 (&prec_re, &prec_im, arg_val_c);
289
+ }
290
+
291
+ // argc = 3 ==> argv[0] is value, argv[1] is prec_r, argv[2] is prec_i
292
+ // OR argv[0] is value, argv[1] is prec, argv[2] is rnd
293
+ if (argc == 3) {
294
+ if (MPCRND_P (argv[1])) {
295
+ mpc_init2 (self_val, mpfr_get_default_prec());
296
+ rb_raise (rb_eArgError, "the rounding mode should be the last argument");
297
+ } else if (FIXNUM_P (argv[2])) {
298
+ if (FIX2INT (argv[2]) >= 0) {
299
+ // argv[1] was actually prec_r and //argv[2] is prec_i
300
+ prec_re = (mpfr_prec_t) prec;
301
+ prec_im = FIX2INT (argv[2]);
302
+ prec = 0;
303
+ } else {
304
+ mpc_init2 (self_val, mpfr_get_default_prec());
305
+ rb_raise (rb_eRangeError, "prec_im must be non-negative");
306
+ }
307
+ } else if (MPCRND_P (argv[2])) {
308
+ rnd_mode_val = r_get_mpc_rounding_mode(argv[2]);
309
+ } else {
310
+ mpc_init2 (self_val, mpfr_get_default_prec());
311
+ rb_raise (rb_eTypeError, "don't know how to interpret argument 2, a %s", rb_class2name (rb_class_of (argv[2])));
312
+ }
313
+ }
314
+
315
+ // argc = 4 ==> argv[0] is value, argv[1] is prec_r, argv[2] is prec_i, argv[3] is rnd
316
+ // TODO
317
+
318
+ if (prec == 0)
319
+ mpc_init2 (self_val, mpfr_get_default_prec());
320
+ else
321
+ mpc_init2 (self_val, prec);
322
+
323
+ if (STRING_P (argv[0])) {
324
+ // unfortunately, we cannot accept an explicit base, as we do in r_gmpf_initialize.
325
+ // #new(c, prec, base) would be indistinguishable from #new(c, prec_r, prec_i).
326
+ // TODO allow this behavior via something like #new_str or String#to_mpc
327
+ mpc_set_str (self_val, StringValuePtr(arg), 0, rnd_mode_val);
328
+ return Qnil;
329
+ }
330
+
331
+ //if (MPC_P(arg)) {
332
+ // mpc_get_struct (arg, arg_val_c);
333
+ // mpc_set (self_val, arg_val_c, rnd_mode_val);
334
+ //} else {
335
+ mpc_set_value (self_val, arg, rnd_mode_val);
336
+ //}
337
+
338
+ return Qnil;
339
+ }
340
+
341
+ void mpc_set_value(MP_COMPLEX *self_val, VALUE arg, mpc_rnd_t rnd)
342
+ {
343
+ MP_INT *arg_val_z, *arg_val_z_im;
344
+ MP_RAT *arg_val_q, *arg_val_q_im;
345
+ MP_FLOAT *arg_val_f, *arg_val_f_im;
346
+ MP_COMPLEX *arg_val_c;
347
+ VALUE arg_re, arg_im;
348
+ int result;
349
+
350
+ if (FIXNUM_P (arg)) {
351
+ mpc_set_si(self_val, FIX2NUM (arg), rnd);
352
+ } else if (FLOAT_P (arg)) {
353
+ mpc_set_d (self_val, NUM2DBL (arg), rnd);
354
+ } else if (GMPQ_P (arg)) {
355
+ mpq_get_struct (arg, arg_val_q);
356
+ mpc_set_q (self_val, arg_val_q, rnd);
357
+ } else if (GMPZ_P (arg)) {
358
+ mpz_get_struct (arg, arg_val_z);
359
+ mpc_set_z (self_val, arg_val_z, rnd);
360
+ // TODO STRING_P
361
+ // TODO BIGNUM_P
362
+ } else if (MPC_P (arg)) {
363
+ mpc_get_struct (arg, arg_val_c);
364
+ mpc_set (self_val, arg_val_c, rnd);
365
+ } else if (GMPF_P (arg)) {
366
+ mpf_get_struct (arg, arg_val_f);
367
+ mpc_set_fr (self_val, arg_val_f, rnd);
368
+ } else if (ARRAY_P (arg)) {
369
+ //if (RARRAY(arg)->len != 2)
370
+ //rb_raise(rb_eArgError, "Value Array must contain exactly two elements, the real value, and the imaginary value.");
371
+ arg_re = rb_ary_shift(arg);
372
+ arg_im = rb_ary_shift(arg);
373
+ if (FIXNUM_P (arg_re) && FIXNUM_P (arg_im)) {
374
+ mpc_set_si_si (self_val, FIX2NUM (arg_re), FIX2NUM (arg_im), rnd);
375
+ } else if (FLOAT_P (arg_re) && FLOAT_P (arg_im)) {
376
+ mpc_set_d_d (self_val, NUM2DBL (arg_re), NUM2DBL (arg_im), rnd);
377
+ } else if (GMPZ_P (arg_re) && GMPZ_P (arg_im)) {
378
+ mpz_get_struct (arg_re, arg_val_z);
379
+ mpz_get_struct (arg_im, arg_val_z_im);
380
+ mpc_set_z_z (self_val, arg_val_z, arg_val_z_im, rnd);
381
+ } else if (GMPQ_P (arg_re) && GMPQ_P (arg_im)) {
382
+ mpq_get_struct (arg_re, arg_val_q);
383
+ mpq_get_struct (arg_im, arg_val_q_im);
384
+ mpc_set_q_q (self_val, arg_val_q, arg_val_q_im, rnd);
385
+ } else if (GMPF_P (arg_re) && GMPF_P (arg_im)) {
386
+ mpf_get_struct (arg_re, arg_val_f);
387
+ mpf_get_struct (arg_im, arg_val_f_im);
388
+ mpc_set_fr_fr (self_val, arg_val_f, arg_val_f_im, rnd);
389
+ // TODO STRING_P
390
+ // TODO BIGNUM_P
391
+ } else
392
+ rb_raise(rb_eTypeError, "Real and imaginary values must be of the same type.");
393
+ } else {
394
+ rb_raise(rb_eTypeError, "Don't know how to convert %s into MPC", rb_class2name (rb_class_of(arg)));
395
+ }
396
+ }
397
+
398
+ /*
399
+ * call-seq:
400
+ * c.prec
401
+ *
402
+ * If the real and imaginary part of _c_ have the same precision, it is returned. Otherwise,
403
+ * 0 is returned.
404
+ */
405
+ VALUE r_mpc_prec(VALUE self)
406
+ {
407
+ MP_COMPLEX *self_val;
408
+ mpc_get_struct (self, self_val);
409
+ return INT2NUM (mpc_get_prec (self_val));
410
+ }
411
+
412
+
413
+ /*********************************************************************
414
+ * String and Stream Input and Output *
415
+ *********************************************************************/
416
+
417
+ /*
418
+ * call-seq:
419
+ * c.to_s
420
+ *
421
+ * Returns the decimal representation of the real part and imaginary part of _c_, as a String.
422
+ *
423
+ * @TODO type check, range check optional argument: rounding mode
424
+ */
425
+ VALUE r_mpc_to_s(int argc, VALUE *argv, VALUE self)
426
+ {
427
+ MP_COMPLEX *self_val;
428
+ char *str;
429
+ VALUE base, sig_figs, rnd_mode, res;
430
+ int base_val;
431
+ size_t sig_figs_val;
432
+ mpc_rnd_t rnd_mode_val;
433
+ //mp_exp_t exponent;
434
+
435
+ mpc_get_struct (self, self_val)
436
+
437
+ rb_scan_args (argc, argv, "03", &base, &sig_figs, &rnd_mode);
438
+ base_val = rb_base_type_range_check (base);
439
+ sig_figs_val = rb_sig_figs_type_range_check (sig_figs);
440
+ //if (NIL_P (sig_figs)) { sig_figs_val = (size_t)(0); }
441
+ //else { sig_figs_val = (size_t)(FIX2NUM(sig_figs)); }
442
+ if (NIL_P (rnd_mode)) { rnd_mode_val = r_mpc_default_rounding_mode; }
443
+ else { rnd_mode_val = r_get_mpc_rounding_mode(rnd_mode); }
444
+
445
+ str = mpc_get_str (base_val, sig_figs_val, self_val, rnd_mode_val);
446
+ res = rb_str_new2 (str);
447
+
448
+ mpc_free_str (str);
449
+ return res;
450
+ }
451
+
452
+
453
+ /*********************************************************************
454
+ * Comparison Functions *
455
+ *********************************************************************/
456
+
457
+ int mpc_cmp_value(MP_COMPLEX *self_val, VALUE arg)
458
+ {
459
+ MP_COMPLEX *arg_val;
460
+ int result;
461
+
462
+ if (MPC_P (arg)) {
463
+ mpc_get_struct (arg,arg_val);
464
+ return mpc_cmp (self_val, arg_val);
465
+ } else {
466
+ mpc_temp_init (arg_val, mpc_get_prec (self_val));
467
+ mpc_set_value (arg_val, arg, r_mpc_default_rounding_mode);
468
+ result = mpc_cmp (self_val, arg_val);
469
+ mpc_temp_free (arg_val);
470
+ return result;
471
+ }
472
+ }
473
+
474
+ VALUE r_mpc_eq(VALUE self, VALUE arg)
475
+ {
476
+ MP_COMPLEX *self_val;
477
+ mpc_get_struct (self,self_val);
478
+ return (mpc_cmp_value (self_val, arg) == 0) ? Qtrue : Qfalse;
479
+ }
480
+
481
+ VALUE r_mpc_cmp(VALUE self, VALUE arg)
482
+ {
483
+ MP_COMPLEX *self_val;
484
+ int res;
485
+ mpc_get_struct (self, self_val);
486
+ res = mpc_cmp_value (self_val, arg);
487
+ return rb_assoc_new(INT2FIX(MPC_INEX_RE(res)), INT2FIX (MPC_INEX_IM(res)));
488
+ }
489
+
490
+
491
+ /*********************************************************************
492
+ * Projection and Decomposition Functions *
493
+ *********************************************************************/
494
+
495
+ /*
496
+ * DEFUN_COMPLEX2FLOAT defines a function. This function takes an
497
+ * MPC as self, calls mpc_fname on the contained mpc_t, whose
498
+ * arguments are exactly (0) the return argument (an mpfr_t), (1) self,
499
+ * and (2) the rounding mode.
500
+ *
501
+ * TODO FINISH!!!
502
+ */
503
+ #define DEFUN_COMPLEX2FLOAT(fname,mpz_fname) \
504
+ static VALUE r_mpc_##fname(int argc, VALUE *argv, VALUE self) \
505
+ { \
506
+ MP_COMPLEX *self_val; \
507
+ MP_FLOAT *res_val; \
508
+ VALUE rnd_mode, res_prec, res; \
509
+ mpfr_prec_t prec, res_prec_value; \
510
+ mpc_rnd_t rnd_mode_val; \
511
+
512
+ /*
513
+ * call-seq:
514
+ * c.real
515
+ * c.real(rounding_mode)
516
+ *
517
+ * Returns the real part of _c_ as a GMP_F float (an MPFR float, really).
518
+ */
519
+ VALUE r_mpc_real(int argc, VALUE *argv, VALUE self)
520
+ {
521
+ MP_COMPLEX *self_val;
522
+ MP_FLOAT *real_val;
523
+ VALUE rnd_mode, real;
524
+ mpfr_prec_t pr=0, pi=0;
525
+ mpc_rnd_t rnd_mode_val;
526
+
527
+ mpc_get_struct (self, self_val);
528
+
529
+ rb_scan_args (argc, argv, "01", &rnd_mode);
530
+ if (NIL_P (rnd_mode)) { rnd_mode_val = r_mpc_default_rounding_mode; }
531
+ else { rnd_mode_val = r_get_mpc_rounding_mode (rnd_mode); }
532
+
533
+ mpf_make_struct (real, real_val);
534
+ mpc_get_prec2 (&pr, &pi, self_val);
535
+ mpfr_init2 (real_val, pr);
536
+ mpc_real (real_val, self_val, rnd_mode_val);
537
+ return real;
538
+ }
539
+
540
+ /*
541
+ * call-seq:
542
+ * c.imag
543
+ * c.imag(rounding_mode)
544
+ *
545
+ * Returns the imaginary part of _c_ as a GMP_F float (an MPFR float, really).
546
+ */
547
+ VALUE r_mpc_imag(int argc, VALUE *argv, VALUE self)
548
+ {
549
+ MP_COMPLEX *self_val;
550
+ MP_FLOAT *imag_val;
551
+ VALUE rnd_mode, imag;
552
+ mpfr_prec_t pr=0, pi=0;
553
+ mpc_rnd_t rnd_mode_val;
554
+
555
+ mpc_get_struct (self, self_val);
556
+
557
+ rb_scan_args (argc, argv, "01", &rnd_mode);
558
+ if (NIL_P (rnd_mode)) { rnd_mode_val = r_mpc_default_rounding_mode; }
559
+ else { rnd_mode_val = r_get_mpc_rounding_mode(rnd_mode); }
560
+
561
+ mpf_make_struct (imag, imag_val);
562
+ mpc_get_prec2 (&pr, &pi, self_val);
563
+ mpfr_init2 (imag_val, pr);
564
+ mpc_imag (imag_val, self_val, rnd_mode_val);
565
+ return imag;
566
+ }
567
+
568
+ MPC_SINGLE_FUNCTION(proj)
569
+
570
+ /*********************************************************************
571
+ * Basic Arithmetic Functions *
572
+ *********************************************************************/
573
+
574
+ /*
575
+ * All of the arithmetic functions will need a lot of massaging ability. For
576
+ * example, there are only 3 variants of mpc_add, one that takes an mpc_t, one
577
+ * that takes an unsigned long int, and one that takes an mpfr_t. Here is a
578
+ * table of the massagings:
579
+ *
580
+ * z + x
581
+ * =====
582
+ *
583
+ * x:Fixnum =>
584
+ * x > 0 => mpc_add_ui ( z, (unsigned long int)x )
585
+ * x < 0 => mpc_sub_ui ( z, (unsigned long int)x )
586
+ * x == 0 => z
587
+ * x:Bignum => mpc_add_fr ( z, (mpfr_t)x )
588
+ * x:GMP::Z => mpc_add_fr ( z, (mpfr_t)x )
589
+ * x:GMP::Q => mpc_add_fr ( z, (mpfr_t)x )
590
+ * x:Float => mpc_add_fr ( z, (mpfr_t)x )
591
+ * x:GMP::F => mpc_add_fr ( z, x )
592
+ * x:MPC => mpc_add ( z, x )
593
+ */
594
+
595
+ VALUE r_mpc_add_do_the_work(VALUE self_val, VALUE arg_val, mpc_rnd_t rnd_mode, mpfr_prec_t res_real_prec, mpfr_prec_t res_imag_prec);
596
+ VALUE r_mpc_add(int argc, VALUE *argv, VALUE self_val)
597
+ {
598
+ MP_COMPLEX *self;
599
+ VALUE rnd_mode_val;
600
+ VALUE res_real_prec_val, res_imag_prec_val;
601
+ VALUE arg_val;
602
+
603
+ mpfr_prec_t real_prec, imag_prec;
604
+ mpfr_prec_t res_real_prec, res_imag_prec;
605
+ mpc_rnd_t rnd_mode;
606
+
607
+ mpc_get_struct(self_val,self);
608
+ real_prec = mpfr_get_prec(mpc_realref(self));
609
+ imag_prec = mpfr_get_prec(mpc_imagref(self));
610
+
611
+ //if (argc > 0 && TYPE(argv[0]) == T_HASH) {
612
+ // rb_mpc_get_hash_arguments (&rnd_mode, &real_prec, &imag_prec, argv[0]);
613
+ //res_real_prec = real_prec;
614
+ //res_imag_prec = imag_prec;
615
+ //} else {
616
+ rb_scan_args (argc, argv, "13", &arg_val, &rnd_mode_val, &res_real_prec_val, &res_imag_prec_val);
617
+
618
+ r_mpc_set_default_args (rnd_mode_val, res_real_prec_val, res_imag_prec_val,
619
+ &rnd_mode, &res_real_prec, &res_imag_prec,
620
+ real_prec, imag_prec);
621
+ //}
622
+
623
+ //return res_val;
624
+ return r_mpc_add_do_the_work(self_val, arg_val, rnd_mode, res_real_prec, res_imag_prec);
625
+ }
626
+
627
+ VALUE r_mpc_add2(VALUE self_val, VALUE arg_val)
628
+ {
629
+ MP_COMPLEX *self;
630
+
631
+ mpfr_prec_t res_real_prec, res_imag_prec;
632
+
633
+ mpc_get_struct(self_val, self);
634
+ res_real_prec = mpfr_get_prec(mpc_realref(self));
635
+ res_imag_prec = mpfr_get_prec(mpc_imagref(self));
636
+
637
+ return r_mpc_add_do_the_work(self_val, arg_val, MPC_RNDNN, res_real_prec, res_imag_prec);
638
+ }
639
+
640
+ VALUE r_mpc_add_do_the_work(VALUE self_val, VALUE arg_val, mpc_rnd_t rnd_mode, mpfr_prec_t res_real_prec, mpfr_prec_t res_imag_prec) {
641
+ MP_COMPLEX *self, *res, *arg_c;
642
+ MP_INT *arg_z;
643
+ MP_FLOAT *arg_f;
644
+ VALUE res_val;
645
+
646
+ mpc_get_struct(self_val,self);
647
+
648
+ if (FIXNUM_P (arg_val)) {
649
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
650
+ if (FIX2NUM (arg_val) >= 0) {
651
+ mpc_add_ui (res, self, FIX2NUM (arg_val), rnd_mode);
652
+ } else {
653
+ mpc_sub_ui (res, self, -FIX2NUM (arg_val), rnd_mode);
654
+ }
655
+ } else if (BIGNUM_P (arg_val)) {
656
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
657
+ mpz_temp_from_bignum (arg_z, arg_val);
658
+ mpc_set_z (res, arg_z, MPC_RNDNN);
659
+ mpz_temp_free (arg_z);
660
+ mpc_add (res, self, res, rnd_mode);
661
+ } else if (GMPZ_P (arg_val)) {
662
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
663
+ mpz_get_struct (arg_val, arg_z);
664
+ mpc_set_z (res, arg_z, MPC_RNDNN);
665
+ mpc_add (res, self, res, rnd_mode);
666
+ } else if (GMPF_P (arg_val)) {
667
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
668
+ mpf_get_struct (arg_val, arg_f);
669
+ mpc_add_fr (res, self, arg_f, rnd_mode);
670
+ } else if (MPC_P (arg_val)) {
671
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
672
+ mpc_get_struct (arg_val, arg_c);
673
+ mpc_add (res, self, arg_c, rnd_mode);
674
+ } else {
675
+ typeerror(FXC);
676
+ }
677
+
678
+ return res_val;
679
+ }
680
+
681
+ VALUE r_mpc_sub_do_the_work(VALUE self_val, VALUE arg_val, mpc_rnd_t rnd_mode, mpfr_prec_t res_real_prec, mpfr_prec_t res_imag_prec);
682
+ VALUE r_mpc_sub(int argc, VALUE *argv, VALUE self_val)
683
+ {
684
+ MP_COMPLEX *self;
685
+ VALUE rnd_mode_val;
686
+ VALUE res_real_prec_val, res_imag_prec_val;
687
+ VALUE arg_val;
688
+
689
+ mpfr_prec_t real_prec, imag_prec;
690
+ mpfr_prec_t res_real_prec, res_imag_prec;
691
+ mpc_rnd_t rnd_mode;
692
+
693
+ mpc_get_struct(self_val,self);
694
+ real_prec = mpfr_get_prec(mpc_realref(self));
695
+ imag_prec = mpfr_get_prec(mpc_imagref(self));
696
+
697
+ //if (argc > 0 && TYPE(argv[0]) == T_HASH) {
698
+ // rb_mpc_get_hash_arguments (&rnd_mode, &real_prec, &imag_prec, argv[0]);
699
+ //res_real_prec = real_prec;
700
+ //res_imag_prec = imag_prec;
701
+ //} else {
702
+ rb_scan_args (argc, argv, "13", &arg_val, &rnd_mode_val, &res_real_prec_val, &res_imag_prec_val);
703
+
704
+ r_mpc_set_default_args (rnd_mode_val, res_real_prec_val, res_imag_prec_val,
705
+ &rnd_mode, &res_real_prec, &res_imag_prec,
706
+ real_prec, imag_prec);
707
+ //}
708
+
709
+ //return res_val;
710
+ return r_mpc_sub_do_the_work(self_val, arg_val, rnd_mode, res_real_prec, res_imag_prec);
711
+ }
712
+
713
+ VALUE r_mpc_sub2(VALUE self_val, VALUE arg_val)
714
+ {
715
+ MP_COMPLEX *self;
716
+
717
+ mpfr_prec_t res_real_prec, res_imag_prec;
718
+
719
+ mpc_get_struct(self_val, self);
720
+ res_real_prec = mpfr_get_prec(mpc_realref(self));
721
+ res_imag_prec = mpfr_get_prec(mpc_imagref(self));
722
+
723
+ return r_mpc_sub_do_the_work(self_val, arg_val, MPC_RNDNN, res_real_prec, res_imag_prec);
724
+ }
725
+
726
+ VALUE r_mpc_sub_do_the_work(VALUE self_val, VALUE arg_val, mpc_rnd_t rnd_mode, mpfr_prec_t res_real_prec, mpfr_prec_t res_imag_prec) {
727
+ MP_COMPLEX *self, *res, *arg_c;
728
+ MP_INT *arg_z;
729
+ MP_FLOAT *arg_f;
730
+ VALUE res_val;
731
+
732
+ mpc_get_struct(self_val,self);
733
+
734
+ if (FIXNUM_P (arg_val)) {
735
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
736
+ if (FIX2NUM (arg_val) >= 0) {
737
+ mpc_sub_ui (res, self, FIX2NUM (arg_val), rnd_mode);
738
+ } else {
739
+ mpc_add_ui (res, self, -FIX2NUM (arg_val), rnd_mode);
740
+ }
741
+ } else if (BIGNUM_P (arg_val)) {
742
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
743
+ mpz_temp_from_bignum (arg_z, arg_val);
744
+ mpc_set_z (res, arg_z, MPC_RNDNN);
745
+ mpz_temp_free (arg_z);
746
+ mpc_sub (res, self, res, rnd_mode);
747
+ } else if (GMPZ_P (arg_val)) {
748
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
749
+ mpz_get_struct (arg_val, arg_z);
750
+ mpc_set_z (res, arg_z, MPC_RNDNN);
751
+ mpc_sub (res, self, res, rnd_mode);
752
+ } else if (GMPF_P (arg_val)) {
753
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
754
+ mpf_get_struct (arg_val, arg_f);
755
+ mpc_sub_fr (res, self, arg_f, rnd_mode);
756
+ } else if (MPC_P (arg_val)) {
757
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
758
+ mpc_get_struct (arg_val, arg_c);
759
+ mpc_sub (res, self, arg_c, rnd_mode);
760
+ } else {
761
+ typeerror(FXC);
762
+ }
763
+
764
+ return res_val;
765
+ }
766
+
767
+ VALUE r_mpc_mul_do_the_work(VALUE self_val, VALUE arg_val, mpc_rnd_t rnd_mode, mpfr_prec_t res_real_prec, mpfr_prec_t res_imag_prec);
768
+ VALUE r_mpc_mul(int argc, VALUE *argv, VALUE self_val)
769
+ {
770
+ MP_COMPLEX *self;
771
+ VALUE rnd_mode_val;
772
+ VALUE res_real_prec_val, res_imag_prec_val;
773
+ VALUE arg_val;
774
+
775
+ mpfr_prec_t real_prec, imag_prec;
776
+ mpfr_prec_t res_real_prec, res_imag_prec;
777
+ mpc_rnd_t rnd_mode;
778
+
779
+ mpc_get_struct(self_val,self);
780
+ real_prec = mpfr_get_prec(mpc_realref(self));
781
+ imag_prec = mpfr_get_prec(mpc_imagref(self));
782
+
783
+ //if (argc > 0 && TYPE(argv[0]) == T_HASH) {
784
+ // rb_mpc_get_hash_arguments (&rnd_mode, &real_prec, &imag_prec, argv[0]);
785
+ //res_real_prec = real_prec;
786
+ //res_imag_prec = imag_prec;
787
+ //} else {
788
+ rb_scan_args (argc, argv, "13", &arg_val, &rnd_mode_val, &res_real_prec_val, &res_imag_prec_val);
789
+
790
+ r_mpc_set_default_args (rnd_mode_val, res_real_prec_val, res_imag_prec_val,
791
+ &rnd_mode, &res_real_prec, &res_imag_prec,
792
+ real_prec, imag_prec);
793
+ //}
794
+
795
+ //return res_val;
796
+ return r_mpc_mul_do_the_work(self_val, arg_val, rnd_mode, res_real_prec, res_imag_prec);
797
+ }
798
+
799
+ VALUE r_mpc_mul2(VALUE self_val, VALUE arg_val)
800
+ {
801
+ MP_COMPLEX *self;
802
+
803
+ mpfr_prec_t res_real_prec, res_imag_prec;
804
+
805
+ mpc_get_struct(self_val, self);
806
+ res_real_prec = mpfr_get_prec(mpc_realref(self));
807
+ res_imag_prec = mpfr_get_prec(mpc_imagref(self));
808
+
809
+ return r_mpc_mul_do_the_work(self_val, arg_val, MPC_RNDNN, res_real_prec, res_imag_prec);
810
+ }
811
+
812
+ VALUE r_mpc_mul_do_the_work(VALUE self_val, VALUE arg_val, mpc_rnd_t rnd_mode, mpfr_prec_t res_real_prec, mpfr_prec_t res_imag_prec) {
813
+ MP_COMPLEX *self, *res, *arg_c;
814
+ MP_INT *arg_z;
815
+ MP_FLOAT *arg_f;
816
+ VALUE res_val;
817
+
818
+ mpc_get_struct(self_val,self);
819
+
820
+ if (FIXNUM_P (arg_val)) {
821
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
822
+ if (FIX2NUM (arg_val) >= 0) {
823
+ mpc_mul_ui (res, self, FIX2NUM (arg_val), rnd_mode);
824
+ } else {
825
+ mpc_mul_si (res, self, FIX2NUM (arg_val), rnd_mode);
826
+ }
827
+ } else if (BIGNUM_P (arg_val)) {
828
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
829
+ mpz_temp_from_bignum (arg_z, arg_val);
830
+ mpc_set_z (res, arg_z, MPC_RNDNN);
831
+ mpz_temp_free (arg_z);
832
+ mpc_mul (res, self, res, rnd_mode);
833
+ } else if (GMPZ_P (arg_val)) {
834
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
835
+ mpz_get_struct (arg_val, arg_z);
836
+ mpc_set_z (res, arg_z, MPC_RNDNN);
837
+ mpc_mul (res, self, res, rnd_mode);
838
+ } else if (GMPF_P (arg_val)) {
839
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
840
+ mpf_get_struct (arg_val, arg_f);
841
+ mpc_mul_fr (res, self, arg_f, rnd_mode);
842
+ } else if (MPC_P (arg_val)) {
843
+ mpc_make_struct_init3 (res_val, res, res_real_prec, res_imag_prec);
844
+ mpc_get_struct (arg_val, arg_c);
845
+ mpc_mul (res, self, arg_c, rnd_mode);
846
+ } else {
847
+ typeerror(FXC);
848
+ }
849
+
850
+ return res_val;
851
+ }
852
+
853
+ MPC_SINGLE_FUNCTION(neg)
854
+
855
+ /*
856
+ * call-seq:
857
+ * -z
858
+ *
859
+ * Returns _-z_, rounded according to the default rounding mode.
860
+ */
861
+ VALUE r_mpc_neg2(VALUE self_val)
862
+ {
863
+ MP_COMPLEX *self, *res;
864
+ VALUE res_val;
865
+ mpfr_prec_t real_prec, imag_prec;
866
+
867
+ mpc_get_struct(self_val,self);
868
+ real_prec = mpfr_get_prec(mpc_realref(self));
869
+ imag_prec = mpfr_get_prec(mpc_imagref(self));
870
+
871
+ mpc_make_struct_init3 (res_val, res, real_prec, imag_prec);
872
+ mpc_neg (res, self, __gmp_default_rounding_mode);
873
+
874
+ return res_val;
875
+ }
876
+
877
+ MPC_SINGLE_FUNCTION(sqr)
878
+ MPC_SINGLE_FUNCTION(conj)
879
+
880
+ /*
881
+ * call-seq:
882
+ * c.abs
883
+ * c.abs(rounding_mode)
884
+ *
885
+ * Returns the absolute value of _c_ as a GMP_F float (an MPFR float, really).
886
+ */
887
+ VALUE r_mpc_abs(int argc, VALUE *argv, VALUE self)
888
+ {
889
+ MP_COMPLEX *self_val;
890
+ MP_FLOAT *abs_val;
891
+ VALUE rnd_mode, abs;
892
+ mpfr_prec_t pr=0, pi=0;
893
+ mpc_rnd_t rnd_mode_val;
894
+
895
+ mpc_get_struct (self, self_val);
896
+
897
+ rb_scan_args (argc, argv, "01", &rnd_mode);
898
+ if (NIL_P (rnd_mode)) { rnd_mode_val = r_mpc_default_rounding_mode; }
899
+ else { rnd_mode_val = r_get_mpc_rounding_mode (rnd_mode); }
900
+
901
+ mpf_make_struct (abs, abs_val);
902
+ mpc_get_prec2 (&pr, &pi, self_val);
903
+ mpfr_init2 (abs_val, pr);
904
+ mpc_abs (abs_val, self_val, rnd_mode_val);
905
+ return abs;
906
+ }
907
+
908
+ /*********************************************************************
909
+ * Power and Logarithm Functions *
910
+ *********************************************************************/
911
+
912
+ MPC_SINGLE_FUNCTION(sqrt)
913
+ MPC_SINGLE_FUNCTION(exp)
914
+ MPC_SINGLE_FUNCTION(log)
915
+
916
+ /*********************************************************************
917
+ * Trigonometric Functions *
918
+ *********************************************************************/
919
+
920
+ /*
921
+ * call-seq:
922
+ * z.sin
923
+ * z.sin(rounding_mode)
924
+ *
925
+ * Returns _sin(z)_, rounded according to `rounding_mode`.
926
+ * s3
927
+ */
928
+ MPC_SINGLE_FUNCTION(sin)
929
+ MPC_SINGLE_FUNCTION(cos)
930
+ MPC_SINGLE_FUNCTION(tan)
931
+ MPC_SINGLE_FUNCTION(sinh)
932
+ MPC_SINGLE_FUNCTION(cosh)
933
+ MPC_SINGLE_FUNCTION(tanh)
934
+ MPC_SINGLE_FUNCTION(asin)
935
+ MPC_SINGLE_FUNCTION(acos)
936
+ MPC_SINGLE_FUNCTION(atan)
937
+
938
+ void Init_mpc() {
939
+ cMPC = rb_define_class ("MPC", rb_cNumeric);
940
+
941
+ rb_define_const (cMPC, "MPC_VERSION", rb_str_new2(MPC_VERSION_STRING));
942
+
943
+ // Initialization Functions and Assignment Functions
944
+ rb_define_singleton_method (cMPC, "new", r_mpcsg_new, -1);
945
+ rb_define_method (cMPC, "initialize", r_mpc_initialize, -1);
946
+ rb_define_method (cMPC, "prec", r_mpc_prec, 0);
947
+ // TODO rb_define_method (cMPC, "prec2", r_mpc_prec, 0);
948
+ // TODO rb_define_method (cMPC, "prec=", r_mpc_prec, 1);
949
+
950
+ // Conversion Functions
951
+ // TODO research Ruby's Complex; see if it uses complex.h
952
+
953
+ // String and Stream Input and Output
954
+ rb_define_method (cMPC, "to_s", r_mpc_to_s, -1);
955
+
956
+ // Comparison Functions
957
+ rb_define_method(cMPC, "<=>", r_mpc_cmp, 1);
958
+ rb_define_method(cMPC, "==", r_mpc_eq, 1);
959
+
960
+ // Projection and Decomposing Functions
961
+ rb_define_method (cMPC, "real", r_mpc_real, -1);
962
+ rb_define_method (cMPC, "imag", r_mpc_imag, -1);
963
+ // TODO rb_define_method (cMPC, "arg", r_mpc_arg, 0);
964
+ rb_define_method (cMPC, "proj", r_mpc_proj, -1);
965
+
966
+ // Basic Arithmetic Functions
967
+ rb_define_method (cMPC, "add", r_mpc_add, -1);
968
+ rb_define_method (cMPC, "+", r_mpc_add2, 1);
969
+ rb_define_method (cMPC, "sub", r_mpc_sub, -1);
970
+ rb_define_method (cMPC, "-", r_mpc_sub2, 1);
971
+ rb_define_method (cMPC, "neg", r_mpc_neg, -1);
972
+ rb_define_method (cMPC, "-@", r_mpc_neg2, 0);
973
+ rb_define_method (cMPC, "mul", r_mpc_mul, -1);
974
+ rb_define_method (cMPC, "*", r_mpc_mul2, 1);
975
+ rb_define_method (cMPC, "sqr", r_mpc_sqr, -1);
976
+ // TODO rb_define_method (cMPC, "fma", r_mpc_fma, 2);
977
+ // TODO rb_define_method (cMPC, "/", r_mpc_div, 1);
978
+ rb_define_method (cMPC, "conj", r_mpc_conj, -1);
979
+ rb_define_method (cMPC, "abs", r_mpc_abs, -1);
980
+ // TODO rb_define_method (cMPC, "norm", r_mpc_norm, 0);
981
+ // TODO rb_define_method (cMPC, "mul_2exp", r_mpc_mul_2exp, 1);
982
+ // TODO rb_define_method (cMPC, "div_2exp", r_mpc_div_2exp, 1);
983
+
984
+ // Power Functions and Logarithm
985
+ rb_define_method (cMPC, "sqrt", r_mpc_sqrt, -1);
986
+ // TODO rb_define_method (cMPC, "**", r_mpc_pow, 1);
987
+ rb_define_method (cMPC, "exp", r_mpc_exp, -1);
988
+ rb_define_method (cMPC, "log", r_mpc_log, -1);
989
+ // TODO rb_define_method (cMPC, "log10", r_mpc_log10, -1);
990
+
991
+ // Trigonometric Functions
992
+ rb_define_method (cMPC, "sin", r_mpc_sin, -1);
993
+ rb_define_method (cMPC, "cos", r_mpc_cos, -1);
994
+ // TODO rb_define_method (cMPC, "sin_cos", r_mpc_sin_cos, -1);
995
+ rb_define_method (cMPC, "tan", r_mpc_tan, -1);
996
+ rb_define_method (cMPC, "sinh", r_mpc_sinh, -1);
997
+ rb_define_method (cMPC, "cosh", r_mpc_cosh, -1);
998
+ rb_define_method (cMPC, "tanh", r_mpc_tanh, -1);
999
+ rb_define_method (cMPC, "asin", r_mpc_asin, -1);
1000
+ rb_define_method (cMPC, "acos", r_mpc_acos, -1);
1001
+ rb_define_method (cMPC, "atan", r_mpc_atan, -1);
1002
+ // TODO rb_define_method (cMPC, "asinh", r_mpc_asinh, -1);
1003
+ // TODO rb_define_method (cMPC, "acosh", r_mpc_acosh, -1);
1004
+ // TODO rb_define_method (cMPC, "atanh", r_mpc_atanh, -1);
1005
+
1006
+ // Miscellaneous Functions
1007
+ // TODO rb_define_method (cMPC, "urandom", r_mpc_urandom, 1);
1008
+
1009
+ init_mpcrnd();
1010
+ }