gnu_mpc 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING.md +13 -0
- data/Gemfile +17 -0
- data/Guardfile +18 -0
- data/Makefile +12 -0
- data/README.md +47 -0
- data/Rakefile +54 -0
- data/ext/extconf.rb +46 -0
- data/ext/mpc.c +1010 -0
- data/ext/mpcrnd.c +194 -0
- data/ext/ruby_gmp.h +343 -0
- data/ext/ruby_mpc.h +63 -0
- data/lib/mpc.rb +30 -0
- data/manual.md +933 -0
- data/manual.pdf +0 -0
- data/manual_template.latex +177 -0
- data/spec/acos_spec.rb +66 -0
- data/spec/add_args_spec.rb +51 -0
- data/spec/add_fr_spec.rb +54 -0
- data/spec/add_spec.rb +32 -0
- data/spec/asin_spec.rb +66 -0
- data/spec/atan_spec.rb +109 -0
- data/spec/conj_spec.rb +56 -0
- data/spec/cos_spec.rb +54 -0
- data/spec/cosh_spec.rb +26 -0
- data/spec/exp_spec.rb +62 -0
- data/spec/hash_arguments_spec.rb +17 -0
- data/spec/log_spec.rb +37 -0
- data/spec/mpc_single_function_args_spec.rb +41 -0
- data/spec/neg_spec.rb +30 -0
- data/spec/new_spec.rb +97 -0
- data/spec/proj_spec.rb +20 -0
- data/spec/real_spec.rb +23 -0
- data/spec/rounding_spec.rb +199 -0
- data/spec/sin_spec.rb +66 -0
- data/spec/sinh_spec.rb +65 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/sqr_spec.rb +96 -0
- data/spec/sqrt_spec.rb +72 -0
- data/spec/sub_spec.rb +50 -0
- data/spec/tan_spec.rb +55 -0
- data/spec/tanh_spec.rb +53 -0
- data/spec/to_s_spec.rb +77 -0
- data/spec/version_spec.rb +7 -0
- metadata +91 -0
data/COPYING.md
ADDED
@@ -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
|
data/Guardfile
ADDED
@@ -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
|
data/Makefile
ADDED
@@ -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
|
+
|
data/README.md
ADDED
@@ -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.
|
data/Rakefile
ADDED
@@ -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
|
+
|
data/ext/extconf.rb
ADDED
@@ -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')
|
data/ext/mpc.c
ADDED
@@ -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
|
+
}
|