ruby-calc 0.1.0

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