fix codetest failure - ASSERT_ARGS does not have a ; after and
[parrot.git] / src / pmc / complex.pmc
blob8bfe21e490fa7871c6b02b964000c3a0dd88458e
1 /*
2 Copyright (C) 2004-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/pmc/complex.pmc - Complex Numbers PMC Class
9 =head1 DESCRIPTION
11 C<Complex> provides a representation of complex numbers. It handles
12 string parsing/generating and basic mathematical operations.
14 =head2 Functions
16 Equations used are sometimes listed.  At times, multiple equations are given,
17 but those starting with => are the ones used
19 =over 4
21 =cut
25 /* HEADERIZER HFILE: none */
26 /* HEADERIZER BEGIN: static */
27 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
29 static void complex_check_divide_zero(PARROT_INTERP, ARGIN(PMC *value))
30         __attribute__nonnull__(1)
31         __attribute__nonnull__(2);
33 static void complex_parse_string(PARROT_INTERP,
34     ARGOUT(FLOATVAL *re),
35     ARGOUT(FLOATVAL *im),
36     ARGIN(STRING *value))
37         __attribute__nonnull__(1)
38         __attribute__nonnull__(2)
39         __attribute__nonnull__(3)
40         __attribute__nonnull__(4)
41         FUNC_MODIFIES(*re)
42         FUNC_MODIFIES(*im);
44 static void float_check_divide_zero(PARROT_INTERP, FLOATVAL value)
45         __attribute__nonnull__(1);
47 static void int_check_divide_zero(PARROT_INTERP, INTVAL value)
48         __attribute__nonnull__(1);
50 #define ASSERT_ARGS_complex_check_divide_zero __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
51        PARROT_ASSERT_ARG(interp) \
52     , PARROT_ASSERT_ARG(value))
53 #define ASSERT_ARGS_complex_parse_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
54        PARROT_ASSERT_ARG(interp) \
55     , PARROT_ASSERT_ARG(re) \
56     , PARROT_ASSERT_ARG(im) \
57     , PARROT_ASSERT_ARG(value))
58 #define ASSERT_ARGS_float_check_divide_zero __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
59        PARROT_ASSERT_ARG(interp))
60 #define ASSERT_ARGS_int_check_divide_zero __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
61        PARROT_ASSERT_ARG(interp))
62 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
63 /* HEADERIZER END: static */
67 =item C<static void complex_parse_string(PARROT_INTERP, FLOATVAL *re, FLOATVAL
68 *im, STRING *value)>
70 Parses the string in C<value> to produce a complex number, represented
71 by the real (C<*re>) and imaginary (C<*im>) parts. Raises an exception
72 if it cannot understand the string.  The string should be of the form
73 C<a+bi> with optional spaces around C<+> and before C<i>. You can also
74 use C<j> instead of C<i>.
76 =cut
78 We have a conflict among our coding standards here.  Our 100-character line
79 limit meant that the following function declaration had to be split over two
80 lines.  However, that leads to t/codingstd/pmc_docs.t reporting that this
81 function lacks documentation -- reporting due to differences in whitespacing
82 between '=item' and function declaration.
86 static void
87 complex_parse_string(PARROT_INTERP,
88                      ARGOUT(FLOATVAL *re), ARGOUT(FLOATVAL *im), ARGIN(STRING *value))
90     ASSERT_ARGS(complex_parse_string)
92     char   * const str        = Parrot_str_to_cstring(interp, value);
93     char   *t                 = str;
94     char   *first_num_offset  = str;
95     char   *second_num_offset = NULL;
96     STRING *S;
98     INTVAL  i                 = 0;
99     INTVAL  first_num_minus   = 0;
100     INTVAL  second_num_minus  = 0;
101     UINTVAL first_num_length, second_num_length;
103     /* walk the string and identify the real and imaginary parts */
105     if (*t == '-') {
106         /* first number is negative */
107         ++t;
108         first_num_minus = 1;
110         /* allow for an optional space */
111         if (*t == ' ')
112             ++t;
113         first_num_offset = t;
114     }
116     /* skip digits */
117     while (*t >= '0' && *t <= '9')
118         ++t;
120     if (*t == '.') {
121         /* this number has a decimal point */
122         ++t;
124         /* skip digits */
125         while (*t >= '0' && *t <= '9')
126             ++t;
127     }
129     /* save the length of the real part */
130     first_num_length = t - first_num_offset;
132     /* end of string; we only have a real part */
133     if (*t == 0) {
134         second_num_length = 0;
135     }
136     else if ((*t == 'i' || *t == 'j') && *(t+1) == 0) {
137         /* there is only an imaginary part, so the first number was
138             actually the imaginary part */
139         second_num_length = first_num_length;
140         first_num_length  = 0;
141         second_num_offset = first_num_offset;
142         second_num_minus  = first_num_minus;
143         first_num_minus   = 0;
145         /* this is useful if there is no number for
146             the imaginary part, like in "-i" */
147         i = 1;
148     }
149     else {
150         /* skip an optional space */
151         if (*t == ' ')
152             ++t;
154         /* expect "+" or "-" and the imaginary part */
155         if (*t == '+' || *t == '-') {
156             /* save the sign */
157             second_num_minus = (*t == '-');
158             ++t;
160             /* skip another optional space */
161             if (*t == ' ')
162                 ++t;
164             /* save the beginning of the imaginary part */
165             second_num_offset = t;
167             /* skip digits */
168             while (*t >= '0' && *t <= '9')
169                 ++t;
171             if (*t == '.') {
172                 /* this number has a decimal point */
173                 ++t;
175                 /* skip digits */
176                 while (*t >= '0' && *t <= '9')
177                     ++t;
178             }
180             /* save the length of the imaginary part */
181             second_num_length = t - second_num_offset;
183             /* allow for one more optional space */
184             if (*t == ' ')
185                 ++t;
187             /* verify that the string ends properly */
188             if ((*t != 'i' && *t != 'j') || (*(t+1) != 0)) {
189                 /* imaginary part does not end in 'i' or 'j' */
190                 Parrot_ex_throw_from_c_args(interp, NULL,
191                     EXCEPTION_INVALID_STRING_REPRESENTATION,
192                     "Complex: malformed string");
193             }
195             /* this is useful if there is no number for the
196                 imaginary part, like in "2+i" */
197             i = 1;
199             /* all is OK, save the number */
200         }
201         else {
202             /* "+" or "-" not found: error */
203             Parrot_str_free_cstring(str);
205             Parrot_ex_throw_from_c_args(interp, NULL,
206                 EXCEPTION_INVALID_STRING_REPRESENTATION,
207                 "Complex: malformed string");
208         }
209     }
211     /* now we have the offsets and the lengths we turn them into float values */
213     if (first_num_length) {
214         /* there is a real part, interpret it */
215         S   = Parrot_str_new(interp, first_num_offset, first_num_length);
216         *re = Parrot_str_to_num(interp, S);
217     }
218     else {
219         /* consider the real part 0.0 */
220         *re = 0.0;
221     }
223     if (second_num_length) {
224         /* there is an imaginary part, interpret it */
225         S   = Parrot_str_new(interp, second_num_offset, second_num_length);
226         *im = Parrot_str_to_num(interp, S);
227     }
228     else {
229         /* consider the imaginary part 0.0 */
230         if (i) /* the string was something like "1+i" */
231             *im = 1.0;
232         else
233             *im = 0.0;
234     }
236     if (first_num_minus)
237         *re = -*re;
239     if (second_num_minus)
240         *im = -*im;
242     Parrot_str_free_cstring(str);
247 =item C<static void int_check_divide_zero(PARROT_INTERP, INTVAL value)>
249 =cut
253 static void
254 int_check_divide_zero(PARROT_INTERP, INTVAL value)
256     ASSERT_ARGS(int_check_divide_zero)
258     if (value == 0)
259         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_DIV_BY_ZERO,
260             "Divide by zero");
265 =item C<static void float_check_divide_zero(PARROT_INTERP, FLOATVAL value)>
267 =cut
271 static void
272 float_check_divide_zero(PARROT_INTERP, FLOATVAL value)
274     ASSERT_ARGS(float_check_divide_zero)
276     if (FLOAT_IS_ZERO(value))
277         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_DIV_BY_ZERO,
278             "Divide by zero");
283 =item C<static void complex_check_divide_zero(PARROT_INTERP, PMC *value)>
285 =cut
289 static void
290 complex_check_divide_zero(PARROT_INTERP, ARGIN(PMC *value))
292     ASSERT_ARGS(complex_check_divide_zero)
294     /* Throw an exception if we are dividing by zero. Check both the real part
295      * and the imaginary part.*/
297     if (FLOAT_IS_ZERO(VTABLE_get_number_keyed_int(interp, value, 0))
298             && FLOAT_IS_ZERO(VTABLE_get_number_keyed_int(interp, value, 1)))
299         Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_DIV_BY_ZERO,
300             "Divide by zero");
304 pmclass Complex provides complex provides scalar auto_attrs {
306     ATTR FLOATVAL re; /* real part */
307     ATTR FLOATVAL im; /* imaginary part */
311 =back
313 =head2 Methods
315 =over 4
317 =item C<void init()>
319 Initializes the complex number with the value 0+0i.
321 =item C<void init_pmc(PMC *initializer)>
323 Initializes the complex number with the specified initializer.
324 The initializer can be a string PMC or a numeric array with (real, imag)
326 =item C<PMC *clone()>
328 Creates an identical copy of the complex number.
330 =cut
334     VTABLE void init() {
335         SET_ATTR_re(INTERP, SELF, 0.0);
336         SET_ATTR_im(INTERP, SELF, 0.0);
337     }
339     VTABLE void init_pmc(PMC *initializer) {
340         const INTVAL arg_type = VTABLE_type(INTERP, initializer);
341         SELF.init();
342         switch (arg_type) {
343           case enum_class_String:
344             SELF.set_string_native(VTABLE_get_string(INTERP, initializer));
345             break;
346           case enum_class_FixedFloatArray:
347           case enum_class_ResizableFloatArray:
348           case enum_class_FixedIntegerArray:
349           case enum_class_ResizableIntegerArray:
350             if (VTABLE_get_integer(INTERP, initializer) == 2) {
351                 const FLOATVAL re = VTABLE_get_number_keyed_int(INTERP, initializer, 0);
352                 const FLOATVAL im = VTABLE_get_number_keyed_int(INTERP, initializer, 1);
353                 SET_ATTR_re(INTERP, SELF, re);
354                 SET_ATTR_im(INTERP, SELF, im);
355                 break;
356             }
357             /* else let it fall to default */
358           default:
359             if (VTABLE_isa(INTERP, initializer, CONST_STRING(INTERP, "String"))) {
360                 STRING * const s = VTABLE_get_string(INTERP, initializer);
361                 SELF.set_string_native(s);
362             }
363             else {
364                 Parrot_ex_throw_from_c_args(INTERP, NULL,
365                         EXCEPTION_INVALID_OPERATION,
366                         "Invalid Complex initializer");
367             }
368         }
369     }
371     VTABLE PMC *clone() {
372         PMC * const dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
373         FLOATVAL re, im;
375         GET_ATTR_re(INTERP, SELF, re);
376         GET_ATTR_im(INTERP, SELF, im);
377         SET_ATTR_re(INTERP, dest, re);
378         SET_ATTR_im(INTERP, dest, im);
380         return dest;
381     }
385 =item C<void freeze(PMC *visit)>
387 =item C<void thaw(PMC *visit)>
389 Serialize/deserialize this object for bytecode.
391 =cut
395     VTABLE void freeze(PMC *visit) {
396         FLOATVAL re, im;
398         SUPER(visit);
400         GET_ATTR_re(INTERP, SELF, re);
401         VTABLE_push_float(INTERP, visit, re);
403         GET_ATTR_im(INTERP, SELF, im);
404         VTABLE_push_float(INTERP, visit, im);
405     }
407     VTABLE void thaw(PMC *visit) {
408         FLOATVAL re, im;
410         SUPER(visit);
412         re = VTABLE_shift_float(INTERP, visit);
413         SET_ATTR_re(INTERP, SELF, re);
415         im = VTABLE_shift_float(INTERP, visit);
416         SET_ATTR_im(INTERP, SELF, im);
417     }
421 =item C<INTVAL get_integer()>
423 Returns the modulus of the complex number as an integer.
425 =item C<FLOATVAL get_number()>
427 Returns the modulus of the complex number.
429 =item C<STRING *get_string()>
431 Returns the complex number as a string in the form C<a+bi>.
433 =item C<INTVAL get_bool()>
435 Returns true if the complex number is non-zero.
437 =cut
441     VTABLE INTVAL get_integer() {
442         const FLOATVAL f = SELF.get_number();
443         return (INTVAL)f;
444     }
446     VTABLE FLOATVAL get_number() {
447         FLOATVAL re, im;
448         GET_ATTR_re(INTERP, SELF, re);
449         GET_ATTR_im(INTERP, SELF, im);
450         return sqrt(re * re + im * im);
451     }
453     VTABLE STRING *get_string() {
454         FLOATVAL re, im;
455         GET_ATTR_re(INTERP, SELF, re);
456         GET_ATTR_im(INTERP, SELF, im);
457         return Parrot_sprintf_c(INTERP, "%vg%+vgi", re, im);
458     }
460     VTABLE INTVAL get_bool() {
461         FLOATVAL re, im;
462         GET_ATTR_re(INTERP, SELF, re);
463         GET_ATTR_im(INTERP, SELF, im);
464         return !(FLOAT_IS_ZERO(re) && FLOAT_IS_ZERO(im));
465     }
469 =item C<INTVAL get_integer_keyed(PMC *key)>
471 =item C<INTVAL get_integer_keyed_str(STRING *key)>
473 =item C<FLOATVAL get_number_keyed(PMC *key)>
475 =item C<FLOATVAL get_number_keyed_str(STRING *key)>
477 =item C<PMC *get_pmc_keyed(PMC *key)>
479 =item C<PMC *get_pmc_keyed_str(STRING *key)>
481 Returns the requested number (real part for C<real> and imaginary for C<imag>).
483 =cut
487     VTABLE INTVAL get_integer_keyed(PMC *key) {
488         STRING * const s = VTABLE_get_string(INTERP, key);
489         return SELF.get_integer_keyed_str(s);
490     }
492     VTABLE INTVAL get_integer_keyed_str(STRING *key) {
493         const FLOATVAL f = SELF.get_number_keyed_str(key);
494         return (INTVAL)f;
495     }
497     VTABLE FLOATVAL get_number_keyed(PMC *key) {
498         STRING * const s = VTABLE_get_string(INTERP, key);
499         return SELF.get_number_keyed_str(s);
500     }
502     VTABLE FLOATVAL get_number_keyed_str(STRING *key) {
503         FLOATVAL value;
504         if (Parrot_str_equal(INTERP, key, CONST_STRING(INTERP, "real"))) {
505             GET_ATTR_re(INTERP, SELF, value);
506         }
507         else if (Parrot_str_equal(INTERP, key, CONST_STRING(INTERP, "imag"))) {
508             GET_ATTR_im(INTERP, SELF, value);
509         }
510         else
511             Parrot_ex_throw_from_c_args(INTERP, NULL,
512                 EXCEPTION_INVALID_OPERATION, "Complex: key is neither 'real' or 'imag'");
513         return value;
514     }
516     VTABLE PMC *get_pmc_keyed(PMC *key) {
517         if (VTABLE_isa(INTERP, key, CONST_STRING(INTERP, "Integer"))) {
518             const INTVAL i = VTABLE_get_integer(INTERP, key);
519             return SELF.get_pmc_keyed_int(i);
520         }
521         else {
522             STRING * const s = VTABLE_get_string(INTERP, key);
523             return SELF.get_pmc_keyed_str(s);
524         }
525     }
527     VTABLE PMC *get_pmc_keyed_str(STRING *key) {
528         PMC * const    ret = Parrot_pmc_new(INTERP, enum_class_Float);
529         const FLOATVAL val = SELF.get_number_keyed_str(key);
530         VTABLE_set_number_native(INTERP, ret, val);
531         return ret;
532     }
536 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
538 Returns the requested number (real part for C<0> and imaginary for C<1>).
540 =cut
544     VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
545         PMC * const    ret = Parrot_pmc_new(INTERP, enum_class_Float);
546         const FLOATVAL val = SELF.get_number_keyed_int(key);
547         VTABLE_set_number_native(INTERP, ret, val);
548         return ret;
549     }
553 =item C<FLOATVAL get_number_keyed_int(INTVAL key)>
555 Quick hack to emulate get_real() and get_imag():
557   key = 0 ... get real part
558   key = 1 ... get imag part
560 =item C<void set_number_keyed_int(INTVAL key, FLOATVAL v)>
562 Set real or imag depending on key
564 =cut
568     VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
569         FLOATVAL f;
570         switch (key) {
571           case 0:
572             GET_ATTR_re(INTERP, SELF, f);
573             break;
574           case 1:
575             GET_ATTR_im(INTERP, SELF, f);
576             break;
577           default:
578             Parrot_ex_throw_from_c_args(INTERP, NULL,
579                     EXCEPTION_INVALID_OPERATION, "Complex: key must be 0 or 1");
580         }
581         return f;
582     }
584     VTABLE void set_number_keyed_int(INTVAL key, FLOATVAL v) {
585         switch (key) {
586           case 0:
587             SET_ATTR_re(INTERP, SELF, v);
588             break;
589           case 1:
590             SET_ATTR_im(INTERP, SELF, v);
591             break;
592           default:
593             Parrot_ex_throw_from_c_args(INTERP, NULL,
594                     EXCEPTION_INVALID_OPERATION, "Complex: key must be 0 or 1");
595         }
596     }
599 =item C<void set_string_native(STRING *value)>
601 Parses the string C<value> into a complex number; raises an exception
602 on failure.
604 =item C<void set_pmc(PMC *value)>
606 if C<value> is a Complex PMC then the complex number is set to its
607 value; otherwise C<value>'s string representation is parsed with
608 C<set_string_native()>.
610 =item C<void set_integer_native(INTVAL value)>
612 =item C<void set_number_native(FLOATVAL value)>
614 Sets the real part of the complex number to C<value> and the imaginary
615 part to C<0.0>
617 =cut
621     VTABLE void set_string_native(STRING *value) {
622         FLOATVAL re, im;
623         complex_parse_string(INTERP, &re, &im, value);
624         SET_ATTR_re(INTERP, SELF, re);
625         SET_ATTR_im(INTERP, SELF, im);
626     }
628     VTABLE void set_pmc(PMC *value) {
629         if (VTABLE_isa(INTERP, value, CONST_STRING(INTERP, "Complex"))) {
630             FLOATVAL re, im;
631             GET_ATTR_re(INTERP, value, re);
632             GET_ATTR_im(INTERP, value, im);
633             SET_ATTR_re(INTERP, SELF, re);
634             SET_ATTR_im(INTERP, SELF, im);
635         }
636         else
637             VTABLE_set_string_native(INTERP, SELF, VTABLE_get_string(INTERP, value));
638     }
640     VTABLE void set_integer_native(INTVAL value) {
641         SELF.set_number_native((FLOATVAL)value);
642     }
644     VTABLE void set_number_native(FLOATVAL value) {
645         SET_ATTR_re(INTERP, SELF, value);
646         SET_ATTR_im(INTERP, SELF, 0.0);
647     }
651 =item C<void set_integer_keyed(PMC *key, INTVAL value)>
653 =item C<void set_integer_keyed_str(STRING *key, INTVAL value)>
655 =item C<void set_number_keyed(PMC *key, FLOATVAL value)>
657 =item C<void set_number_keyed_str(STRING *key, FLOATVAL value)>
659 =item C<void set_pmc_keyed(PMC *key, PMC *value)>
661 =item C<void set_pmc_keyed_str(STRING *key, PMC *value)>
663 Sets the requested number (real part for C<real> and imaginary for C<imag>)
664 to C<value>.
666 =cut
670     VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
671         SELF.set_number_keyed(key, (FLOATVAL)value);
672     }
674     VTABLE void set_integer_keyed_str(STRING *key, INTVAL value) {
675         SELF.set_number_keyed_str(key, (FLOATVAL)value);
676     }
678     VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
679         if (VTABLE_isa(INTERP, key, CONST_STRING(INTERP, "Integer"))) {
680             const INTVAL i = VTABLE_get_integer(INTERP, key);
681             SELF.set_number_keyed_int(i, value);
682         }
683         else {
684             STRING *s = VTABLE_get_string(INTERP, key);
685             SELF.set_number_keyed_str(s, value);
686         }
687     }
689     VTABLE void set_number_keyed_str(STRING *key, FLOATVAL value) {
690         if (Parrot_str_equal(INTERP, key, CONST_STRING(INTERP, "real"))) {
691             SET_ATTR_re(INTERP, SELF, value);
692         }
693         else if (Parrot_str_equal(INTERP, key, CONST_STRING(INTERP, "imag"))) {
694             SET_ATTR_im(INTERP, SELF, value);
695         }
696         else
697             Parrot_ex_throw_from_c_args(INTERP, NULL,
698                 EXCEPTION_INVALID_OPERATION, "Complex: key is neither 'real' or 'imag'");
699     }
701     VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
702         const FLOATVAL f = VTABLE_get_number(INTERP, value);
703         SELF.set_number_keyed(key, f);
704     }
706     VTABLE void set_pmc_keyed_str(STRING *key, PMC *value) {
707         const FLOATVAL f = VTABLE_get_number(INTERP, value);
708         SELF.set_number_keyed_str(key, f);
709     }
713 =item C<PMC *add(PMC *value, PMC *dest)>
715 =item C<PMC *add_int(INTVAL value, PMC *dest)>
717 =item C<PMC *add_float(FLOATVAL value, PMC *dest)>
719 Adds C<value> to the complex number, placing the result in C<dest>.
721 =cut
725     MULTI PMC *add(Complex value, PMC *dest) {
726         FLOATVAL self_re, self_im, val_re, val_im;
727         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
729         GET_ATTR_re(INTERP, SELF, self_re);
730         GET_ATTR_im(INTERP, SELF, self_im);
732         GET_ATTR_re(INTERP, value, val_re);
733         GET_ATTR_im(INTERP, value, val_im);
735         SET_ATTR_re(INTERP, dest, self_re + val_re);
736         SET_ATTR_im(INTERP, dest, self_im + val_im);
738         return dest;
739     }
741     MULTI PMC *add(DEFAULT value, PMC *dest) {
742         FLOATVAL re, im;
743         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
745         GET_ATTR_re(INTERP, SELF, re);
746         GET_ATTR_im(INTERP, SELF, im);
747         SET_ATTR_re(INTERP, dest, re + VTABLE_get_number(INTERP, value));
748         SET_ATTR_im(INTERP, dest, im);
750         return dest;
751     }
753     VTABLE PMC *add_int(INTVAL value, PMC *dest) {
754         return SELF.add_float((FLOATVAL)value, dest);
755     }
757     VTABLE PMC *add_float(FLOATVAL value, PMC *dest) {
758         FLOATVAL re, im;
759         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
761         GET_ATTR_re(INTERP, SELF, re);
762         GET_ATTR_im(INTERP, SELF, im);
763         SET_ATTR_re(INTERP, dest, re + value);
764         SET_ATTR_im(INTERP, dest, im);
766         return dest;
767     }
769     MULTI void i_add(Complex value) {
770         FLOATVAL self_re, self_im, val_re, val_im;
772         GET_ATTR_re(INTERP, SELF, self_re);
773         GET_ATTR_im(INTERP, SELF, self_im);
775         GET_ATTR_re(INTERP, value, val_re);
776         GET_ATTR_im(INTERP, value, val_im);
778         SET_ATTR_re(INTERP, SELF, self_re + val_re);
779         SET_ATTR_im(INTERP, SELF, self_im + val_im);
780     }
782     MULTI void i_add(DEFAULT value) {
783         FLOATVAL re;
785         GET_ATTR_re(INTERP, SELF, re);
786         SET_ATTR_re(INTERP, SELF, re + VTABLE_get_number(INTERP, value));
787     }
789     VTABLE void i_add_int(INTVAL value) {
790         SELF.i_add_float((FLOATVAL)value);
791     }
793     VTABLE void i_add_float(FLOATVAL value) {
794         FLOATVAL re;
796         GET_ATTR_re(INTERP, SELF, re);
797         SET_ATTR_re(INTERP, SELF, re + value);
798     }
802 =item C<PMC *subtract(PMC *value, PMC *dest)>
804 =item C<PMC *subtract_int(INTVAL value, PMC *dest)>
806 =item C<PMC *subtract_float(FLOATVAL value, PMC *dest)>
808 Subtracts C<value> from the complex number, placing the result in C<dest>.
810 =cut
814     MULTI PMC *subtract(Complex value, PMC *dest) {
815         FLOATVAL self_re, self_im, val_re, val_im;
816         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
818         GET_ATTR_re(INTERP, SELF, self_re);
819         GET_ATTR_im(INTERP, SELF, self_im);
821         GET_ATTR_re(INTERP, value, val_re);
822         GET_ATTR_im(INTERP, value, val_im);
824         SET_ATTR_re(INTERP, dest, self_re - val_re);
825         SET_ATTR_im(INTERP, dest, self_im - val_im);
827         return dest;
828     }
830     MULTI PMC *subtract(DEFAULT value, PMC *dest) {
831         FLOATVAL re, im;
832         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
834         GET_ATTR_re(INTERP, SELF, re);
835         GET_ATTR_im(INTERP, SELF, im);
836         SET_ATTR_re(INTERP, dest, re - VTABLE_get_number(INTERP, value));
837         SET_ATTR_im(INTERP, dest, im);
839         return dest;
840     }
842     VTABLE PMC *subtract_int(INTVAL value, PMC *dest) {
843         return SELF.subtract_float((FLOATVAL)value, dest);
844     }
846     VTABLE PMC *subtract_float(FLOATVAL value, PMC *dest) {
847         FLOATVAL re, im;
848         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
850         GET_ATTR_re(INTERP, SELF, re);
851         GET_ATTR_im(INTERP, SELF, im);
852         SET_ATTR_re(INTERP, dest, re - value);
853         SET_ATTR_im(INTERP, dest, im);
855         return dest;
856     }
858     MULTI void i_subtract(Complex value) {
859         FLOATVAL self_re, self_im, val_re, val_im;
861         GET_ATTR_re(INTERP, SELF, self_re);
862         GET_ATTR_im(INTERP, SELF, self_im);
864         GET_ATTR_re(INTERP, value, val_re);
865         GET_ATTR_im(INTERP, value, val_im);
867         SET_ATTR_re(INTERP, SELF, self_re - val_re);
868         SET_ATTR_im(INTERP, SELF, self_im - val_im);
869     }
871     MULTI void i_subtract(DEFAULT value) {
872         FLOATVAL re;
874         GET_ATTR_re(INTERP, SELF, re);
875         SET_ATTR_re(INTERP, SELF, re - VTABLE_get_number(INTERP, value));
876     }
878     VTABLE void i_subtract_int(INTVAL value) {
879         SELF.i_subtract_float((FLOATVAL) value);
880     }
882     VTABLE void i_subtract_float(FLOATVAL value) {
883         FLOATVAL re;
885         GET_ATTR_re(INTERP, SELF, re);
886         SET_ATTR_re(INTERP, SELF, re - value);
887     }
890 =item C<PMC *multiply(PMC *value, PMC *dest)>
892 =item C<PMC *multiply_int(INTVAL value, PMC *dest)>
894 =item C<PMC *multiply_float(FLOATVAL value, PMC *dest)>
896 Multiplies the complex number with C<value>, placing the result in C<dest>.
898 =item C<void i_multiply(PMC *value)>
900 =item C<void i_multiply_int(INTVAL value)>
902 =item C<void i_multiply_float(FLOATVAL value)>
904 Multiplies the complex number SELF inplace with C<value>.
906 =cut
912   (a+ib)(c+id)=(ac-bd)+i((a+b)(c+d)-ac-bd).
913   (a+bi)(c+di)=(ac-bd)+i(ad+bc)
916     MULTI PMC *multiply(Complex value, PMC *dest) {
917         FLOATVAL a, b, c, d;
919         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
921         GET_ATTR_re(INTERP, SELF, a);
922         GET_ATTR_im(INTERP, SELF, b);
923         GET_ATTR_re(INTERP, value, c);
924         GET_ATTR_im(INTERP, value, d);
925         SET_ATTR_re(INTERP, dest, a * c - b * d);
926         SET_ATTR_im(INTERP, dest, a * d + b * c);
928         return dest;
929     }
931     MULTI PMC *multiply(DEFAULT value, PMC *dest) {
932         FLOATVAL re, im;
933         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
935         GET_ATTR_re(INTERP, SELF, re);
936         GET_ATTR_im(INTERP, SELF, im);
937         SET_ATTR_re(INTERP, dest, re * VTABLE_get_number(INTERP, value));
938         SET_ATTR_im(INTERP, dest, im * VTABLE_get_number(INTERP, value));
940         return dest;
941     }
943     VTABLE PMC *multiply_int(INTVAL value, PMC *dest) {
944         return SELF.multiply_float((FLOATVAL) value, dest);
945     }
947     VTABLE PMC *multiply_float(FLOATVAL value, PMC *dest) {
948         FLOATVAL re, im;
949         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
951         GET_ATTR_re(INTERP, SELF, re);
952         GET_ATTR_im(INTERP, SELF, im);
953         SET_ATTR_re(INTERP, dest, re * value);
954         SET_ATTR_im(INTERP, dest, im * value);
956         return dest;
957     }
959     MULTI void i_multiply(Complex value) {
960         FLOATVAL a, b, c, d;
962         GET_ATTR_re(INTERP, SELF, a);
963         GET_ATTR_im(INTERP, SELF, b);
964         GET_ATTR_re(INTERP, value, c);
965         GET_ATTR_im(INTERP, value, d);
966         SET_ATTR_re(INTERP, SELF, a * c - b * d);
967         SET_ATTR_im(INTERP, SELF, a * d + b * c);
968     }
970     MULTI void i_multiply(DEFAULT value) {
971         FLOATVAL re, im;
973         GET_ATTR_re(INTERP, SELF, re);
974         GET_ATTR_im(INTERP, SELF, im);
975         SET_ATTR_re(INTERP, SELF, re * VTABLE_get_number(INTERP, value));
976         SET_ATTR_im(INTERP, SELF, im * VTABLE_get_number(INTERP, value));
977     }
979     VTABLE void i_multiply_int(INTVAL value) {
980         FLOATVAL re, im;
982         GET_ATTR_re(INTERP, SELF, re);
983         GET_ATTR_im(INTERP, SELF, im);
984         SET_ATTR_re(INTERP, SELF, re * value);
985         SET_ATTR_im(INTERP, SELF, im * value);
986     }
988     VTABLE void i_multiply_float(FLOATVAL value) {
989         FLOATVAL re, im;
991         GET_ATTR_re(INTERP, SELF, re);
992         GET_ATTR_im(INTERP, SELF, im);
993         SET_ATTR_re(INTERP, SELF, re * value);
994         SET_ATTR_im(INTERP, SELF, im * value);
995     }
999 =item C<PMC *divide(PMC *value, PMC *dest)>
1001 =item C<PMC *divide_int(INTVAL value, PMC *dest)>
1003 =item C<PMC *divide_float(FLOATVAL value, PMC *dest)>
1005 Divide the complex number by C<value>, placing the result in C<dest>.
1007 =item C<void i_divide(PMC *value, PMC *dest)>
1009 =item C<void i_divide_int(INTVAL value, PMC *dest)>
1011 =item C<void i_divide_float(FLOATVAL value, PMC *dest)>
1013 Divide the complex number C<SELF> by C<value> inplace.
1015 Throws divide by zero exception if divisor is zero.
1017 =cut
1019 TODO: for better fp precision
1020 http://docs.sun.com/source/806-3568/ncg_goldberg.html
1021 (a+ib)/(c+id) =
1022     (a + b(d/c)) / (c + d(d/c)) + i(b - a(d/c)) / (c + d(d/c)) if |d|<|c|
1023     (b + a(c/d)) / (d + c(c/d)) + i(-a + b(c/d)) / (d + c(c/d)) if |d|>=|c|
1027     MULTI PMC *divide(Complex value, PMC *dest) {
1028         FLOATVAL mod, re, im;
1029         FLOATVAL self_re, self_im, val_re, val_im;
1031         complex_check_divide_zero(INTERP, value);
1032         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1034         GET_ATTR_re(INTERP, SELF, self_re);
1035         GET_ATTR_im(INTERP, SELF, self_im);
1036         GET_ATTR_re(INTERP, value, val_re);
1037         GET_ATTR_im(INTERP, value, val_im);
1039         /* a little speed optimisation: cache an intermediate number;
1040             I'm not sure the compiler does this */
1042         if (self_im == 0.0 && val_im == 0.0) {
1043             re = self_re / val_re;
1044             im = 0.0;
1045         }
1046         else {
1047             mod = (val_re * val_re + val_im * val_im);
1048             re  = (self_re * val_re + self_im * val_im) / mod;
1049             im  = (self_im * val_re - self_re * val_im) / mod;
1050         }
1052         SET_ATTR_re(INTERP, dest, re);
1053         SET_ATTR_im(INTERP, dest, im);
1055         return dest;
1056     }
1058     MULTI PMC *divide(DEFAULT value, PMC *dest) {
1059         FLOATVAL re, im;
1060         const FLOATVAL d = VTABLE_get_number(INTERP, value);
1061         float_check_divide_zero(INTERP, d);
1062         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1064         GET_ATTR_re(INTERP, SELF, re);
1065         GET_ATTR_im(INTERP, SELF, im);
1067         SET_ATTR_re(INTERP, dest, re / d);
1068         SET_ATTR_im(INTERP, dest, im / d);
1070         return dest;
1071     }
1073     VTABLE PMC *divide_int(INTVAL value, PMC *dest) {
1074         FLOATVAL re, im;
1075         int_check_divide_zero(INTERP, value);
1076         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1078         GET_ATTR_re(INTERP, SELF, re);
1079         GET_ATTR_im(INTERP, SELF, im);
1081         SET_ATTR_re(INTERP, dest, re / value);
1082         SET_ATTR_im(INTERP, dest, im / value);
1084         return dest;
1085     }
1087     VTABLE PMC *divide_float(FLOATVAL value, PMC *dest) {
1088         FLOATVAL re, im;
1089         float_check_divide_zero(INTERP, value);
1090         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1092         GET_ATTR_re(INTERP, SELF, re);
1093         GET_ATTR_im(INTERP, SELF, im);
1095         SET_ATTR_re(INTERP, dest, re / value);
1096         SET_ATTR_im(INTERP, dest, im / value);
1098         return dest;
1099     }
1101     MULTI void i_divide(Complex value) {
1102         FLOATVAL re, im;
1103         FLOATVAL self_re, self_im, val_re, val_im;
1105         complex_check_divide_zero(INTERP, value);
1107         GET_ATTR_re(INTERP, SELF, self_re);
1108         GET_ATTR_im(INTERP, SELF, self_im);
1109         GET_ATTR_re(INTERP, value, val_re);
1110         GET_ATTR_im(INTERP, value, val_im);
1112         if (self_im == 0.0 && val_im == 0.0) {
1113             re = self_re / val_re;
1114             im = 0.0;
1115         }
1116         else {
1117             /* a little speed optimisation: cache an intermediate number;
1118                I'm not sure the compiler does this */
1119             const FLOATVAL mod = (val_re * val_re + val_im * val_im);
1120             re  = (self_re * val_re + self_im * val_im) / mod;
1121             im  = (self_im * val_re - self_re * val_im) / mod;
1122         }
1124         SET_ATTR_re(INTERP, SELF, re);
1125         SET_ATTR_im(INTERP, SELF, im);
1127     }
1129     MULTI void i_divide(DEFAULT value) {
1130         FLOATVAL re, im;
1131         const FLOATVAL d = VTABLE_get_number(INTERP, value);
1132         float_check_divide_zero(INTERP, d);
1134         GET_ATTR_re(INTERP, SELF, re);
1135         GET_ATTR_im(INTERP, SELF, im);
1137         SET_ATTR_re(INTERP, SELF, re / d);
1138         SET_ATTR_im(INTERP, SELF, im / d);
1139     }
1141     VTABLE void i_divide_int(INTVAL value) {
1142         FLOATVAL re, im;
1143         int_check_divide_zero(INTERP, value);
1145         GET_ATTR_re(INTERP, SELF, re);
1146         GET_ATTR_im(INTERP, SELF, im);
1148         SET_ATTR_re(INTERP, SELF, re / value);
1149         SET_ATTR_im(INTERP, SELF, im / value);
1150     }
1152     VTABLE void i_divide_float(FLOATVAL value) {
1153         FLOATVAL re, im;
1154         float_check_divide_zero(INTERP, value);
1156         GET_ATTR_re(INTERP, SELF, re);
1157         GET_ATTR_im(INTERP, SELF, im);
1159         SET_ATTR_re(INTERP, SELF, re / value);
1160         SET_ATTR_im(INTERP, SELF, im / value);
1161     }
1165 =item C<PMC *neg(PMC *dest)>
1167 =item C<void neg()>
1169 Set C<dest> to the negated value of C<SELF>.
1171 =cut
1175     VTABLE PMC *neg(PMC *dest) {
1176         FLOATVAL re, im;
1177         dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1179         GET_ATTR_re(INTERP, SELF, re);
1180         GET_ATTR_im(INTERP, SELF, im);
1182         SET_ATTR_re(INTERP, dest, -re);
1183         SET_ATTR_im(INTERP, dest, -im);
1185         return dest;
1186     }
1188     VTABLE void i_neg() {
1189         FLOATVAL re, im;
1190         GET_ATTR_re(INTERP, SELF, re);
1191         GET_ATTR_im(INTERP, SELF, im);
1192         SET_ATTR_re(INTERP, SELF, -re);
1193         SET_ATTR_im(INTERP, SELF, -im);
1194     }
1198 =item C<INTVAL is_equal(PMC *value)>
1200 Compares the complex number with C<value> and returns true if they are equal.
1202 =cut
1206     MULTI INTVAL is_equal(Complex value) {
1207         FLOATVAL self_re, self_im, val_re, val_im;
1208         GET_ATTR_re(INTERP, SELF, self_re);
1209         GET_ATTR_im(INTERP, SELF, self_im);
1210         GET_ATTR_re(INTERP, value, val_re);
1211         GET_ATTR_im(INTERP, value, val_im);
1212         return (INTVAL)(self_re == val_re && self_im == val_im);
1213     }
1215     MULTI INTVAL is_equal(DEFAULT value) {
1216         FLOATVAL re, im;
1217         GET_ATTR_re(INTERP, SELF, re);
1218         GET_ATTR_im(INTERP, SELF, im);
1220         if (im != 0.0)
1221             return (INTVAL)0;
1223         return (re == VTABLE_get_number(INTERP, value));
1224     }
1228 =item C<PMC *absolute(PMC *dest)>
1230 =item C<void i_absolute()>
1232 Sets C<dest> to the absolute value of SELF that is the distance from (0.0).
1234 =cut
1240   TODO for better precision: hinted by vaxman according to "Numerical Recipes
1241   in Fortran 77", 2nd edition, Press, Vetterling, Teukolsky, Flannery,
1242   Cambridge University Press, 2001, pp. 171ff:
1245 |a+ib|=|a|*sqrt(1+(b/a)**2), if |a|>=|b|,
1246        |b|*sqrt(1+(a/b)**2)  else.
1250     VTABLE PMC *absolute(PMC *dest) {
1251         FLOATVAL re, im, d;
1252         GET_ATTR_re(INTERP, SELF, re);
1253         GET_ATTR_im(INTERP, SELF, im);
1254         d = sqrt(re*re + im*im);
1256         dest = Parrot_pmc_new(INTERP,
1257             Parrot_get_ctx_HLL_type(INTERP, enum_class_Float));
1259         VTABLE_set_number_native(INTERP, dest, d);
1260         return dest;
1261     }
1263     VTABLE void i_absolute() {
1264         FLOATVAL re, im, d;
1265         GET_ATTR_re(INTERP, SELF, re);
1266         GET_ATTR_im(INTERP, SELF, im);
1267         d = sqrt(re*re + im*im);
1268         Parrot_pmc_reuse(INTERP, SELF, enum_class_Float, 0);
1269         VTABLE_set_number_native(INTERP, SELF, d);
1270     }
1274 =item C<METHOD ln()>
1276 Returns the natural logarithm of SELF as a PMC.
1278 =cut
1280 ln z = ln |z| + i arg(z)
1281 |x + iy| = sqrt(x^2 + y^2)
1282 arg(x + iy) = atan2(y, x)
1284 Some special cases
1285 ln(-1) = pi i
1286 ln(0) = -inf
1287 ln(1) = 0
1288 ln(e) = 1
1289 ln(+-i) = +- (pi i)/2
1293     METHOD ln() {
1294         PMC * const d  = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1295         FLOATVAL re, im, result_re, result_im;
1296         GET_ATTR_re(INTERP, SELF, re);
1297         GET_ATTR_im(INTERP, SELF, im);
1299         /* This is necessary for atan2 to behave */
1300         if (im == -0.0)
1301             im = 0.0;
1303         result_re = log(sqrt(re*re + im*im));
1304         if (re == 0.0 && im == 0.0) /* atan2(0, 0) not portable */
1305             result_im = 0.0;
1306         else
1307             result_im = atan2(im, re);
1309         SET_ATTR_re(INTERP, d, result_re);
1310         SET_ATTR_im(INTERP, d, result_im);
1312         RETURN(PMC *d);
1313     }
1317 =item C<METHOD exp()>
1319 Returns e ^ SELF as a PMC.
1321 =cut
1323 exp(a + bi) = exp(a) * (cos(b) + i * sin(b))
1327     METHOD exp() {
1328         PMC * const d  = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1329         FLOATVAL re, im, f;
1330         GET_ATTR_re(INTERP, SELF, re);
1331         GET_ATTR_im(INTERP, SELF, im);
1333         f  = exp(re);
1335         SET_ATTR_re(INTERP, d, f * cos(im));
1337         /* If only sin(pi) worked. */
1338         if (im == 4.0 * atan(1.0)) {
1339             SET_ATTR_im(INTERP, d, 0.0);
1340         }
1341         else {
1342             SET_ATTR_im(INTERP, d, f * sin(im));
1343         }
1345         RETURN(PMC *d);
1346     }
1350 =item C<METHOD PMC *sin()>
1352 =item C<METHOD PMC *cos()>
1354 =item C<METHOD PMC *tan()>
1356 =item C<METHOD PMC *csc()>
1358 =item C<METHOD PMC *sec()>
1360 =item C<METHOD PMC *cot()>
1362 Returns C<FUNC>(SELF).
1364 =cut
1366  => sin(a + bi) = sin(a)cosh(b)+i*cos(a)sinh(b)
1367     sin(z) = ((e ^ zi) - (e ^ -zi)) / (2i)
1368  => cos(a + bi) = cos(a) * cosh(b) - i * sin(a) * sinh(b)
1369     cos(z) = ((e ^ zi) + (e ^ -zi)) / 2
1371     sin(iz) = i sinh(z)
1372     cos(iz) = cosh(z)
1374     sinh(iz) = i sin(z)
1375     cosh(iz) = cos z
1376     sinh(a + bi) = sinh(a) * cos(b) + i * cosh(a) * sin(b)
1377     cosh(a + bi) = cosh(a) * cos(b) + i * sinh(a) * sin(b)
1381     METHOD sin() {
1382         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1383         FLOATVAL re, im, result_re, result_im;
1384         GET_ATTR_re(INTERP, SELF, re);
1385         GET_ATTR_im(INTERP, SELF, im);
1387         if (FLOAT_IS_ZERO(im)) {
1388             result_re = sin(re);
1389             result_im = 0.0;
1390         }
1391         else if (FLOAT_IS_ZERO(re)) {
1392             result_re = 0.0;
1393             result_im = sinh(im);
1394         }
1395         else {
1396             result_re = sin(re) * cosh(im);
1398             if (im == -0.0)
1399                 result_im = 0.0;
1400             else
1401                 result_im = cos(re) * sinh(im);
1403         }
1405         SET_ATTR_re(INTERP, d, result_re);
1406         SET_ATTR_im(INTERP, d, result_im);
1408         RETURN(PMC *d);
1409     }
1411     METHOD cos() {
1412         PMC * const d  = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1413         FLOATVAL re, im, result_re, result_im;
1414         GET_ATTR_re(INTERP, SELF, re);
1415         GET_ATTR_im(INTERP, SELF, im);
1417         if (FLOAT_IS_ZERO(re)) {
1418             result_re = cosh(im);
1419             result_im = 0.0;
1420         }
1421         else if (FLOAT_IS_ZERO(im)) {
1422             result_re = cos(re);
1423             result_im = 0.0;
1424         }
1425         else {
1426             result_re = cos(re) * cosh(im);
1427             result_im = -1.0 * sin(re) * sinh(im);
1428         }
1430         SET_ATTR_re(INTERP, d, result_re);
1431         SET_ATTR_im(INTERP, d, result_im);
1433         RETURN(PMC *d);
1434     }
1436     METHOD tan() {
1437         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1438         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1440         (PMC *d) = PCCINVOKE(INTERP, SELF, "sin");
1441         (PMC *e) = PCCINVOKE(INTERP, SELF, "cos");
1443         Parrot_Complex_multi_i_divide_Complex(INTERP, d, e);
1445         RETURN(PMC *d);
1446     }
1448     METHOD cot() {
1449         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1450         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1451         (PMC *d) = PCCINVOKE(INTERP, SELF, "cos");
1452         (PMC *e) = PCCINVOKE(INTERP, SELF, "sin");
1454         Parrot_Complex_multi_i_divide_Complex(INTERP, d, e);
1456         RETURN(PMC *d);
1457     }
1459     METHOD sec() {
1460         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1461         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1462         SET_ATTR_re(INTERP, d, 1.0);
1463         SET_ATTR_im(INTERP, d, 0.0);
1464         (PMC *e) = PCCINVOKE(INTERP, SELF, "cos");
1466         Parrot_Complex_multi_i_divide_Complex(INTERP, d, e);
1468         RETURN(PMC *d);
1469     }
1471     METHOD csc() {
1472         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1473         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1475         SET_ATTR_re(INTERP, d, 1.0);
1476         SET_ATTR_im(INTERP, d, 0.0);
1478         (PMC *e) = PCCINVOKE(INTERP, SELF, "sin");
1480         Parrot_Complex_multi_i_divide_Complex(INTERP, d, e);
1482         RETURN(PMC *d);
1483     }
1487 =item C<METHOD PMC *asin()>
1489 =item C<METHOD PMC *acos()>
1491 =item C<METHOD PMC *atan()>
1493 =item C<METHOD PMC *acsc()>
1495 =item C<METHOD PMC *asec()>
1497 =item C<METHOD PMC *acot()>
1499 Returns the inverse function of SELF.
1501 =cut
1503  => arcsin z = -i ln(iz + sqrt(1-z*z))
1504  => arccos z = pi/2 + i * ln(iz + sqrt(1 - z*z))
1505     arccos z = -i ln(z + sqrt(z*z-1))
1506  => arctan z = i/2 ln((i+z) / (i-z))
1507     arctan z = 1/2 i (ln(1-iz) - ln(1 + iz))
1509  => acot(z) = atan(1 / z)
1510     acot(z) = i/2 (ln((z - i) / z) - ln((z + i) / z))
1511  => asec(z) = acos(1 / z)
1512     asec(z) = 1/2 pi + i ln(sqrt(1 - 1/zz) + i/z)
1513  => acsc(z) = asin(1 / z)
1514     acsc(z) = -i ln(sqrt(1 - 1/zz + i/z))
1518     METHOD asin() {
1519         FLOATVAL d_re, d_im, e_re, e_im, self_re, self_im;
1520         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1521         PMC *       e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1522         GET_ATTR_re(INTERP, SELF, self_re);
1523         GET_ATTR_im(INTERP, SELF, self_im);
1525         e      = Parrot_Complex_multi_multiply_Complex_PMC(INTERP, SELF, SELF, e);
1526         GET_ATTR_re(INTERP, e, e_re);
1527         GET_ATTR_im(INTERP, e, e_im);
1528         SET_ATTR_re(INTERP, e, 1.0 - e_re);
1529         SET_ATTR_im(INTERP, e, -e_im);
1531         (PMC *d) = PCCINVOKE(INTERP, e, "sqrt");
1532         GET_ATTR_re(INTERP, d, d_re);
1533         GET_ATTR_im(INTERP, d, d_im);
1534         SET_ATTR_re(INTERP, d, d_re - self_im);
1535         SET_ATTR_im(INTERP, d, d_im + self_re);
1537         (PMC *d) = PCCINVOKE(INTERP, d, "ln");
1538         GET_ATTR_re(INTERP, d, d_re);
1539         GET_ATTR_im(INTERP, d, d_im);
1540         SET_ATTR_re(INTERP, e, d_im);
1541         SET_ATTR_im(INTERP, e, d_re ? -d_re : 0.0);
1543         RETURN(PMC *e);
1544     }
1546     METHOD acos() {
1547         FLOATVAL d_re, d_im, e_re, e_im, self_re, self_im;
1548         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1549         PMC *       e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1550         GET_ATTR_re(INTERP, SELF, self_re);
1551         GET_ATTR_im(INTERP, SELF, self_im);
1553         e = Parrot_Complex_multi_multiply_Complex_PMC(INTERP, SELF, SELF, e);
1554         GET_ATTR_re(INTERP, e, e_re);
1555         GET_ATTR_im(INTERP, e, e_im);
1556         SET_ATTR_re(INTERP, e, 1.0 - e_re);
1557         SET_ATTR_im(INTERP, e, -e_im);
1559         (PMC *d) = PCCINVOKE(INTERP, e, "sqrt");
1560         GET_ATTR_re(INTERP, d, d_re);
1561         GET_ATTR_im(INTERP, d, d_im);
1562         SET_ATTR_re(INTERP, d, d_re + self_im);
1563         SET_ATTR_im(INTERP, d, d_im - self_re);
1565         (PMC *e) = PCCINVOKE(INTERP, d, "ln");
1566         GET_ATTR_re(INTERP, e, e_re);
1567         GET_ATTR_im(INTERP, e, e_im);
1568         SET_ATTR_re(INTERP, d, e_im + 2.0 * atan(1.0));
1569         SET_ATTR_im(INTERP, d, e_re ? -e_re : 0.0);
1571         RETURN(PMC *d);
1572     }
1574     METHOD atan() {
1575         PMC * const d  = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1576         PMC * const e  = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1577         FLOATVAL re, im, d_re, d_im;
1578         GET_ATTR_re(INTERP, SELF, re);
1579         GET_ATTR_im(INTERP, SELF, im);
1581         SET_ATTR_re(INTERP, d, re);
1582         SET_ATTR_im(INTERP, d, 1 + im);
1583         SET_ATTR_re(INTERP, e, -re);
1584         SET_ATTR_im(INTERP, e, 1 - im);
1586         Parrot_Complex_multi_i_divide_Complex(INTERP, d, e);
1588         (PMC *d) = PCCINVOKE(INTERP, d, "ln");
1589         GET_ATTR_re(INTERP, d, d_re);
1590         GET_ATTR_im(INTERP, d, d_im);
1592         SET_ATTR_re(INTERP, e, (d_im ? d_im : -0.0) / -2.0);
1593         SET_ATTR_im(INTERP, e, d_re / 2.0);
1595         RETURN(PMC *e);
1596     }
1598     METHOD acot() {
1599         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1600         PMC     *e;
1601         FLOATVAL re, im;
1602         GET_ATTR_re(INTERP, SELF, re);
1603         GET_ATTR_im(INTERP, SELF, im);
1605         SET_ATTR_re(INTERP, d,  re / (re * re + im * im));
1606         SET_ATTR_im(INTERP, d, -im / (re * re + im * im));
1608         (PMC *e) = PCCINVOKE(INTERP, d, "atan");
1609         RETURN(PMC *e);
1610     }
1612     METHOD acsc() {
1613         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1614         PMC     *e;
1615         FLOATVAL re, im;
1616         GET_ATTR_re(INTERP, SELF, re);
1617         GET_ATTR_im(INTERP, SELF, im);
1619         SET_ATTR_re(INTERP, d,  re / (re * re + im * im));
1620         SET_ATTR_im(INTERP, d, -im / (re * re + im * im));
1622         (PMC *e) = PCCINVOKE(INTERP, d, "asin");
1623         RETURN(PMC *e);
1624     }
1626     METHOD asec() {
1627         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1628         PMC     *e;
1629         FLOATVAL re, im;
1630         GET_ATTR_re(INTERP, SELF, re);
1631         GET_ATTR_im(INTERP, SELF, im);
1633         SET_ATTR_re(INTERP, d,  re / (re * re + im * im));
1634         SET_ATTR_im(INTERP, d, -im / (re * re + im * im));
1636         (PMC *e) = PCCINVOKE(INTERP, d, "acos");
1637         RETURN(PMC *e);
1638     }
1642 =item C<METHOD PMC *sinh()>
1644 Returns the arctangent of SELF.
1646 =item C<METHOD PMC *cosh()>
1648 Returns the arcsine of SELF.
1650 =item C<METHOD PMC *tanh()>
1652 Returns the arccosine of SELF.
1654 =cut
1656 tanh(z) = sinh(z) / cosh(z)
1660     METHOD sinh() {
1661         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1662         FLOATVAL re, im;
1663         GET_ATTR_re(INTERP, SELF, re);
1664         GET_ATTR_im(INTERP, SELF, im);
1666         SET_ATTR_re(INTERP, d, sinh(re) * cos(im));
1667         SET_ATTR_im(INTERP, d, im ? cosh(re) * sin(im) : 0.0);
1669         RETURN(PMC *d);
1670     }
1672     METHOD cosh() {
1673         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1674         FLOATVAL re, im;
1675         GET_ATTR_re(INTERP, SELF, re);
1676         GET_ATTR_im(INTERP, SELF, im);
1678         SET_ATTR_re(INTERP, d, cosh(re) * cos(im));
1679         if (re == 0.0 || im == 0.0) {
1680             SET_ATTR_im(INTERP, d, 0.0);
1681         }
1682         else {
1683             SET_ATTR_im(INTERP, d, sinh(re) * sin(im));
1684         }
1686         RETURN(PMC *d);
1687     }
1689     METHOD tanh() {
1690         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1691         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1693         (PMC *d) = PCCINVOKE(INTERP, SELF, "sinh");
1694         (PMC *e) = PCCINVOKE(INTERP, SELF, "cosh");
1696         Parrot_Complex_multi_i_divide_Complex(INTERP, d, e);
1698         RETURN(PMC *d);
1699     }
1701     METHOD coth() {
1702         FLOATVAL re, im;
1703         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1705         (PMC *d) = PCCINVOKE(INTERP, SELF, "tanh");
1706         GET_ATTR_re(INTERP, d, re);
1707         GET_ATTR_im(INTERP, d, im);
1709         SET_ATTR_re(INTERP, d, re ?  re / (re * re + im * im) : 0.0);
1710         SET_ATTR_im(INTERP, d, im ? -im / (re * re + im * im) : 0.0);
1712         RETURN(PMC *d);
1713     }
1715     METHOD csch() {
1716         FLOATVAL re, im;
1717         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1719         (PMC *d) = PCCINVOKE(INTERP, SELF, "sinh");
1720         GET_ATTR_re(INTERP, d, re);
1721         GET_ATTR_im(INTERP, d, im);
1723         SET_ATTR_re(INTERP, d, re ?  re / (re * re + im * im) : 0.0);
1724         SET_ATTR_im(INTERP, d, im ? -im / (re * re + im * im) : 0.0);
1726         RETURN(PMC *d);
1727     }
1729     METHOD sech() {
1730         FLOATVAL re, im;
1731         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1733         (PMC *d) = PCCINVOKE(INTERP, SELF, "cosh");
1734         GET_ATTR_re(INTERP, d, re);
1735         GET_ATTR_im(INTERP, d, im);
1737         SET_ATTR_re(INTERP, d, re ?  re / (re * re + im * im) : 0.0);
1738         SET_ATTR_im(INTERP, d, im ? -im / (re * re + im * im) : 0.0);
1740         RETURN(PMC *d);
1741     }
1745 =item C<METHOD PMC *asinh()>
1747 =item C<METHOD PMC *acosh()>
1749 =item C<METHOD PMC *atanh()>
1751 =item C<METHOD PMC *acsch()>
1753 =item C<METHOD PMC *asech()>
1755 =item C<METHOD PMC *acoth()>
1757 The inverse hyperbolic functions.  Currently all broken, but for
1758 C<func(a+bi) = c+di>, C<|c|> and C<|d|> will be correct, confusingly enough.
1760 =cut
1762 asinh z = -ln(sqrt(1+zz) - z)
1763 asinh z = ln(sqrt(zz + 1) + z)
1765 asinh = i asin(-ix)
1766 acosh = i acos(x)
1767 atanh = i atan(-ix)
1771     METHOD asinh() {
1772         FLOATVAL re, im;
1773         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1774         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1776         GET_ATTR_re(INTERP, SELF, re);
1777         GET_ATTR_im(INTERP, SELF, im);
1778         SET_ATTR_re(INTERP, d,  im);
1779         SET_ATTR_im(INTERP, d, -re);
1781         (PMC *d) = PCCINVOKE(INTERP, d, "asin");
1782         GET_ATTR_re(INTERP, d, re);
1783         GET_ATTR_im(INTERP, d, im);
1784         SET_ATTR_re(INTERP, e, -im);
1785         SET_ATTR_im(INTERP, e,  re);
1787         RETURN(PMC *e);
1788     }
1790     METHOD acosh() {
1791         FLOATVAL re, im;
1792         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1793         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1795         (PMC *d) = PCCINVOKE(INTERP, SELF, "acos");
1796         GET_ATTR_re(INTERP, d, re);
1797         GET_ATTR_im(INTERP, d, im);
1798         SET_ATTR_re(INTERP, e, -im);
1799         SET_ATTR_im(INTERP, e,  re);
1801         RETURN(PMC *e);
1802     }
1804     METHOD atanh() {
1805         FLOATVAL re, im;
1806         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1807         PMC * const e = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1809         GET_ATTR_re(INTERP, SELF, re);
1810         GET_ATTR_im(INTERP, SELF, im);
1811         SET_ATTR_re(INTERP, d,  im);
1812         SET_ATTR_im(INTERP, d, -re);
1814         (PMC *d) = PCCINVOKE(INTERP, d, "atan");
1815         GET_ATTR_re(INTERP, d, re);
1816         GET_ATTR_im(INTERP, d, im);
1817         SET_ATTR_re(INTERP, e, -im);
1818         SET_ATTR_im(INTERP, e,  re);
1820         RETURN(PMC *e);
1821     }
1823     METHOD acoth() {
1824         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1825         PMC     *e;
1826         FLOATVAL re, im;
1827         GET_ATTR_re(INTERP, SELF, re);
1828         GET_ATTR_im(INTERP, SELF, im);
1830         SET_ATTR_re(INTERP, d,  re / (re * re + im * im));
1831         SET_ATTR_im(INTERP, d, -im / (re * re + im * im));
1833         (PMC *e) = PCCINVOKE(INTERP, d, "atanh");
1834         RETURN(PMC *e);
1835     }
1837     METHOD acsch() {
1838         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1839         PMC     *e;
1840         FLOATVAL re, im;
1841         GET_ATTR_re(INTERP, SELF, re);
1842         GET_ATTR_im(INTERP, SELF, im);
1844         SET_ATTR_re(INTERP, d,  re / (re * re + im * im));
1845         SET_ATTR_im(INTERP, d, -im / (re * re + im * im));
1847         (PMC *e) = PCCINVOKE(INTERP, d, "asinh");
1848         RETURN(PMC *e);
1849     }
1851     METHOD asech() {
1852         PMC * const d = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1853         PMC     *e;
1854         FLOATVAL re, im;
1855         GET_ATTR_re(INTERP, SELF, re);
1856         GET_ATTR_im(INTERP, SELF, im);
1858         SET_ATTR_re(INTERP, d,  re / (re * re + im * im));
1859         SET_ATTR_im(INTERP, d, -im / (re * re + im * im));
1861         (PMC *e) = PCCINVOKE(INTERP, d, "acosh");
1862         RETURN(PMC *e);
1863     }
1867 =item C<METHOD PMC *pow(PMC *value)>
1869 Raise SELF to the power of value. Replacement for the old pow() vtable, which
1870 was deleted.
1872 TODO: Requires testing
1874 =item C<METHOD PMC *sqrt()>
1876 Return the square root of SELF.
1878 =cut
1880 TODO: mmd in other pmc's to allow .Integer ^ .Complex, etc.
1881 and i_pow, and pow_(float|int), etc
1883 x ^ y = exp(y * ln x))
1887     METHOD pow(PMC * value) {
1888         PMC *l = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1889         PMC *log;
1890         PMC *dest = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1892         Parrot_pcc_invoke_method_from_c_args(INTERP, SELF, CONST_STRING(INTERP, "ln"),
1893                     "->P", &log);
1895         l = VTABLE_multiply(INTERP, log, value, l);
1897         Parrot_pcc_invoke_method_from_c_args(INTERP, l, CONST_STRING(INTERP, "exp"),
1898                     "->P", &dest);
1899         RETURN(PMC *dest);
1900     }
1902     METHOD sqrt() {
1903         PMC * const result = Parrot_pmc_new(INTERP, VTABLE_type(INTERP, SELF));
1904         const FLOATVAL absval = SELF.get_number();
1905         FLOATVAL sx, sy, rx, ry;
1906         GET_ATTR_re(INTERP, SELF, sx);
1907         GET_ATTR_im(INTERP, SELF, sy);
1909         rx = sqrt((absval + sx) / 2);
1910         ry = sqrt((absval - sx) / 2);
1911         if (sy < 0)
1912             ry = -ry;
1913         SET_ATTR_re(INTERP, result, rx);
1914         SET_ATTR_im(INTERP, result, ry);
1915         RETURN(PMC *result);
1916     }
1922 =back
1924 =cut
1929  * Local variables:
1930  *   c-file-style: "parrot"
1931  * End:
1932  * vim: expandtab shiftwidth=4:
1933  */