ruby-calc 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +52 -0
- data/.rubocop_todo.yml +11 -0
- data/.travis.yml +15 -0
- data/.yardopts +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +497 -0
- data/Rakefile +23 -0
- data/bin/console +10 -0
- data/bin/install_calc.sh +18 -0
- data/bin/makefile.patch +48 -0
- data/bin/setup +7 -0
- data/bin/todo.rb +374 -0
- data/ext/calc/c.c +775 -0
- data/ext/calc/calc.c +192 -0
- data/ext/calc/calc.h +71 -0
- data/ext/calc/config.c +239 -0
- data/ext/calc/convert.c +193 -0
- data/ext/calc/extconf.rb +29 -0
- data/ext/calc/math_error.c +72 -0
- data/ext/calc/numeric.c +623 -0
- data/ext/calc/q.c +2755 -0
- data/lib/calc.rb +214 -0
- data/lib/calc/c.rb +371 -0
- data/lib/calc/import.rb +6 -0
- data/lib/calc/numeric.rb +208 -0
- data/lib/calc/q.rb +628 -0
- data/lib/calc/version.rb +3 -0
- data/ruby-calc.gemspec +29 -0
- metadata +167 -0
data/ext/calc/c.c
ADDED
@@ -0,0 +1,775 @@
|
|
1
|
+
#include "calc.h"
|
2
|
+
|
3
|
+
/* Document-class: Calc::C
|
4
|
+
*
|
5
|
+
* Calc complex number.
|
6
|
+
*
|
7
|
+
* A complex number consists of a real and an imaginary part, both of which
|
8
|
+
* are Calc::Q objects.
|
9
|
+
*
|
10
|
+
* Wraps the libcalc C type `COMPLEX*`.
|
11
|
+
*/
|
12
|
+
VALUE cC;
|
13
|
+
|
14
|
+
void
|
15
|
+
cc_free(void *p)
|
16
|
+
{
|
17
|
+
comfree((COMPLEX *) p);
|
18
|
+
}
|
19
|
+
|
20
|
+
const rb_data_type_t calc_c_type = {
|
21
|
+
"Calc::C",
|
22
|
+
{0, cc_free, 0},
|
23
|
+
0, 0
|
24
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
25
|
+
, RUBY_TYPED_FREE_IMMEDIATELY
|
26
|
+
#endif
|
27
|
+
};
|
28
|
+
|
29
|
+
VALUE
|
30
|
+
cc_alloc(VALUE klass)
|
31
|
+
{
|
32
|
+
return TypedData_Wrap_Struct(klass, &calc_c_type, 0);
|
33
|
+
}
|
34
|
+
|
35
|
+
/* Creates a new complex number.
|
36
|
+
*
|
37
|
+
* If a single param of type Complex or Calc::C, returns a new complex number
|
38
|
+
* with the same real and imaginary parts.
|
39
|
+
*
|
40
|
+
* If a single param of other numeric types (Fixnum, Bignum, Rational, Float,
|
41
|
+
* Calc::Q), returns a complex number with the specified real part and zero
|
42
|
+
* imaginary part.
|
43
|
+
*
|
44
|
+
* If two params, returns a complex number with the specified real and
|
45
|
+
* imaginary parts; the parts can be any type allowed by Calc::Q.new.
|
46
|
+
*/
|
47
|
+
static VALUE
|
48
|
+
cc_initialize(int argc, VALUE * argv, VALUE self)
|
49
|
+
{
|
50
|
+
COMPLEX *cself;
|
51
|
+
NUMBER *qre, *qim;
|
52
|
+
VALUE re, im;
|
53
|
+
setup_math_error();
|
54
|
+
|
55
|
+
if (rb_scan_args(argc, argv, "11", &re, &im) == 1) {
|
56
|
+
if (CALC_C_P(re)) {
|
57
|
+
cself = clink((COMPLEX *) DATA_PTR(re));
|
58
|
+
}
|
59
|
+
else if (TYPE(re) == T_COMPLEX) {
|
60
|
+
cself = value_to_complex(re);
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
qre = value_to_number(re, 1);
|
64
|
+
cself = qqtoc(qre, &_qzero_);
|
65
|
+
qfree(qre);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
qre = value_to_number(re, 1);
|
70
|
+
qim = value_to_number(im, 1);
|
71
|
+
cself = qqtoc(qre, qim);
|
72
|
+
qfree(qre);
|
73
|
+
qfree(qim);
|
74
|
+
}
|
75
|
+
DATA_PTR(self) = cself;
|
76
|
+
|
77
|
+
return self;
|
78
|
+
}
|
79
|
+
|
80
|
+
static VALUE
|
81
|
+
cc_initialize_copy(VALUE obj, VALUE orig)
|
82
|
+
{
|
83
|
+
COMPLEX *corig;
|
84
|
+
|
85
|
+
if (obj == orig) {
|
86
|
+
return obj;
|
87
|
+
}
|
88
|
+
if (!CALC_C_P(orig)) {
|
89
|
+
rb_raise(rb_eTypeError, "wrong argument type");
|
90
|
+
}
|
91
|
+
corig = DATA_PTR(orig);
|
92
|
+
DATA_PTR(obj) = clink(corig);
|
93
|
+
return obj;
|
94
|
+
}
|
95
|
+
|
96
|
+
static VALUE
|
97
|
+
numeric_op(VALUE self, VALUE other,
|
98
|
+
COMPLEX * (fcc) (COMPLEX *, COMPLEX *), COMPLEX * (fcq) (COMPLEX *, NUMBER *))
|
99
|
+
{
|
100
|
+
COMPLEX *cresult, *cother;
|
101
|
+
setup_math_error();
|
102
|
+
|
103
|
+
if (CALC_C_P(other)) {
|
104
|
+
cresult = (*fcc) (DATA_PTR(self), DATA_PTR(other));
|
105
|
+
}
|
106
|
+
else if (fcq && CALC_Q_P(other)) {
|
107
|
+
cresult = (*fcq) (DATA_PTR(self), DATA_PTR(other));
|
108
|
+
}
|
109
|
+
else {
|
110
|
+
cother = value_to_complex(other);
|
111
|
+
cresult = (*fcc) (DATA_PTR(self), cother);
|
112
|
+
comfree(cother);
|
113
|
+
}
|
114
|
+
return wrap_complex(cresult);
|
115
|
+
}
|
116
|
+
|
117
|
+
static VALUE
|
118
|
+
trans_function(int argc, VALUE * argv, VALUE self, COMPLEX * (*f) (COMPLEX *, NUMBER *))
|
119
|
+
{
|
120
|
+
VALUE result, epsilon;
|
121
|
+
COMPLEX *cresult;
|
122
|
+
NUMBER *qepsilon;
|
123
|
+
setup_math_error();
|
124
|
+
|
125
|
+
if (rb_scan_args(argc, argv, "01", &epsilon) == 0) {
|
126
|
+
cresult = (*f) (DATA_PTR(self), conf->epsilon);
|
127
|
+
}
|
128
|
+
else {
|
129
|
+
qepsilon = value_to_number(epsilon, 1);
|
130
|
+
cresult = (*f) (DATA_PTR(self), qepsilon);
|
131
|
+
qfree(qepsilon);
|
132
|
+
}
|
133
|
+
if (!cresult) {
|
134
|
+
rb_raise(e_MathError, "Complex transcendental function returned NULL");
|
135
|
+
}
|
136
|
+
result = wrap_complex(cresult);
|
137
|
+
return result;
|
138
|
+
}
|
139
|
+
|
140
|
+
static VALUE
|
141
|
+
trans_function2(int argc, VALUE * argv, VALUE self,
|
142
|
+
COMPLEX * (f) (COMPLEX *, COMPLEX *, NUMBER *))
|
143
|
+
{
|
144
|
+
VALUE arg, epsilon;
|
145
|
+
COMPLEX *carg, *cresult;
|
146
|
+
NUMBER *qepsilon;
|
147
|
+
setup_math_error();
|
148
|
+
|
149
|
+
if (rb_scan_args(argc, argv, "11", &arg, &epsilon) == 1) {
|
150
|
+
carg = value_to_complex(arg);
|
151
|
+
cresult = (*f) (DATA_PTR(self), carg, conf->epsilon);
|
152
|
+
comfree(carg);
|
153
|
+
}
|
154
|
+
else {
|
155
|
+
carg = value_to_complex(arg);
|
156
|
+
qepsilon = value_to_number(epsilon, 1);
|
157
|
+
cresult = (*f) (DATA_PTR(self), carg, qepsilon);
|
158
|
+
qfree(qepsilon);
|
159
|
+
comfree(carg);
|
160
|
+
}
|
161
|
+
if (!cresult) {
|
162
|
+
rb_raise(e_MathError, "Complex transcendental function returned NULL");
|
163
|
+
}
|
164
|
+
return wrap_complex(cresult);
|
165
|
+
}
|
166
|
+
|
167
|
+
/*****************************************************************************
|
168
|
+
* instance method implementations *
|
169
|
+
*****************************************************************************/
|
170
|
+
|
171
|
+
/* Performs complex multiplication.
|
172
|
+
*
|
173
|
+
* @param y [Numeric,Numeric::Calc]
|
174
|
+
* @return [Calc::C]
|
175
|
+
* @example
|
176
|
+
* Calc::C(1,1) * Calc::C(1,1) #=> Calc::C(2i)
|
177
|
+
*/
|
178
|
+
static VALUE
|
179
|
+
cc_multiply(VALUE x, VALUE y)
|
180
|
+
{
|
181
|
+
return numeric_op(x, y, &c_mul, &c_mulq);
|
182
|
+
}
|
183
|
+
|
184
|
+
/* Performs complex addition.
|
185
|
+
*
|
186
|
+
* @param y [Numeric,Numeric::Calc]
|
187
|
+
* @return [Calc::C]
|
188
|
+
* @example
|
189
|
+
* Calc::C(1,1) + Calc::C(2,-2) #=> Calc::C(3-1i)
|
190
|
+
*/
|
191
|
+
static VALUE
|
192
|
+
cc_add(VALUE x, VALUE y)
|
193
|
+
{
|
194
|
+
return numeric_op(x, y, &c_add, &c_addq);
|
195
|
+
}
|
196
|
+
|
197
|
+
/* Performs complex subtraction.
|
198
|
+
*
|
199
|
+
* @param y [Numeric,Numeric::Calc]
|
200
|
+
* @return [Calc::C]
|
201
|
+
* @example
|
202
|
+
* Calc::C(1,1) - Calc::C(2,2) #=> Calc::C(-1-1i)
|
203
|
+
*/
|
204
|
+
static VALUE
|
205
|
+
cc_subtract(VALUE x, VALUE y)
|
206
|
+
{
|
207
|
+
return numeric_op(x, y, &c_sub, &c_subq);
|
208
|
+
}
|
209
|
+
|
210
|
+
/* Unary minus. Returns the receiver's value, negated.
|
211
|
+
*
|
212
|
+
* @return [Calc::C]
|
213
|
+
* @example
|
214
|
+
* -Calc::C(1,-1) #=> Calc::C(-1,1)
|
215
|
+
*/
|
216
|
+
static VALUE
|
217
|
+
cc_uminus(VALUE self)
|
218
|
+
{
|
219
|
+
setup_math_error();
|
220
|
+
return wrap_complex(c_sub(&_czero_, DATA_PTR(self)));
|
221
|
+
}
|
222
|
+
|
223
|
+
/* Performs complex division.
|
224
|
+
*
|
225
|
+
* @param y [Numeric,Numeric::Calc]
|
226
|
+
* @return [Calc::C]
|
227
|
+
* @example
|
228
|
+
* Calc::C(1,1) / Calc::C(0,1) #=> Calc::C(1-1i)
|
229
|
+
*/
|
230
|
+
static VALUE
|
231
|
+
cc_divide(VALUE x, VALUE y)
|
232
|
+
{
|
233
|
+
return numeric_op(x, y, &c_div, &c_divq);
|
234
|
+
}
|
235
|
+
|
236
|
+
/* Test for equality.
|
237
|
+
*
|
238
|
+
* If the other value is complex (Calc::C or Complex), returns true if the
|
239
|
+
* real an imaginary parts of both numbers are the same.
|
240
|
+
*
|
241
|
+
* The other value is some other numberic type (Fixnum, Bignum, Calc::Q,
|
242
|
+
* Rational or Float) then returns true if the complex part of this number is
|
243
|
+
* zero and the real part is equal to the other.
|
244
|
+
*
|
245
|
+
* For any other type, returns false.
|
246
|
+
*
|
247
|
+
* @return [Boolean]
|
248
|
+
* @example
|
249
|
+
* Calc::C(1,2) == Complex(1,2) #=> true
|
250
|
+
* Calc::C(1,2) == Calc::C(1,2) #=> true
|
251
|
+
* Calc::C(4,0) == 4 #=> true
|
252
|
+
* Calc::C(4,1) == 4 #=> false
|
253
|
+
*/
|
254
|
+
static VALUE
|
255
|
+
cc_equal(VALUE self, VALUE other)
|
256
|
+
{
|
257
|
+
COMPLEX *cself, *cother;
|
258
|
+
int result;
|
259
|
+
setup_math_error();
|
260
|
+
|
261
|
+
cself = DATA_PTR(self);
|
262
|
+
if (CALC_C_P(other)) {
|
263
|
+
result = !c_cmp(cself, DATA_PTR(other));
|
264
|
+
}
|
265
|
+
else if (TYPE(other) == T_COMPLEX) {
|
266
|
+
cother = value_to_complex(other);
|
267
|
+
result = !c_cmp(cself, cother);
|
268
|
+
comfree(cother);
|
269
|
+
}
|
270
|
+
else if (TYPE(other) == T_FIXNUM || TYPE(other) == T_BIGNUM || TYPE(other) == T_RATIONAL ||
|
271
|
+
TYPE(other) == T_FLOAT || CALC_Q_P(other)) {
|
272
|
+
cother = qqtoc(value_to_number(other, 0), &_qzero_);
|
273
|
+
result = !c_cmp(cself, cother);
|
274
|
+
comfree(cother);
|
275
|
+
}
|
276
|
+
else {
|
277
|
+
return Qfalse;
|
278
|
+
}
|
279
|
+
|
280
|
+
return result ? Qtrue : Qfalse;
|
281
|
+
}
|
282
|
+
|
283
|
+
/* Inverse trigonometric cosine
|
284
|
+
*
|
285
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
286
|
+
* @return [Calc::C]
|
287
|
+
* @example
|
288
|
+
* Calc::C(2,3).acos #=> Calc::C(1.00014354247379721852-1.98338702991653543235i)
|
289
|
+
*/
|
290
|
+
static VALUE
|
291
|
+
cc_acos(int argc, VALUE * argv, VALUE self)
|
292
|
+
{
|
293
|
+
return trans_function(argc, argv, self, &c_acos);
|
294
|
+
}
|
295
|
+
|
296
|
+
/* Inverse hyperbolic cosine
|
297
|
+
*
|
298
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
299
|
+
* @return [Calc::C]
|
300
|
+
* @example
|
301
|
+
* Calc::C(2,3).acosh #=> Calc::C(1.98338702991653543235+1.00014354247379721852i)
|
302
|
+
*/
|
303
|
+
static VALUE
|
304
|
+
cc_acosh(int argc, VALUE * argv, VALUE self)
|
305
|
+
{
|
306
|
+
return trans_function(argc, argv, self, &c_acosh);
|
307
|
+
}
|
308
|
+
|
309
|
+
/* Inverse trigonometric cotangent
|
310
|
+
*
|
311
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
312
|
+
* @return [Calc::C]
|
313
|
+
* @example
|
314
|
+
* Calc::C(2,3).acot #=> Calc::C(0.1608752771983210967-~0.22907268296853876630i)
|
315
|
+
*/
|
316
|
+
static VALUE
|
317
|
+
cc_acot(int argc, VALUE * argv, VALUE self)
|
318
|
+
{
|
319
|
+
return trans_function(argc, argv, self, &c_acot);
|
320
|
+
}
|
321
|
+
|
322
|
+
/* Inverse hyperbolic cotangent
|
323
|
+
*
|
324
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
325
|
+
* @return [Calc::C]
|
326
|
+
* @example
|
327
|
+
* Calc::C(2,3).acoth #=> Calc::C(~0.14694666622552975204-~0.23182380450040305810i)
|
328
|
+
*/
|
329
|
+
static VALUE
|
330
|
+
cc_acoth(int argc, VALUE * argv, VALUE self)
|
331
|
+
{
|
332
|
+
return trans_function(argc, argv, self, &c_acoth);
|
333
|
+
}
|
334
|
+
|
335
|
+
/* Inverse trigonometric cosecant
|
336
|
+
*
|
337
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
338
|
+
* @return [Calc::C]
|
339
|
+
* @example
|
340
|
+
* Calc::C(2,3).acsc #=> Calc::C(0.15038560432786196325-0.23133469857397331455i)
|
341
|
+
*/
|
342
|
+
static VALUE
|
343
|
+
cc_acsc(int argc, VALUE * argv, VALUE self)
|
344
|
+
{
|
345
|
+
return trans_function(argc, argv, self, &c_acsc);
|
346
|
+
}
|
347
|
+
|
348
|
+
/* Inverse hyperbolic cosecant
|
349
|
+
*
|
350
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
351
|
+
* @return [Calc::C]
|
352
|
+
* @example
|
353
|
+
* Calc::C(2,3).acsch #=> Calc::C(0.15735549884498542878-0.22996290237720785451i)
|
354
|
+
*/
|
355
|
+
static VALUE
|
356
|
+
cc_acsch(int argc, VALUE * argv, VALUE self)
|
357
|
+
{
|
358
|
+
return trans_function(argc, argv, self, &c_acsch);
|
359
|
+
}
|
360
|
+
|
361
|
+
/* Inverse gudermannian function
|
362
|
+
*
|
363
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
364
|
+
* @return [Calc::C]
|
365
|
+
* @example
|
366
|
+
* Calc::C(1,2).agd #=> Calc::C(0.22751065843194319695+1.422911462459226797i)
|
367
|
+
*/
|
368
|
+
static VALUE
|
369
|
+
cc_agd(int argc, VALUE * argv, VALUE self)
|
370
|
+
{
|
371
|
+
return trans_function(argc, argv, self, &c_agd);
|
372
|
+
}
|
373
|
+
|
374
|
+
/* Inverse trigonometric secant
|
375
|
+
*
|
376
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
377
|
+
* @return [Calc::C]
|
378
|
+
* @example
|
379
|
+
* Calc::C(2,3).asec #=> Calc::C(1.42041072246703465598+0.23133469857397331455i)
|
380
|
+
*/
|
381
|
+
static VALUE
|
382
|
+
cc_asec(int argc, VALUE * argv, VALUE self)
|
383
|
+
{
|
384
|
+
return trans_function(argc, argv, self, &c_asec);
|
385
|
+
}
|
386
|
+
|
387
|
+
/* Inverse hyperbolic secant
|
388
|
+
*
|
389
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
390
|
+
* @return [Calc::C]
|
391
|
+
* @example
|
392
|
+
* Calc::C(2,3).asech #=> Calc::C(0.23133469857397331455-1.42041072246703465598i)
|
393
|
+
*/
|
394
|
+
static VALUE
|
395
|
+
cc_asech(int argc, VALUE * argv, VALUE self)
|
396
|
+
{
|
397
|
+
return trans_function(argc, argv, self, &c_asech);
|
398
|
+
}
|
399
|
+
|
400
|
+
/* Inverse trigonometric sine
|
401
|
+
*
|
402
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
403
|
+
* @return [Calc::C]
|
404
|
+
* @example
|
405
|
+
* Calc::C(2,3).asin #=> Calc::C(0.57065278432109940071+1.98338702991653543235i)
|
406
|
+
*/
|
407
|
+
static VALUE
|
408
|
+
cc_asin(int argc, VALUE * argv, VALUE self)
|
409
|
+
{
|
410
|
+
return trans_function(argc, argv, self, &c_asin);
|
411
|
+
}
|
412
|
+
|
413
|
+
/* Inverse hyperbolic sine
|
414
|
+
*
|
415
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
416
|
+
* @return [Calc::C]
|
417
|
+
* @example
|
418
|
+
* Calc::C(2,3).asinh #=> Calc::C(1.96863792579309629179+0.96465850440760279204i
|
419
|
+
*/
|
420
|
+
static VALUE
|
421
|
+
cc_asinh(int argc, VALUE * argv, VALUE self)
|
422
|
+
{
|
423
|
+
return trans_function(argc, argv, self, &c_asinh);
|
424
|
+
}
|
425
|
+
|
426
|
+
/* Inverse trigonometric tangent
|
427
|
+
*
|
428
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
429
|
+
* @return [Calc::C]
|
430
|
+
* @example
|
431
|
+
* Calc::C(2,3).atan #=> Calc::C(1.40992104959657552253+~0.22907268296853876630i)
|
432
|
+
*/
|
433
|
+
static VALUE
|
434
|
+
cc_atan(int argc, VALUE * argv, VALUE self)
|
435
|
+
{
|
436
|
+
return trans_function(argc, argv, self, &c_atan);
|
437
|
+
}
|
438
|
+
|
439
|
+
/* Inverse hyperbolic tangent
|
440
|
+
*
|
441
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
442
|
+
* @return [Calc::C]
|
443
|
+
* @example
|
444
|
+
* Calc::C(2,3).atanh #=> Calc::C(~0.14694666622552975204+~1.33897252229449356112i)
|
445
|
+
*/
|
446
|
+
static VALUE
|
447
|
+
cc_atanh(int argc, VALUE * argv, VALUE self)
|
448
|
+
{
|
449
|
+
return trans_function(argc, argv, self, &c_atanh);
|
450
|
+
}
|
451
|
+
|
452
|
+
/* Cosine
|
453
|
+
*
|
454
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
455
|
+
* @return [Calc::C]
|
456
|
+
* @example
|
457
|
+
* Calc::C(2,3).cos #=> Calc::C(-4.18962569096880723013-9.10922789375533659798i)
|
458
|
+
*/
|
459
|
+
static VALUE
|
460
|
+
cc_cos(int argc, VALUE * argv, VALUE self)
|
461
|
+
{
|
462
|
+
return trans_function(argc, argv, self, &c_cos);
|
463
|
+
}
|
464
|
+
|
465
|
+
/* Hyperbolic cosine
|
466
|
+
*
|
467
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
468
|
+
* @return [Calc::C]
|
469
|
+
* @example
|
470
|
+
* Calc::C(2,3).cosh #=> Calc::C(~-3.72454550491532256548+~0.51182256998738460884i)
|
471
|
+
*/
|
472
|
+
static VALUE
|
473
|
+
cc_cosh(int argc, VALUE * argv, VALUE self)
|
474
|
+
{
|
475
|
+
return trans_function(argc, argv, self, &c_cosh);
|
476
|
+
}
|
477
|
+
|
478
|
+
/* Returns true if the number is real and even
|
479
|
+
*
|
480
|
+
* @return [Boolean]
|
481
|
+
* @example
|
482
|
+
* Calc::C(2,0).even? #=> true
|
483
|
+
* Calc::C(2,2).even? #=> false
|
484
|
+
*/
|
485
|
+
static VALUE
|
486
|
+
cc_evenp(VALUE self)
|
487
|
+
{
|
488
|
+
/* note that macro ciseven() doesn't match calc's actual behaviour */
|
489
|
+
COMPLEX *cself = DATA_PTR(self);
|
490
|
+
if (cisreal(cself) && qiseven(cself->real)) {
|
491
|
+
return Qtrue;
|
492
|
+
}
|
493
|
+
return Qfalse;
|
494
|
+
}
|
495
|
+
|
496
|
+
/* Exponential function
|
497
|
+
*
|
498
|
+
* @param eps [Numeric] (optional) calculation accuracy
|
499
|
+
* @return [Calc::C]
|
500
|
+
* @example
|
501
|
+
* Calc::C(1,2).exp #=> Calc::C(-1.13120438375681363843+2.47172667200481892762i)
|
502
|
+
*/
|
503
|
+
static VALUE
|
504
|
+
cc_exp(int argc, VALUE * argv, VALUE self)
|
505
|
+
{
|
506
|
+
return trans_function(argc, argv, self, &c_exp);
|
507
|
+
}
|
508
|
+
|
509
|
+
/* Return the fractional part of self
|
510
|
+
*
|
511
|
+
* @return [Calc::C]
|
512
|
+
* @example
|
513
|
+
* Calc::C("2.15", "-3.25").frac #=> Calc::C(0.15-0.25i)
|
514
|
+
*/
|
515
|
+
static VALUE
|
516
|
+
cc_frac(VALUE self)
|
517
|
+
{
|
518
|
+
setup_math_error();
|
519
|
+
return wrap_complex(c_frac(DATA_PTR(self)));
|
520
|
+
}
|
521
|
+
|
522
|
+
/* Gudermannian function
|
523
|
+
*
|
524
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
525
|
+
* @return [Calc::C]
|
526
|
+
* @example
|
527
|
+
*/
|
528
|
+
static VALUE
|
529
|
+
cc_gd(int argc, VALUE * argv, VALUE self)
|
530
|
+
{
|
531
|
+
return trans_function(argc, argv, self, &c_gd);
|
532
|
+
}
|
533
|
+
|
534
|
+
/* Returns the imaginary part of a complex number
|
535
|
+
*
|
536
|
+
* @return [Calc::Q]
|
537
|
+
* @example
|
538
|
+
* Calc::C(1,2).im #=> Calc::Q(2)
|
539
|
+
*/
|
540
|
+
static VALUE
|
541
|
+
cc_im(VALUE self)
|
542
|
+
{
|
543
|
+
COMPLEX *cself;
|
544
|
+
setup_math_error();
|
545
|
+
|
546
|
+
cself = DATA_PTR(self);
|
547
|
+
return wrap_number(qlink(cself->imag));
|
548
|
+
}
|
549
|
+
|
550
|
+
/* Returns true if the number is imaginary (ie, has zero real part and non-zero
|
551
|
+
* imaginary part)
|
552
|
+
*
|
553
|
+
* @return [Boolean]
|
554
|
+
* @example
|
555
|
+
* Calc::C(0,1).imag? #=> true
|
556
|
+
* Calc::C(1,1).imag? #=> false
|
557
|
+
*/
|
558
|
+
static VALUE
|
559
|
+
cc_imagp(VALUE self)
|
560
|
+
{
|
561
|
+
return cisimag((COMPLEX *) DATA_PTR(self)) ? Qtrue : Qfalse;
|
562
|
+
}
|
563
|
+
|
564
|
+
/* Integer parts of the number
|
565
|
+
*
|
566
|
+
* @return [Calc::C]
|
567
|
+
* @example
|
568
|
+
* Calc::C("2.15", "-3.25").int #=> Calc::C(2-3i)
|
569
|
+
*/
|
570
|
+
static VALUE
|
571
|
+
cc_int(VALUE self)
|
572
|
+
{
|
573
|
+
COMPLEX *cself;
|
574
|
+
setup_math_error();
|
575
|
+
|
576
|
+
cself = DATA_PTR(self);
|
577
|
+
if (cisint(cself)) {
|
578
|
+
return self;
|
579
|
+
}
|
580
|
+
return wrap_complex(c_int(cself));
|
581
|
+
}
|
582
|
+
|
583
|
+
/* Inverse of a complex number
|
584
|
+
*
|
585
|
+
* @return [Calc::C]
|
586
|
+
* @raise [Calc::MathError] if self is zero
|
587
|
+
* @example
|
588
|
+
* Calc::C(2+2i).inverse #=> Calc::C(0.25-0.25i)
|
589
|
+
*/
|
590
|
+
static VALUE
|
591
|
+
cc_inverse(VALUE self)
|
592
|
+
{
|
593
|
+
setup_math_error();
|
594
|
+
return wrap_complex(c_inv(DATA_PTR(self)));
|
595
|
+
}
|
596
|
+
|
597
|
+
/* Norm of a value
|
598
|
+
*
|
599
|
+
* For complex values, norm is the sum of re.norm and im.norm.
|
600
|
+
*
|
601
|
+
* @return [Calc::Q]
|
602
|
+
* @example
|
603
|
+
* Calc::C(3, 4).norm #=> Calc::Q(25)
|
604
|
+
* Calc::C(4, -5).norm #=> Calc::Q(41)
|
605
|
+
*/
|
606
|
+
static VALUE
|
607
|
+
cc_norm(VALUE self)
|
608
|
+
{
|
609
|
+
COMPLEX *cself;
|
610
|
+
NUMBER *q1, *q2, *qresult;
|
611
|
+
setup_math_error();
|
612
|
+
|
613
|
+
cself = DATA_PTR(self);
|
614
|
+
q1 = qsquare(cself->real);
|
615
|
+
q2 = qsquare(cself->imag);
|
616
|
+
qresult = qqadd(q1, q2);
|
617
|
+
qfree(q1);
|
618
|
+
qfree(q2);
|
619
|
+
return wrap_number(qresult);
|
620
|
+
}
|
621
|
+
|
622
|
+
/* Returns true if the number is real and odd
|
623
|
+
*
|
624
|
+
* @return [Boolean]
|
625
|
+
* @example
|
626
|
+
* Calc::C(1,0).odd? #=> true
|
627
|
+
* Calc::C(1,1).odd? #=> false
|
628
|
+
*/
|
629
|
+
static VALUE
|
630
|
+
cc_oddp(VALUE self)
|
631
|
+
{
|
632
|
+
/* note that macro cisodd() doesn't match calc's actual behaviour */
|
633
|
+
COMPLEX *cself = DATA_PTR(self);
|
634
|
+
if (cisreal(cself) && qisodd(cself->real)) {
|
635
|
+
return Qtrue;
|
636
|
+
}
|
637
|
+
return Qfalse;
|
638
|
+
}
|
639
|
+
|
640
|
+
/* Raise to a specified power
|
641
|
+
*
|
642
|
+
* @param y [Numeric,Numeric::Calc]
|
643
|
+
* @param eps [Numeric,Calc::Q] (optional) calculation accuracy
|
644
|
+
* @return [Calc::C]
|
645
|
+
* @example
|
646
|
+
* Calc::C(1,1) ** 2 #=> Calc::C(2i)
|
647
|
+
*/
|
648
|
+
static VALUE
|
649
|
+
cc_power(int argc, VALUE * argv, VALUE self)
|
650
|
+
{
|
651
|
+
/* todo: if y is integer, converting to NUMBER* and using c_powi might
|
652
|
+
* be faster */
|
653
|
+
return trans_function2(argc, argv, self, &c_power);
|
654
|
+
}
|
655
|
+
|
656
|
+
/* Returns the real part of a complex number
|
657
|
+
*
|
658
|
+
* @return [Calc::Q]
|
659
|
+
* @example
|
660
|
+
* Calc::C(1,2).re #=> Calc::Q(1)
|
661
|
+
*/
|
662
|
+
static VALUE
|
663
|
+
cc_re(VALUE self)
|
664
|
+
{
|
665
|
+
COMPLEX *cself;
|
666
|
+
setup_math_error();
|
667
|
+
|
668
|
+
cself = DATA_PTR(self);
|
669
|
+
return wrap_number(qlink(cself->real));
|
670
|
+
}
|
671
|
+
|
672
|
+
/* Returns true if the number is real (ie, has zero imaginary part)
|
673
|
+
*
|
674
|
+
* @return [Boolean]
|
675
|
+
* @example
|
676
|
+
* Calc::C(1,1).real? #=> false
|
677
|
+
* Calc::C(1,0).real? #=> true
|
678
|
+
*/
|
679
|
+
static VALUE
|
680
|
+
cc_realp(VALUE self)
|
681
|
+
{
|
682
|
+
return cisreal((COMPLEX *) DATA_PTR(self)) ? Qtrue : Qfalse;
|
683
|
+
}
|
684
|
+
|
685
|
+
/* Trigonometric sine
|
686
|
+
*
|
687
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
688
|
+
* @return [Calc::C]
|
689
|
+
* @example
|
690
|
+
* Calc::C(2,3).sin #=> Calc::C(9.15449914691142957347-4.16890695996656435076i)
|
691
|
+
*/
|
692
|
+
static VALUE
|
693
|
+
cc_sin(int argc, VALUE * argv, VALUE self)
|
694
|
+
{
|
695
|
+
return trans_function(argc, argv, self, &c_sin);
|
696
|
+
}
|
697
|
+
|
698
|
+
/* Hyperbolic sine
|
699
|
+
*
|
700
|
+
* @param eps [Calc::Q] (optional) calculation accuracy
|
701
|
+
* @return [Calc::C]
|
702
|
+
* @example
|
703
|
+
* Calc::C(2,3).acos #=>
|
704
|
+
*/
|
705
|
+
static VALUE
|
706
|
+
cc_sinh(int argc, VALUE * argv, VALUE self)
|
707
|
+
{
|
708
|
+
return trans_function(argc, argv, self, &c_sinh);
|
709
|
+
}
|
710
|
+
|
711
|
+
/* Returns true if real and imaginary parts are both zero
|
712
|
+
*
|
713
|
+
* @return [Boolean]
|
714
|
+
* @example
|
715
|
+
* Calc::C(1, 1).zero? #=> false
|
716
|
+
* Calc::C(0, 0).zero? #=> true
|
717
|
+
*/
|
718
|
+
static VALUE
|
719
|
+
cc_zerop(VALUE self)
|
720
|
+
{
|
721
|
+
return ciszero((COMPLEX *) DATA_PTR(self)) ? Qtrue : Qfalse;
|
722
|
+
}
|
723
|
+
|
724
|
+
/* class initialization */
|
725
|
+
|
726
|
+
void
|
727
|
+
define_calc_c(VALUE m)
|
728
|
+
{
|
729
|
+
cC = rb_define_class_under(m, "C", cNumeric);
|
730
|
+
rb_define_alloc_func(cC, cc_alloc);
|
731
|
+
rb_define_method(cC, "initialize", cc_initialize, -1);
|
732
|
+
rb_define_method(cC, "initialize_copy", cc_initialize_copy, 1);
|
733
|
+
|
734
|
+
rb_define_method(cC, "*", cc_multiply, 1);
|
735
|
+
rb_define_method(cC, "+", cc_add, 1);
|
736
|
+
rb_define_method(cC, "-", cc_subtract, 1);
|
737
|
+
rb_define_method(cC, "-@", cc_uminus, 0);
|
738
|
+
rb_define_method(cC, "/", cc_divide, 1);
|
739
|
+
rb_define_method(cC, "==", cc_equal, 1);
|
740
|
+
rb_define_method(cC, "acos", cc_acos, -1);
|
741
|
+
rb_define_method(cC, "acosh", cc_acosh, -1);
|
742
|
+
rb_define_method(cC, "acot", cc_acot, -1);
|
743
|
+
rb_define_method(cC, "acoth", cc_acoth, -1);
|
744
|
+
rb_define_method(cC, "acsc", cc_acsc, -1);
|
745
|
+
rb_define_method(cC, "acsch", cc_acsch, -1);
|
746
|
+
rb_define_method(cC, "agd", cc_agd, -1);
|
747
|
+
rb_define_method(cC, "asec", cc_asec, -1);
|
748
|
+
rb_define_method(cC, "asech", cc_asech, -1);
|
749
|
+
rb_define_method(cC, "asin", cc_asin, -1);
|
750
|
+
rb_define_method(cC, "asinh", cc_asinh, -1);
|
751
|
+
rb_define_method(cC, "atan", cc_atan, -1);
|
752
|
+
rb_define_method(cC, "atanh", cc_atanh, -1);
|
753
|
+
rb_define_method(cC, "cos", cc_cos, -1);
|
754
|
+
rb_define_method(cC, "cosh", cc_cosh, -1);
|
755
|
+
rb_define_method(cC, "even?", cc_evenp, 0);
|
756
|
+
rb_define_method(cC, "exp", cc_exp, -1);
|
757
|
+
rb_define_method(cC, "frac", cc_frac, 0);
|
758
|
+
rb_define_method(cC, "gd", cc_gd, -1);
|
759
|
+
rb_define_method(cC, "im", cc_im, 0);
|
760
|
+
rb_define_method(cC, "imag?", cc_imagp, 0);
|
761
|
+
rb_define_method(cC, "int", cc_int, 0);
|
762
|
+
rb_define_method(cC, "inverse", cc_inverse, 0);
|
763
|
+
rb_define_method(cC, "norm", cc_norm, 0);
|
764
|
+
rb_define_method(cC, "odd?", cc_oddp, 0);
|
765
|
+
rb_define_method(cC, "power", cc_power, -1);
|
766
|
+
rb_define_method(cC, "re", cc_re, 0);
|
767
|
+
rb_define_method(cC, "real?", cc_realp, 0);
|
768
|
+
rb_define_method(cC, "sin", cc_sin, -1);
|
769
|
+
rb_define_method(cC, "sinh", cc_sinh, -1);
|
770
|
+
rb_define_method(cC, "zero?", cc_zerop, 0);
|
771
|
+
|
772
|
+
rb_define_alias(cC, "**", "power");
|
773
|
+
rb_define_alias(cC, "imag", "im");
|
774
|
+
rb_define_alias(cC, "real", "re");
|
775
|
+
}
|