tagged release 0.6.4
[parrot.git] / languages / pipp / src / common / php_math.pir
blob520c9a1b6de39d2a022f8c3da10a65b27bba8712
1 # Copyright (C) 2008, The Perl Foundation.
2 # $Id$
4 =head1 NAME
6 php_math.pir - PHP math Standard Library
8 =head1 DESCRIPTION
10 =head2 Functions
12 =over 4
14 =cut
16 .const num PI = 3.14159265358979323846
18 .sub 'longtobase' :anon
19     .param int value
20     .param int base
21     .const string digits = '0123456789abcdefghijklmnopqrstuvwxyz'
22     $S0 = ''
23   L1:
24     $I0 = value % base
25     $S1 = substr digits, $I0, 1
26     $S0 = concat $S1, $S0
27     value = value / base
28     if value goto L1
29     .return ($S0)
30 .end
32 .macro ROUND_WITH_FUZZ(val, places)
33     .local num tmp
34     tmp = .val
35     .local num f
36     f = pow 10.0, .places
37     tmp *= f
38     unless tmp >= 0.0 goto L11
39     tmp += 0.5
40     tmp = floor tmp
41     goto L12
42   L11:
43     tmp -= 0.5
44     tmp =ceil tmp
45   L12:
46     .val = tmp / f
47 .endm
49 .macro TRIG1(args, func)
50     .local int argc
51     argc = .args
52     unless argc != 1 goto L1
53     wrong_param_count()
54     .RETURN_NULL()
55   L1:
56     $P1 = shift .args
57     $I0 = isa $P1, 'PhpFloat'
58     if $I0 goto L2
59     $N1 = $P1
60     new $P1, 'PhpFloat'
61     set $P1, $N1
62   L2:
63     $P0 = $P1. .func ()
64     .return ($P0)
65 .endm
68 =item C<int abs(int number)>
70 Return the absolute value of the number
72 =cut
74 .sub 'abs'
75     .param pmc args :slurpy
76     .local int argc
77     argc = args
78     unless argc != 1 goto L1
79     wrong_param_count()
80     .RETURN_NULL()
81   L1:
82     $P1 = shift args
83     $P1 = $P1.'to_number'()
84     $I0 = isa $P1, 'PhpFloat'
85     unless $I0 goto L2
86     $N1 = $P1
87     $N0 = abs $N1
88     .RETURN_DOUBLE($N0)
89   L2:
90     $I0 = isa $P1, 'PhpInteger'
91     unless $I0 goto L3
92     $I1 = $P1
93     $I0 = abs $I1
94     .RETURN_LONG($I0)
95   L3:
96     .RETURN_FALSE()
97 .end
99 =item C<float acos(float number)>
101 Return the arc cosine of the number in radians
103 =cut
105 .sub 'acos'
106     .param pmc args :slurpy
107     .TRIG1(args, acos)
108 .end
110 =item C<float acosh(float number)>
112 Returns the inverse hyperbolic cosine of the number, i.e. the value whose hyperbolic cosine is number
114 =cut
116 .sub 'acosh'
117     .param pmc args :slurpy
118     .TRIG1(args, acosh)
119 .end
121 =item C<float asin(float number)>
123 Returns the arc sine of the number in radians
125 =cut
127 .sub 'asin'
128     .param pmc args :slurpy
129     .TRIG1(args, asin)
130 .end
132 =item C<float asinh(float number)>
134 Returns the inverse hyperbolic sine of the number, i.e. the value whose hyperbolic sine is number
136 =cut
138 .sub 'asinh'
139     .param pmc args :slurpy
140     .TRIG1(args, asinh)
141 .end
143 =item C<float atan(float number)>
145 Returns the arc tangent of the number in radians
147 =cut
149 .sub 'atan'
150     .param pmc args :slurpy
151     .TRIG1(args, atan)
152 .end
154 =item C<float atan2(float y, float x)>
156 Returns the arc tangent of y/x, with the resulting quadrant determined by the signs of y and x
158 =cut
160 .sub 'atan2'
161     .param pmc args :slurpy
162     .local int argc
163     argc = args
164     unless argc != 2 goto L1
165     wrong_param_count()
166     .RETURN_NULL()
167   L1:
168     $P1 = shift args
169     $N1 = $P1
170     $P2 = shift args
171     $N2 = $P2
172     $N0 = atan $N1, $N2
173     .RETURN_DOUBLE($N0)
174 .end
176 =item C<float atanh(float number)>
178 Returns the inverse hyperbolic tangent of the number, i.e. the value whose hyperbolic tangent is number
180 =cut
182 .sub 'atanh'
183     .param pmc args :slurpy
184     .TRIG1(args, atanh)
185 .end
187 =item C<string base_convert(string number, int frombase, int tobase)>
189 Converts a number in a string from any base <= 36 to any base <= 36
191 =cut
193 .sub 'base_convert'
194     .param pmc args :slurpy
195     .local int argc
196     argc = args
197     unless argc != 3 goto L1
198     wrong_param_count()
199     .RETURN_NULL()
200   L1:
201     $P1 = shift args
202     $S1 = $P1
203     new $P1, 'PhpString'
204     set $P1, $S1
205     $P2 = shift args
206     $I2 = $P2
207     $P3 = shift args
208     $I3 = $P3
209     if $I2 < 2 goto L2
210     if $I2 > 36 goto L2
211     goto L3
212   L2:
213     error(E_WARNING, "Invalid `from base' (", $I2, ")")
214     .RETURN_FALSE()
215   L3:
216     if $I3 < 2 goto L4
217     if $I3 > 36 goto L4
218     goto L5
219   L4:
220     error(E_WARNING, "Invalid `to base' (", $I3, ")")
221     .RETURN_FALSE()
222   L5:
223     $P0 = $P1.'to_base'($I2)
224     $I0 = isa $P0, 'PhpInteger'
225     unless $I0 goto L6
226     $I0 = $P0
227     $S0 = longtobase($I0, $I3)
228     .RETURN_STRING($S0)
229   L6:
230     .RETURN_FALSE()
231 .end
233 =item C<int bindec(string binary_number)>
235 Returns the decimal equivalent of the binary number
237 =cut
239 .sub 'bindec'
240     .param pmc args :slurpy
241     .local int argc
242     argc = args
243     unless argc != 1 goto L1
244     wrong_param_count()
245     .RETURN_NULL()
246   L1:
247     $P1 = shift args
248     $S1 = $P1
249     new $P1, 'PhpString'
250     set $P1, $S1
251     $P0 = $P1.'to_base'(2)
252     .return ($P0)
253 .end
255 =item C<float ceil(float number)>
257 Returns the next highest integer value of the number
259 =cut
261 .sub 'ceil'
262     .param pmc args :slurpy
263     .local int argc
264     argc = args
265     unless argc != 1 goto L1
266     wrong_param_count()
267     .RETURN_NULL()
268   L1:
269     $P1 = shift args
270     $P1 = $P1.'to_number'()
271     $I0 = isa $P1, 'PhpFloat'
272     unless $I0 goto L2
273     $N1 = $P1
274     $N0 = ceil $N1
275     .RETURN_DOUBLE($N0)
276   L2:
277     $I0 = isa $P1, 'PhpInteger'
278     unless $I0 goto L3
279     $N0 = $P1
280     .RETURN_DOUBLE($N0)
281   L3:
282     .RETURN_FALSE()
283 .end
285 =item C<float cos(float number)>
287 Returns the cosine of the number in radians
289 =cut
291 .sub 'cos'
292     .param pmc args :slurpy
293     .TRIG1(args, cos)
294 .end
296 =item C<float cosh(float number)>
298 Returns the hyperbolic cosine of the number, defined as (exp(number) + exp(-number))/2
300 =cut
302 .sub 'cosh'
303     .param pmc args :slurpy
304     .TRIG1(args, cosh)
305 .end
307 =item C<string decbin(int decimal_number)>
309 Returns a string containing a binary representation of the number
311 =cut
313 .sub 'decbin'
314     .param pmc args :slurpy
315     .local int argc
316     argc = args
317     unless argc != 1 goto L1
318     wrong_param_count()
319     .RETURN_NULL()
320   L1:
321     $P1 = shift args
322     $I1 = $P1
323     $S0 = longtobase($I1, 2)
324     .RETURN_STRING($S0)
325 .end
327 =item C<string dechex(int decimal_number)>
329 Returns a string containing a hexadecimal representation of the given number
331 =cut
333 .sub 'dechex'
334     .param pmc args :slurpy
335     .local int argc
336     argc = args
337     unless argc != 1 goto L1
338     wrong_param_count()
339     .RETURN_NULL()
340   L1:
341     $P1 = shift args
342     $I1 = $P1
343     $S0 = longtobase($I1, 16)
344     .RETURN_STRING($S0)
345 .end
347 =item C<string decoct(int decimal_number)>
349 Returns a string containing an octal representation of the given number
351 =cut
353 .sub 'decoct'
354     .param pmc args :slurpy
355     .local int argc
356     argc = args
357     unless argc != 1 goto L1
358     wrong_param_count()
359     .RETURN_NULL()
360   L1:
361     $P1 = shift args
362     $I1 = $P1
363     $S0 = longtobase($I1, 8)
364     .RETURN_STRING($S0)
365 .end
367 =item C<float deg2rad(float number)>
369 Converts the number in degrees to the radian equivalent
371 =cut
373 .sub 'deg2rad'
374     .param pmc args :slurpy
375     .local int argc
376     argc = args
377     unless argc != 1 goto L1
378     wrong_param_count()
379     .RETURN_NULL()
380   L1:
381     $P1 = shift args
382     $N1 = $P1
383     $N0 = $N1 / 180.0
384     $N0 *= PI
385     .RETURN_DOUBLE($N0)
386 .end
388 =item C<float exp(float number)>
390 Returns e raised to the power of the number
392 =cut
394 .sub 'exp'
395     .param pmc args :slurpy
396     .local num number
397     ($I0, number) = parse_parameters('d', args :flat)
398     if $I0 goto L1
399     .RETURN_NULL()
400   L1:
401     $N0 = exp number
402     .RETURN_DOUBLE($N0)
403 .end
405 =item C<float expm1(float number)>
407 Returns exp(number) - 1, computed in a way that accurate even when the value of number is close to zero
409 NOT IMPLEMENTED. WARNING: this function is experimental.
411 =cut
413 .sub 'expm1'
414     not_implemented()
415 .end
417 =item C<float floor(float number)>
419 Returns the next lowest integer value from the number
421 =cut
423 .sub 'floor'
424     .param pmc args :slurpy
425     .local int argc
426     argc = args
427     unless argc != 1 goto L1
428     wrong_param_count()
429     .RETURN_NULL()
430   L1:
431     $P1 = shift args
432     $P1 = $P1.'to_number'()
433     $I0 = isa $P1, 'PhpFloat'
434     unless $I0 goto L2
435     $N1 = $P1
436     $N0 = floor $N1
437     .RETURN_DOUBLE($N0)
438   L2:
439     $I0 = isa $P1, 'PhpInteger'
440     unless $I0 goto L3
441     $N0 = $P1
442     .RETURN_DOUBLE($N0)
443   L3:
444     .RETURN_FALSE()
445 .end
447 =item C<float fmod(float x, float y)>
449 Returns the remainder of dividing x by y as a float
451 =cut
453 .sub 'fmod'
454     .param pmc args :slurpy
455     .local num x
456     .local num y
457     ($I0, x, y) = parse_parameters('dd', args :flat)
458     if $I0 goto L1
459     .RETURN_NULL()
460   L1:
461     $N0 = cmod x, y
462     .RETURN_DOUBLE($N0)
463 .end
465 =item C<int hexdec(string hexadecimal_number)>
467 Returns the decimal equivalent of the hexadecimal number
469 =cut
471 .sub 'hexdec'
472     .param pmc args :slurpy
473     .local int argc
474     argc = args
475     unless argc != 1 goto L1
476     wrong_param_count()
477     .RETURN_NULL()
478   L1:
479     $P1 = shift args
480     $S1 = $P1
481     new $P1, 'PhpString'
482     set $P1, $S1
483     $P0 = $P1.'to_base'(16)
484     .return ($P0)
485 .end
487 =item C<float hypot(float num1, float num2)>
489 Returns sqrt(num1*num1 + num2*num2)
491 =cut
493 .sub 'hypot'
494     .param pmc args :slurpy
495     .local int argc
496     argc = args
497     unless argc != 2 goto L1
498     wrong_param_count()
499     .RETURN_NULL()
500   L1:
501     $P1 = shift args
502     $N1 = $P1
503     $P2 = shift args
504     $N2 = $P2
505     $N1 *= $N1
506     $N2 *= $N2
507     $N1 += $N2
508     $N0 = sqrt $N1
509     .RETURN_DOUBLE($N0)
510 .end
512 =item C<bool is_finite(float val)>
514 Returns whether argument is finite
516 =cut
518 .sub 'is_finite'
519     .param pmc args :slurpy
520     .local pmc val
521     ($I0, val) = parse_parameters('d', args :flat)
522     if $I0 goto L1
523     .RETURN_NULL()
524   L1:
525     $P0 = val.'is_finite'()
526     .return ($P0)
527 .end
529 =item C<bool is_infinite(float val)>
531 Returns whether argument is infinite
533 =cut
535 .sub 'is_infinite'
536     .param pmc args :slurpy
537     .local pmc val
538     ($I0, val) = parse_parameters('d', args :flat)
539     if $I0 goto L1
540     .RETURN_NULL()
541   L1:
542     $P0 = val.'is_infinite'()
543     .return ($P0)
544 .end
546 =item C<bool is_nan(float val)>
548 Returns whether argument is not a number
550 =cut
552 .sub 'is_nan'
553     .param pmc args :slurpy
554     .local pmc val
555     ($I0, val) = parse_parameters('d', args :flat)
556     if $I0 goto L1
557     .RETURN_NULL()
558   L1:
559     $P0 = val.'is_nan'()
560     .return ($P0)
561 .end
563 =item C<float log(float number, [float base])>
565 Returns the natural logarithm of the number, or the base log if base is specified
567 =cut
569 .sub 'log'
570     .param pmc args :slurpy
571     .local int argc
572     argc = args
573     unless argc == 1 goto L1
574     $P1 = shift args
575     $N1 = $P1
576     $N0 = ln $N1
577     .RETURN_DOUBLE($N0)
578   L1:
579     unless argc == 2 goto L2
580     $P1 = shift args
581     $N1 = $P1
582     $P2 = shift args
583     $N2 = $P2
584     unless $N2 <= 0.0 goto L3
585     error(E_WARNING, "base must be greater than 0")
586     .RETURN_FALSE()
587   L3:
588     $N1 = ln $N1
589     $N2 = ln $N2
590     $N0 = $N1 / $N2
591     .RETURN_DOUBLE($N0)
592   L2:
593     wrong_param_count()
594     .RETURN_NULL()
595 .end
597 =item C<float log10(float number)>
599 Returns the base-10 logarithm of the number
601 =cut
603 .sub 'log10'
604     .param pmc args :slurpy
605     .local int argc
606     argc = args
607     unless argc != 1 goto L1
608     wrong_param_count()
609     .RETURN_NULL()
610   L1:
611     $P1 = shift args
612     $N1 = $P1
613     $N0 = log10 $N1
614     .RETURN_DOUBLE($N0)
615 .end
617 =item C<float log1p(float number)>
619 Returns log(1 + number), computed in a way that accurate even when the value of number is close to zero
621 NOT IMPLEMENTED. WARNING: this function is experimental.
623 =cut
625 .sub 'log1p'
626     not_implemented()
627 .end
629 =item C<string number_format(float number [, int num_decimal_places [, string dec_seperator, string thousands_seperator]])>
631 Formats a number with grouped thousands
633 =cut
635 .sub 'number_format'
636     .param pmc args :slurpy
637     .local int argc
638     argc = args
639     .local string thousand_sep, dec_point
640     thousand_sep = ','
641     dec_point = '.'
642     unless argc == 1 goto L1
643     $P1 = shift args
644     $P1 = $P1.'to_number'()
645     $N1 = $P1
646     .return _number_format($N1, 0, dec_point, thousand_sep)
647   L1:
648     unless argc == 2 goto L2
649     $P1 = shift args
650     $P1 = $P1.'to_number'()
651     $N1 = $P1
652     $P2 = shift args
653     $I2 = $P2
654     .return _number_format($N1, $I2, dec_point, thousand_sep)
655   L2:
656     unless argc == 4 goto L3
657     $P1 = shift args
658     $P1 = $P1.'to_number'()
659     $N1 = $P1
660     $P2 = shift args
661     $I2 = $P2
662     $P3 = shift args
663     $I0 = isa $P3, 'PhpUndef'
664     if $I0 goto L4
665     dec_point = $P3
666     $I3 = length dec_point
667     unless $I3 goto L4
668     dec_point =substr dec_point, 0, 1
669   L4:
670     $P4 = shift args
671     $I0 = isa $P4, 'PhpUndef'
672     if $I0 goto L5
673     thousand_sep = $P4
674     $I4 = length thousand_sep
675     unless $I4 goto L5
676     thousand_sep =substr thousand_sep, 0, 1
677   L5:
678     .return _number_format($N1, $I2, dec_point, thousand_sep)
679   L3:
680     wrong_param_count()
681     .RETURN_NULL()
682 .end
684 .sub '_number_format' :anon
685     .param num d
686     .param int dec
687     .param string dec_point
688     .param string thousand_sep
689     .local int is_negative
690     is_negative = 0
691     unless d < 0 goto L1
692     is_negative = 1
693     neg d
694   L1:
695     unless dec < 0 goto L2
696     dec = 0
697   L2:
698     .ROUND_WITH_FUZZ(d, dec)
699     $S1 = dec
700     $S0 = concat '%.', $S1
701     $S0 = concat 'f'
702     new $P0, 'FixedFloatArray'
703     set $P0, 1
704     $P0[0] = d
705     .local string tmpbuf
706     tmpbuf = sprintf $S0, $P0
707     $S0 = ''
708     $I0 = index tmpbuf, '.'
709     unless $I0 < 0 goto L3
710     $I0 = length tmpbuf
711     goto L4
712   L3:
713     unless dec goto L4
714     $I1 = $I0 + 1
715     $S0 = substr tmpbuf, $I1
716     unless dec_point goto L4
717     $S0 = concat dec_point, $S0
718   L4:
719     $I1 = $I0 - 3
720     $I2 = 3
721     unless $I1 < 0 goto L5
722     $I1 = 0
723     $I2 = $I0
724   L5:
725     $S1 = substr tmpbuf, $I1, $I2
726     $S0 = concat $S1, $S0
727     $I0 -= 3
728     unless $I0 > 0 goto L6
729     unless thousand_sep goto L4
730     $S0 = concat thousand_sep, $S0
731     goto L4
732   L6:
733     unless is_negative goto L7
734     $S0 = concat '-', $S0
735   L7:
736     .RETURN_STRING($S0)
737 .end
739 =item C<int octdec(string octal_number)>
741 Returns the decimal equivalent of an octal string
743 =cut
745 .sub 'octdec'
746     .param pmc args :slurpy
747     .local int argc
748     argc = args
749     unless argc != 1 goto L1
750     wrong_param_count()
751     .RETURN_NULL()
752   L1:
753     $P1 = shift args
754     $S1 = $P1
755     new $P1, 'PhpString'
756     set $P1, $S1
757     $P0 = $P1.'to_base'(8)
758     .return ($P0)
759 .end
761 =item C<float pi(void)>
763 Returns an approximation of pi
765 =cut
767 .sub 'pi'
768     .param pmc args :slurpy
769     .RETURN_DOUBLE(PI)
770 .end
772 =item C<number pow(number base, number exponent)>
774 Returns base raised to the power of exponent. Returns integer result when possible
776 =cut
778 .sub 'pow'
779     .param pmc args :slurpy
780     .local pmc base
781     .local pmc exponent
782     ($I0, base, exponent) = parse_parameters('z/z/', args :flat)
783     if $I0 goto L1
784     .RETURN_NULL()
785   L1:
786     base = base.'to_number'()
787     exponent = exponent.'to_number'()
788     $I0 = isa base, 'PhpInteger'
789     unless $I0 goto L2
790     $I0 = isa exponent, 'PhpInteger'
791     unless $I0 goto L2
792     $N1 = base
793     $N2 = exponent
794     $N0 = pow $N1, $N2
795     $I0 = $N0
796     .RETURN_LONG($I0)
797   L2:
798     $N1 = base
799     $N2 = exponent
800     $N0 = pow $N1, $N2
801     .RETURN_DOUBLE($N0)
802 .end
804 =item C<float rad2deg(float number)>
806 Converts the radian number to the equivalent number in degrees
808 =cut
810 .sub 'rad2deg'
811     .param pmc args :slurpy
812     .local int argc
813     argc = args
814     unless argc != 1 goto L1
815     wrong_param_count()
816     .RETURN_NULL()
817   L1:
818     $P1 = shift args
819     $N1 = $P1
820     $N0 = $N1 / PI
821     $N0 *= 180.0
822     .RETURN_DOUBLE($N0)
823 .end
825 =item C<float round(float number [, int precision])>
827 Returns the number rounded to specified precision
829 =cut
831 .sub 'round'
832     .param pmc args :slurpy
833     .local int argc
834     argc = args
835     if argc < 1 goto L1
836     if argc > 2 goto L1
837     goto L2
838   L1:
839     wrong_param_count()
840     .RETURN_NULL()
841   L2:
842     $P1 = shift args
843     $I2 = 0
844     unless argc == 2 goto L3
845     $P2 = shift args
846     $I2 = $P2
847   L3:
848     $I0 = isa $P1, 'PhpInteger'
849     unless $I0 goto L4
850     unless $I2 >= 0 goto L5
851     $N0 = $P1
852     .RETURN_DOUBLE($N0)
853   L4:
854     $I0 = isa $P1, 'PhpFloat'
855     unless $I0 goto L6
856   L5:
857     $N0 = $P1
858     $N2 = $I2
859     .ROUND_WITH_FUZZ($N0, $N2)
860     .RETURN_DOUBLE($N0)
861   L6:
862     .RETURN_FALSE()
863 .end
865 =item C<float sin(float number)>
867 Returns the sine of the number in radians
869 =cut
871 .sub 'sin'
872     .param pmc args :slurpy
873     .TRIG1(args, sin)
874 .end
876 =item C<float sinh(float number)>
878 Returns the hyperbolic sine of the number, defined as (exp(number) - exp(-number))/2
880 =cut
882 .sub 'sinh'
883     .param pmc args :slurpy
884     .TRIG1(args, sinh)
885 .end
887 =item C<float sqrt(float number)>
889 Returns the square root of the number
891 =cut
893 .sub 'sqrt'
894     .param pmc args :slurpy
895     .local int argc
896     argc = args
897     unless argc != 1 goto L1
898     wrong_param_count()
899     .RETURN_NULL()
900   L1:
901     $P1 = shift args
902     $N1 = $P1
903     $N0 = sqrt $N1
904     .RETURN_DOUBLE($N0)
905 .end
907 =item C<float tan(float number)>
909 Returns the tangent of the number in radians
911 =cut
913 .sub 'tan'
914     .param pmc args :slurpy
915     .TRIG1(args, tan)
916 .end
918 =item C<float tanh(float number)>
920 Returns the hyperbolic tangent of the number, defined as sinh(number)/cosh(number)
922 =cut
924 .sub 'tanh'
925     .param pmc args :slurpy
926     .TRIG1(args, tanh)
927 .end
929 =back
931 =cut
933 # Local Variables:
934 #   mode: pir
935 #   fill-column: 100
936 # End:
937 # vim: expandtab shiftwidth=4 ft=pir: