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