gnu_mpc 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }