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.
- 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
|
+
}
|