Tagging trunk at r29566 so that the revisionpm can later be synched to it.
[parrot.git] / src / ops / math.ops
blob607124b9aa80bd34a68fd817e623980590cbcf17
1 /*
2  * $Id$
3 ** math.ops
4 */
6 VERSION = PARROT_VERSION;
8 =head1 NAME
10 math.ops - Mathematical Operations
12 =cut
14 =head1 DESCRIPTION
16 Operations that perform some sort of mathematics, including both basic
17 math and transcendental functions.
19 The variants with a prepended B<n_> like <n_abs> generate a new target PMC.
20 If possible, they use the appropriate language type, specified with C<.HLL>.
22 =head2 General infix operations
24 These operations take an infix operation number and PMC arguments.
26 =over 4
28 =item B<infix>(inconst INT, invar PMC, in INT)
30 =item B<infix>(inconst INT, invar PMC, in NUM)
32 =item B<infix>(inconst INT, invar PMC, in STR)
34 =item B<infix>(inconst INT, invar PMC, invar PMC)
36 General inplace infix dispatch opcode. $1 is the MMD function number.
38 =item B<infix>(inconst INT, out PMC, invar PMC, in INT)
40 =item B<infix>(inconst INT, out PMC, invar PMC, in NUM)
42 =item B<infix>(inconst INT, out PMC, invar PMC, in STR)
44 =item B<infix>(inconst INT, out PMC, invar PMC, invar PMC)
46 General infix dispatch opcode. $1 is the MMD function number.
48 =item B<n_infix>(inconst INT, out PMC, invar PMC, in INT)
50 =item B<n_infix>(inconst INT, out PMC, invar PMC, in NUM)
52 =item B<n_infix>(inconst INT, out PMC, invar PMC, in STR)
54 =item B<n_infix>(inconst INT, out PMC, invar PMC, invar PMC)
56 General infix dispatch opcode. $1 is the MMD function number.
57 These opcodes return a new result PMC $2.
59 =cut
61 inline op infix(inconst INT, invar PMC, in INT) :base_core {
62   mmd_dispatch_v_pi(interp, $2, $3, $1);
65 inline op infix(inconst INT, invar PMC, in NUM) :base_core {
66   mmd_dispatch_v_pn(interp, $2, $3, $1);
69 inline op infix(inconst INT, invar PMC, in STR) :base_core {
70   mmd_dispatch_v_ps(interp, $2, $3, $1);
73 inline op infix(inconst INT, invar PMC, invar PMC) :base_core {
74   mmd_dispatch_v_pp(interp, $2, $3, $1);
77 inline op infix(inconst INT, out PMC, invar PMC, in INT) :base_core {
78   $2 = mmd_dispatch_p_pip(interp, $3, $4, $2, $1);
81 inline op infix(inconst INT, out PMC, invar PMC, in NUM) :base_core {
82   $2 = mmd_dispatch_p_pnp(interp, $3, $4, $2, $1);
85 inline op infix(inconst INT, out PMC, invar PMC, in STR) :base_core {
86   $2 = mmd_dispatch_p_psp(interp, $3, $4, $2, $1);
89 inline op infix(inconst INT, out PMC, invar PMC, invar PMC) :base_core {
90   $2 = mmd_dispatch_p_ppp(interp, $3, $4, $2, $1);
93 inline op n_infix(inconst INT, out PMC, invar PMC, in INT) :base_core {
94   $2 = mmd_dispatch_p_pip(interp, $3, $4, NULL, $1);
97 inline op n_infix(inconst INT, out PMC, invar PMC, in NUM) :base_core {
98   $2 = mmd_dispatch_p_pnp(interp, $3, $4, NULL, $1);
101 inline op n_infix(inconst INT, out PMC, invar PMC, in STR) :base_core {
102   $2 = mmd_dispatch_p_psp(interp, $3, $4, NULL, $1);
105 inline op n_infix(inconst INT, out PMC, invar PMC, invar PMC) :base_core {
106   $2 = mmd_dispatch_p_ppp(interp, $3, $4, NULL, $1);
108 ###############################################################################
110 =back
112 =head2 Arithmetic operations
114 These operations store the results of arithmetic on other registers and
115 constants into their destination register, $1.
117 =over 4
119 =cut
121 ########################################
123 =item B<abs>(inout INT)
125 =item B<abs>(inout NUM)
127 =item B<abs>(invar PMC)
129 Set $1 to its absolute value.
131 =item B<abs>(out INT, in INT)
133 =item B<abs>(out NUM, in NUM)
135 =item B<abs>(out PMC, invar PMC)
137 Set $1 to absolute value of $2.
139 =item B<n_abs>(out PMC, invar PMC)
141 Create new $1 as the absolute of $2.
143 =cut
145 inline op abs(inout INT) :base_core {
146   $1 = abs($1);
149 inline op abs(inout NUM) :base_core {
150   $1 = fabs($1);
153 inline op abs(out INT, in INT) :base_core {
154   if ($2 < 0)
155     $1 = - (INTVAL)$2;
156   else
157     $1 = (INTVAL)$2;
160 inline op abs(out NUM, in NUM) :base_core {
161   if ($2 < 0)
162     $1 = - (FLOATVAL)$2;
163   else
164     $1 = (FLOATVAL)$2;
167 inline op abs(invar PMC) :base_core {
168   VTABLE_i_absolute(interp, $1);
171 inline op abs(out PMC, invar PMC) :base_core {
172   $1 = VTABLE_absolute(interp, $2, $1);
175 inline op n_abs(out PMC, invar PMC) :base_core {
176   $1 = VTABLE_absolute(interp, $2, NULL);
179 ########################################
181 =item B<add>(inout INT, in INT)
183 =item B<add>(inout NUM, in NUM)
185 Increase $1 by the amount in $2.
187 =item B<add>(out INT, in INT, in INT)
189 =item B<add>(out NUM, in NUM, in NUM)
191 Set $1 to the sum of $2 and $3.
193 Please note that all PMC variants of all infix functions are handled
194 by the C<infix> and C<n_infix> opcodes. Thus there is no distinct implementation
195 of e.g. C<add_p_p_p>.
197 =cut
199 inline op add(inout INT, in INT) :base_core {
200   $1 += $2;
203 inline op add(inout NUM, in NUM) :base_core {
204   $1 += $2;
207 inline op add(out INT, in INT, in INT) :base_core {
208   $1 = $2 + $3;
211 inline op add(out NUM, in NUM, in NUM) :base_core {
212   $1 = $2 + $3;
215 ########################################
217 =item B<cmod>(out INT, in INT, in INT)
219 NOTE: This "uncorrected mod" algorithm uses the C language's built-in
220 mod operator (x % y), which is
222     ... the remainder when x is divided by y, and thus is zero
223     when y divides x exactly.
224     ...
225     The direction of truncation for / and the sign of the result
226     for % are machine-dependent for negative operands, as is the
227     action taken on overflow or underflow.
228                                                      -- [1], page 41
230 Also:
232     ... if the second operand is 0, the result is undefined.
233     Otherwise, it is always true that (a/b)*b + a%b is equal to z. If
234     both operands are non-negative, then the remainder is non-
235     negative and smaller than the divisor; if not, it is guaranteed
236     only that the absolute value of the remainder is smaller than
237     the absolute value of the divisor.
238                                                      -- [1], page 205
240 This op is provided for those who need it (such as speed-sensitive
241 applications with heavy use of mod, but using it only with positive
242 arguments), but a more mathematically useful mod based on ** floor(x/y)
243 and defined with y == 0 is provided by the mod op.
245   [1] Brian W. Kernighan and Dennis M. Ritchie, *The C Programming
246       Language*, Second Edition. Prentice Hall, 1988.
248 If the denominator is zero, a 'Divide by zero' exception is thrown.
250 =cut
252 inline op cmod(out INT, in INT, in INT) :base_core {
253   INTVAL den = $3;
254   if ($3 == 0)
255     real_exception(interp, NULL, E_ZeroDivisionError,
256                     "Divide by zero");
257   $1 = $2 % den;
260 ########################################
262 =item B<cmod>(out NUM, in NUM, in NUM)
264 NOTE: This "uncorrected mod" algorithm uses the built-in C math library's
265 fmod() function, which computes
267     ... the remainder of dividing x by y. The return value is
268     x - n * y, where n is the quotient of x / y, rounded towards
269     zero to an integer.
270                                 -- fmod() manpage on RedHat Linux 7.0
272 In addition, fmod() returns
274     the remainder, unless y is zero, when the function fails and
275     errno is set.
277 According to page 251 of [1], the result when y is zero is implementation-
278 defined.
280 This op is provided for those who need it, but a more mathematically
281 useful numeric mod based on floor(x/y) instead of truncate(x/y) and
282 defined with y == 0 is provided by the mod op.
284   [1] Brian W. Kernighan and Dennis M. Ritchie, *The C Programming
285       Language*, Second Edition. Prentice Hall, 1988.
287 If the denominator is zero, a 'Divide by zero' exception is thrown.
289 =cut
291 inline op cmod(out NUM, in NUM, in NUM) :base_core {
292   FLOATVAL den = $3;
293   if (FLOAT_IS_ZERO($3))
294     real_exception(interp, NULL, E_ZeroDivisionError,
295                     "Divide by zero");
296   $1 = fmod($2, den);
299 ########################################
301 =item B<dec>(inout INT)
303 =item B<dec>(inout NUM)
305 =item B<dec>(invar PMC)
307 Decrease $1 by one.
309 =cut
311 inline op dec(inout INT) :base_core {
312   $1--;
315 inline op dec(inout NUM) :base_core {
316   $1--;
319 inline op dec(invar PMC) :base_core {
320   VTABLE_decrement(interp, $1);
323 ########################################
325 =item B<div>(inout INT, in INT)
327 =item B<div>(inout NUM, in NUM)
329 Divide $1 by $2.
331 =item B<div>(out INT, in INT, in INT)
333 =item B<div>(out NUM, in NUM, in NUM)
335 Set $1 to the quotient of $2 divided by $3. In the case of INTVAL division, the
336 result is truncated (NOT rounded or floored).
337 If the denominator is zero, a 'Divide by zero' exception is thrown.
339 =cut
341 inline op div(inout INT, in INT) :base_core {
342   INTVAL den = $2;
343   if ($2 == 0)
344     real_exception(interp, NULL, E_ZeroDivisionError,
345                     "Divide by zero");
346   $1 /= den;
349 inline op div(inout NUM, in NUM) :base_core {
350   FLOATVAL den = $2;
351   if (FLOAT_IS_ZERO($2))
352     real_exception(interp, NULL, E_ZeroDivisionError,
353                     "Divide by zero");
354   $1 /= den;
357 inline op div(out INT, in INT, in INT) :base_core {
358   INTVAL den = $3;
359   if ($3 == 0)
360     real_exception(interp, NULL, E_ZeroDivisionError,
361                     "Divide by zero");
362   $1 = $2 / den;
365 inline op div(out NUM, in NUM, in NUM) :base_core {
366   FLOATVAL den = $3;
367   if (FLOAT_IS_ZERO($3))
368     real_exception(interp, NULL, E_ZeroDivisionError,
369                     "Divide by zero");
370   $1 = $2 / den;
373 =item B<fdiv>(inout INT, in INT)
375 =item B<fdiv>(inout NUM, in NUM)
377 Floor divide $1 by $2.
379 =item B<fdiv>(out INT, in INT, in INT)
381 =item B<fdiv>(out NUM, in NUM, in NUM)
383 Set $1 to the quotient of $2 divided by $3. The result is the floor()
384 of the division i.e. the next whole integer towards -inf.
385 If the denominator is zero, a 'Divide by zero' exception is thrown.
387 =cut
389 inline op fdiv(inout INT, in INT) :base_core {
390   INTVAL   den = $2;
391   FLOATVAL f;
393   if ($2 == 0)
394     real_exception(interp, NULL, E_ZeroDivisionError,
395                     "Divide by zero");
397   f  = floor($1 / den);
398   $1 = (INTVAL)f;
401 inline op fdiv(inout NUM, in NUM) :base_core {
402   FLOATVAL den = $2;
403   if (FLOAT_IS_ZERO($2))
404     real_exception(interp, NULL, E_ZeroDivisionError,
405                     "Divide by zero");
406   $1 = floor($1 / den);
409 inline op fdiv(out INT, in INT, in INT) :base_core {
410   INTVAL   den = $3;
411   FLOATVAL f;
413   if ($3 == 0)
414     real_exception(interp, NULL, E_ZeroDivisionError,
415                     "Divide by zero");
417   f  = floor($2 / den);
418   $1 = (INTVAL)f;
421 inline op fdiv(out NUM, in NUM, in NUM) :base_core {
422   FLOATVAL den = $3;
423   if (FLOAT_IS_ZERO($3))
424     real_exception(interp, NULL, E_ZeroDivisionError,
425                     "Divide by zero");
426   $1 = floor($2 / den);
429 ########################################
431 =item B<ceil>(inout NUM)
433 Set $1 to the smallest integral value greater than or equal to $1.
435 =item B<ceil>(out INT, in NUM)
437 =item B<ceil>(out NUM, in NUM)
439 Set $1 to the smallest integral value greater than or equal to $2.
441 =cut
443 inline op ceil(inout NUM) :base_core {
444   $1 = ceil($1);
447 inline op ceil(out INT, in NUM) :base_core {
448   FLOATVAL f = ceil($2);
449   $1         = (INTVAL)f;
452 inline op ceil(out NUM, in NUM) :base_core {
453   $1 = ceil($2);
456 ########################################
458 =item B<floor>(inout NUM)
460 Set $1 to the largest integral value less than or equal to $1.
462 =item B<floor>(out INT, in NUM)
464 =item B<floor>(out NUM, in NUM)
466 Set $1 to the largest integral value less than or equal to $2.
468 =cut
470 inline op floor(inout NUM) :base_core {
471   $1 = floor($1);
474 inline op floor(out INT, in NUM) :base_core {
475   FLOATVAL f = floor($2);
476   $1         = (INTVAL)f;
479 inline op floor(out NUM, in NUM) :base_core {
480   $1 = floor($2);
483 ########################################
485 =item B<inc>(inout INT)
487 =item B<inc>(inout NUM)
489 =item B<inc>(invar PMC)
491 Increase $1 by one.
493 =cut
495 inline op inc(inout INT) :base_core {
496   $1++;
499 inline op inc(inout NUM) :base_core {
500   $1++;
503 inline op inc(invar PMC) :base_core {
504   VTABLE_increment(interp, $1);
508 ########################################
510 =item B<mod>(out INT, in INT, in INT)
512 =item B<mod>(out NUM, in NUM, in NUM)
514 Sets $1 to the modulus of $2 and $3.
516 =item B<mod>(inout INT, in INT)
518 =item B<mod>(inout NUM, in NUM)
520 Sets $1 to the modulus of $1 and $2.
523 NOTE: This "corrected mod" algorithm is based on the C code on page 70
524 of [1]. Assuming correct behavior of the built-in mod operator (%) with
525 positive arguments, this algorithm implements a mathematically convenient
526 version of mod, defined thus:
528   x mod y = x - y * floor(x / y)
530 For more information on this definition of mod, see section 3.4 of [2],
531 pages 81-85.
533 References:
535   [1] Donald E. Knuth, *MMIXware: A RISC Computer for the Third
536       Millennium* Springer, 1999.
538   [2] Ronald L. Graham, Donald E. Knuth and Oren Patashnik, *Concrete
539       Mathematics*, Second Edition. Addison-Wesley, 1994.
541 =cut
543 op mod(inout INT, in INT) :base_core {
544   $1 = intval_mod($1, $2);
547 op mod(out INT, in INT, in INT) :base_core {
548   $1 = intval_mod($2, $3);
551 op mod(out NUM, in NUM, in NUM) :base_core {
552   $1 = floatval_mod($2, $3);
555 op mod(inout NUM, in NUM) :base_core {
556   $1 = floatval_mod($1, $2);
559 ########################################
561 =item B<mul>(inout INT, in INT)
563 =item B<mul>(inout NUM, in NUM)
565 Set $1 to the product of $1 and $2.
567 =item B<mul>(out INT, in INT, in INT)
569 =item B<mul>(out NUM, in NUM, in NUM)
571 Set $1 to the product of $2 and $3.
573 =cut
575 inline op mul(inout INT, in INT) :base_core {
576   $1 *= $2;
579 inline op mul(inout NUM, in NUM) :base_core {
580   $1 *= $2;
583 inline op mul(out INT, in INT, in INT) :base_core {
584   $1 = $2 * $3;
587 inline op mul(out NUM, in NUM, in NUM) :base_core {
588   $1 = $2 * $3;
591 ########################################
593 =item B<neg>(inout INT)
595 =item B<neg>(inout NUM)
597 =item B<neg>(invar PMC)
599 Set $1 to its negative.
601 =item B<neg>(out INT, in INT)
603 =item B<neg>(out NUM, in NUM)
605 =item B<neg>(out PMC, invar PMC)
607 Set $1 to the negative of $2.
609 =item B<n_neg>(out PMC, invar PMC)
611 Create $1 as the negative of $2.
613 =cut
615 inline op neg(inout INT) :base_core {
616   $1 = - $1;
619 inline op neg(inout NUM) :base_core {
620   $1 = - $1;
623 inline op neg(invar PMC) :base_core {
624   VTABLE_i_neg(interp, $1);
627 inline op neg(out INT, in INT) :base_core {
628   $1 = - $2;
631 inline op neg(out NUM, in NUM) :base_core {
632   $1 = - $2;
635 inline op neg(out PMC, invar PMC) :base_core {
636   $1 = VTABLE_neg(interp, $2, $1);
639 inline op n_neg(out PMC, invar PMC) :base_core {
640   $1 = VTABLE_neg(interp, $2, NULL);
643 ########################################
645 =item B<pow>(out NUM, in NUM, in NUM)
647 Set $1 to $2 raised to the power $3.
649 =cut
651 inline op pow(out NUM, in NUM, in NUM) :base_core {
652    $1 = pow((FLOATVAL)$2, (FLOATVAL)$3);
655 ########################################
657 =item B<sub>(inout INT, in INT)
659 =item B<sub>(inout NUM, in NUM)
661 Decrease $1 by the amount in $2.
663 =item B<sub>(out INT, in INT, in INT)
665 =item B<sub>(out NUM, in NUM, in NUM)
667 Set $1 to $2 minus $3.
669 =cut
671 inline op sub(inout INT, in INT) :base_core {
672   $1 -= $2;
675 inline op sub(inout NUM, in NUM) :base_core {
676   $1 -= $2;
679 inline op sub(out INT, in INT, in INT) :base_core {
680   $1 = $2 - $3;
683 inline op sub(out NUM, in NUM, in NUM) :base_core {
684   $1 = $2 - $3;
687 ########################################
689 =item B<sqrt>(out NUM, in NUM)
691 Set $1 to the square root of $2.
693 =cut
695 inline op sqrt(out NUM, in NUM) :base_core {
696   $1 = sqrt((FLOATVAL)$2);
699 =back
701 =cut
705 ###############################################################################
707 =head2 Transcendental mathematical operations
709 These operations perform various transcendental operations such as logarithmics
710 and trigonometrics.
712 =over 4
714 =cut
716 ########################################
718 =item B<acos>(out NUM, in NUM)
720 Set $1 to the arc cosine (in radians) of $2.
722 =cut
724 inline op acos(out NUM, in NUM) :base_math {
725   $1 = acos((FLOATVAL)$2);
728 ########################################
730 =item B<asec>(out NUM, in NUM)
732 Set $1 to the arc secant (in radians) of $2.
734 =cut
736 inline op asec(out NUM, in NUM) :base_math {
737   $1 = acos(((FLOATVAL)1) / ((FLOATVAL)$2));
740 ########################################
743 =item B<asin>(out NUM, in NUM)
745 Set $1 to the arc sine (in radians) of $2.
747 =cut
749 inline op asin(out NUM, in NUM) :base_math {
750   $1 = asin((FLOATVAL)$2);
753 ########################################
755 =item B<atan>(out NUM, in NUM)
757 =item B<atan>(out NUM, in NUM, in NUM)
759 The two-argument versions set $1 to the arc tangent (in radians) of $2.
761 The three-argument versions set $1 to the arc tangent (in radians) of
762 $2 / $3, taking account of the signs of the arguments in determining the
763 quadrant of the result.
765 =cut
767 inline op atan(out NUM, in NUM) :base_math {
768   $1 = atan((FLOATVAL)$2);
771 inline op atan(out NUM, in NUM, in NUM) :base_math {
772   $1 = atan2((FLOATVAL)$2, (FLOATVAL)$3);
775 ########################################
777 =item B<cos>(out NUM, in NUM)
779 Set $1 to the cosine of $2 (given in radians).
781 =cut
783 inline op cos(out NUM, in NUM) :base_math {
784   $1 = cos((FLOATVAL)$2);
787 ########################################
789 =item B<cosh>(out NUM, in NUM)
791 Set $1 to the hyperbolic cosine of $2 (given in radians).
793 =cut
795 inline op cosh(out NUM, in NUM) :base_math {
796   $1 = cosh((FLOATVAL)$2);
799 ########################################
801 =item B<exp>(out NUM, in NUM)
803 Set $1 to I<e> raised to the power $2. I<e> is the base of the natural
804 logarithm.
806 =cut
808 inline op exp(out NUM, in NUM) :base_math {
809   $1 = exp((FLOATVAL)$2);
812 ########################################
814 =item B<ln>(out NUM, in NUM)
816 Set $1 to the natural (base I<e>) logarithm of $2.
818 =cut
820 inline op ln(out NUM, in NUM) :base_math {
821   $1 = log((FLOATVAL)$2);
824 ########################################
826 =item B<log10>(out NUM, in NUM)
828 Set $1 to the base 10 logarithm of $2.
830 =cut
832 inline op log10(out NUM, in NUM) :base_math {
833   $1 = log10((FLOATVAL)$2);
836 ########################################
838 =item B<log2>(out NUM, in NUM)
840 Set $1 to the base 2 logarithm of $2.
842 =cut
844 op log2(out NUM, in NUM) :base_math {
845    FLOATVAL temp = log((FLOATVAL)2.0);
846   $1 = log((FLOATVAL)$2) / temp;
849 ########################################
851 =item B<sec>(out NUM, in NUM)
853 Set $1 to the secant of $2 (given in radians).
855 =cut
857 inline op sec(out NUM, in NUM) :base_math {
858   $1 = ((FLOATVAL)1) / cos((FLOATVAL)$2);
861 ########################################
863 =item B<sech>(out NUM, in NUM)
865 Set $1 to the hyperbolic secant of $2 (given in radians).
867 =cut
869 inline op sech(out NUM, in NUM) :base_math {
870   $1 = ((FLOATVAL)1) / cosh((FLOATVAL)$2);
873 ########################################
875 =item B<sin>(out NUM, in NUM)
877 Set $1 to the sine of $2 (given in radians).
879 =cut
881 inline op sin(out NUM, in NUM) :base_math {
882   $1 = sin((FLOATVAL)$2);
885 ########################################
887 =item B<sinh>(out NUM, in NUM)
889 Set $1 to the hyperbolic sine of $2 (given in radians).
891 =cut
893 inline op sinh(out NUM, in NUM) :base_math {
894   $1 = sinh((FLOATVAL)$2);
897 ########################################
899 =item B<tan>(out NUM, in NUM)
901 Set $1 to the tangent of $2 (given in radians).
903 =cut
905 inline op tan(out NUM, in NUM) :base_math {
906   $1 = tan((FLOATVAL)$2);
909 ########################################
911 =item B<tanh>(out NUM, in NUM)
913 Set $1 to the hyperbolic tangent of $2 (given in radians).
915 =cut
917 inline op tanh(out NUM, in NUM) :base_math {
918   $1 = tanh((FLOATVAL)$2);
921 =back
923 =cut
925 ###############################################################################
927 =head2 Other mathematical operations
929 Implementations of various mathematical operations
931 =over 4
933 =cut
935 ########################################
937 =item B<gcd>(out INT, in INT, in INT)
939 Greatest Common divisor of $2 and $3.
941 =cut
943 inline op gcd(out INT, in INT, in INT) :advanced_math {
944  INTVAL p = 0;
945  INTVAL a = $2 < 0 ? -$2 : $2;
946  INTVAL b = $3 < 0 ? -$3 : $3;
948  if (a==0) { $1=b; goto NEXT(); }
949  if (b==0) { $1=a; goto NEXT(); }
951  while (!((a | b) & 1)) {
952    a>>=1;
953    b>>=1;
954    p++;
957  while (a>0) {
958    if (!(a & 1)) a>>=1;
959    else if (!(b & 1)) b>>=1;
960    else if (a<b)      b = (b-a)>>1;
961    else               a = (a-b)>>1;
964  $1 = b<<p;
968 ########################################
970 =item B<lcm>(out INT, in INT, in INT)
972 Least Common Multiple of $2 and $3
974 =cut
976 inline op lcm(out INT, in INT, in INT) :advanced_math {
977  INTVAL gcd = 0;
978  INTVAL p = 0;
979  INTVAL a = $2 < 0 ? -$2 : $2;
980  INTVAL b = $3 < 0 ? -$3 : $3;
981  INTVAL saved_var1 = a, saved_var2 = b;
983  if (a==0 || b==0) { $1=0; goto NEXT(); }
985  while (!((a | b) & 1)) {
986    a>>=1;
987    b>>=1;
988    p++;
991  while (a>0) {
992    if (!(a & 1)) a>>=1;
993    else if (!(b & 1)) b>>=1;
994    else if (a<b)      b = (b-a)>>1;
995    else               a = (a-b)>>1;
998  gcd = b<<p;
999  saved_var1 /= gcd;
1000  $1 = saved_var1*saved_var2;
1003 ########################################
1005 =item B<fact>(out INT, in INT)
1007 =item B<fact>(out NUM, in INT)
1009 Factorial, n!. Calculates the product of 1 to N.
1011 =cut
1013 inline op fact(out INT, in INT) :advanced_math {
1014   /* Coercing a negative to a UINT can get pretty ugly
1015    * in this situation. */
1016   INTVAL i = $2;
1017   UINTVAL q = 1;
1018   while (i>0) {
1019     q = q*i;
1020     i--;
1021   }
1022   $1 = q;
1025 inline op fact(out NUM, in INT) :advanced_math {
1026   /* Coercing a negative to a UINT can get pretty ugly
1027    * in this situation. */
1028   INTVAL i = $2;
1029   FLOATVAL q = 1;
1030   while (i>0) {
1031     q = q*i;
1032     i--;
1033   }
1034   $1 = q;
1037 =back
1039 =cut
1041 ###############################################################################
1043 =head1 COPYRIGHT
1045 Copyright (C) 2001-2008, The Perl Foundation.
1047 =head1 LICENSE
1049 This program is free software. It is subject to the same license
1050 as the Parrot interpreter itself.
1052 =cut
1055  * Local variables:
1056  *   c-file-style: "parrot"
1057  * End:
1058  * vim: expandtab shiftwidth=4:
1059  */