summaryrefslogtreecommitdiff
path: root/ext/standard/math.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/standard/math.c')
-rw-r--r--ext/standard/math.c708
1 files changed, 708 insertions, 0 deletions
diff --git a/ext/standard/math.c b/ext/standard/math.c
new file mode 100644
index 0000000000..e13fb82119
--- /dev/null
+++ b/ext/standard/math.c
@@ -0,0 +1,708 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP HTML Embedded Scripting Language Version 3.0 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997,1998 PHP Development Team (See Credits file) |
+ +----------------------------------------------------------------------+
+ | This program is free software; you can redistribute it and/or modify |
+ | it under the terms of one of the following licenses: |
+ | |
+ | A) the GNU General Public License as published by the Free Software |
+ | Foundation; either version 2 of the License, or (at your option) |
+ | any later version. |
+ | |
+ | B) the PHP License as published by the PHP Development Team and |
+ | included in the distribution in the file: LICENSE |
+ | |
+ | This program is distributed in the hope that it will be useful, |
+ | but WITHOUT ANY WARRANTY; without even the implied warranty of |
+ | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
+ | GNU General Public License for more details. |
+ | |
+ | You should have received a copy of both licenses referred to here. |
+ | If you did not, or have any questions about PHP licensing, please |
+ | contact core@php.net. |
+ +----------------------------------------------------------------------+
+ | Authors: Jim Winstead (jimw@php.net) |
+ | Stig Sæther Bakken <ssb@guardian.no> |
+ +----------------------------------------------------------------------+
+ */
+
+#ifdef THREAD_SAFE
+#include "tls.h"
+#endif
+#include "php.h"
+#include "phpmath.h"
+#include "snprintf.h"
+
+#include <math.h>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+char *_php3_number_format(double, int, char ,char);
+
+/* {{{ proto int abs(int number)
+ Return the absolute value of the number */
+void php3_abs(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *value;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht)!=1||getParameters(ht,1,&value)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ if (value->type == IS_STRING) {
+ convert_scalar_to_number(value);
+ }
+
+ if (value->type == IS_DOUBLE) {
+ RETURN_DOUBLE(fabs(value->value.dval));
+ }
+ else if (value->type == IS_LONG) {
+ RETURN_LONG(labs(value->value.lval));
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int ceil(double number)
+ Returns the next highest integer value of the number */
+void php3_ceil(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *value;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht)!=1||getParameters(ht,1,&value)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ if (value->type == IS_STRING) {
+ convert_scalar_to_number(value);
+ }
+
+ if (value->type == IS_DOUBLE) {
+ RETURN_LONG((long)ceil(value->value.dval));
+ }
+ else if (value->type == IS_LONG) {
+ RETURN_LONG(value->value.lval);
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int floor(double number)
+ Returns the next lowest integer value from the number */
+void php3_floor(INTERNAL_FUNCTION_PARAMETERS) {
+ pval *value;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht)!=1||getParameters(ht,1,&value)==FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ if (value->type == IS_STRING) {
+ convert_scalar_to_number(value);
+ }
+
+ if (value->type == IS_DOUBLE) {
+ RETURN_LONG((long)floor(value->value.dval));
+ }
+ else if (value->type == IS_LONG) {
+ RETURN_LONG(value->value.lval);
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+#ifndef HAVE_RINT
+/* emulate rint */
+inline double rint(double n)
+{
+ double i, f;
+ f = modf(n, &i);
+ if (f > .5)
+ i++;
+ else if (f < -.5)
+ i--;
+ return i;
+}
+#endif
+
+/* {{{ proto int round(double number)
+ Returns the rounded value of the number */
+void php3_round(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *value;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &value) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ if (value->type == IS_STRING) {
+ convert_scalar_to_number(value);
+ }
+ if (value->type == IS_DOUBLE) {
+ RETURN_DOUBLE(rint(value->value.dval));
+ }
+ if (value->type == IS_LONG) {
+ RETURN_DOUBLE((double)value->value.lval);
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto double sin(double number)
+ Returns the sine of the number in radians */
+void php3_sin(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = sin(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double cos(double number)
+ Returns the cosine of the number in radians */
+void php3_cos(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = cos(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double tan(double number)
+ Returns the tangent of the number in radians */
+void php3_tan(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = tan(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double asin(double number)
+ Returns the arc sine of the number in radians */
+void php3_asin(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = asin(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double acos(double number)
+ Return the arc cosine of the number in radians */
+void php3_acos(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = acos(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double atan(double number)
+ Returns the arc tangent of the number in radians */
+void php3_atan(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = atan(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double atan2(double y, double x)
+ Returns the arc tangent of y/x, with the resulting quadrant determined by the signs of y and x */
+void php3_atan2(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num1, *num2;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht, 2, &num1, &num2) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num1);
+ convert_to_double(num2);
+ return_value->value.dval = atan2(num1->value.dval,num2->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double pi(void)
+ Returns an approximation of pi */
+void php3_pi(INTERNAL_FUNCTION_PARAMETERS)
+{
+ return_value->value.dval = M_PI;
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double pow(double base, double exponent)
+ Returns base raised to the power of expopent */
+void php3_pow(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num1, *num2;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht) != 2 || getParameters(ht,2,&num1,&num2) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num1);
+ convert_to_double(num2);
+ RETURN_DOUBLE(pow(num1->value.dval, num2->value.dval));
+}
+/* }}} */
+
+/* {{{ proto double exp(double number)
+ Returns e raised to the power of the number */
+void php3_exp(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = exp(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double log(double number)
+ Returns the natural logarithm of the number */
+void php3_log(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = log(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double log10(double number)
+ Returns the base-10 logarithm of the number */
+void php3_log10(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = log10(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double sqrt(double number)
+ Returns the square root of the number */
+void php3_sqrt(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &num) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(num);
+ return_value->value.dval = sqrt(num->value.dval);
+ return_value->type = IS_DOUBLE;
+}
+/* }}} */
+
+/* {{{ proto double deg2rad(double number)
+ Converts the number in degrees to the radian equivalent */
+void php3_deg2rad(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *deg;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &deg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(deg);
+ RETVAL_DOUBLE((deg->value.dval / 180.0) * M_PI);
+}
+/* }}} */
+
+/* {{{ proto double rad2deg(double number)
+ Converts the radian number to the equivalent number in degrees */
+void php3_rad2deg(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *rad;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &rad) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_double(rad);
+ RETVAL_DOUBLE((rad->value.dval / M_PI) * 180);
+}
+/* }}} */
+
+
+/*
+ * Convert a string representation of a base(2-36) number to a long.
+ */
+static long
+_php3_basetolong(pval *arg, int base) {
+ long mult = 1, num = 0, digit;
+ int i;
+ char c, *s;
+
+ if (arg->type != IS_STRING || base < 2 || base > 36) {
+ return 0;
+ }
+
+ s = arg->value.str.val;
+
+ for (i = arg->value.str.len - 1; i >= 0; i--, mult *= base) {
+ c = toupper(s[i]);
+ if (c >= '0' && c <= '9') {
+ digit = (c - '0');
+ } else if (c >= 'A' && c <= 'Z') {
+ digit = (c - 'A' + 10);
+ } else {
+ continue;
+ }
+ if (digit >= base) {
+ continue;
+ }
+ num += mult * digit;
+ }
+
+ return num;
+}
+
+
+/*
+ * Convert a long to a string containing a base(2-36) representation of
+ * the number.
+ */
+static char *
+_php3_longtobase(pval *arg, int base)
+{
+ static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ char *result, *ptr, *ret;
+ int len, digit;
+ long value;
+
+ if (arg->type != IS_LONG || base < 2 || base > 36) {
+ return empty_string;
+ }
+
+ value = arg->value.lval;
+
+ /* allocates space for the longest possible result with the lowest base */
+ len = (sizeof(arg->value.lval) * 8) + 1;
+ result = emalloc((sizeof(arg->value.lval) * 8) + 1);
+
+ ptr = result + len - 1;
+ *ptr-- = '\0';
+
+ do {
+ digit = value % base;
+ *ptr = digits[digit];
+ value /= base;
+ }
+ while (ptr-- > result && value);
+ ptr++;
+ ret = estrdup(ptr);
+ efree(result);
+
+ return ret;
+}
+
+/* {{{ proto int bindec(string binary_number)
+ Returns the decimal equivalent of the binary number */
+void php3_bindec(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg;
+ long ret;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ convert_to_string(arg);
+ ret = _php3_basetolong(arg, 2);
+
+ RETVAL_LONG(ret);
+}
+/* }}} */
+
+/* {{{ proto int hexdec(string hexadimal_number)
+ Returns the decimal equivalent of the hexadecimal number */
+void php3_hexdec(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg;
+ long ret;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ convert_to_string(arg);
+
+ ret = _php3_basetolong(arg, 16);
+ RETVAL_LONG(ret);
+}
+/* }}} */
+
+/* {{{ proto int octdec(string octal_number)
+ Returns the decimal equivalent of an octal string */
+void php3_octdec(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg;
+ long ret;
+ TLS_VARS;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ convert_to_string(arg);
+
+ ret = _php3_basetolong(arg, 8);
+ RETVAL_LONG(ret);
+}
+/* }}} */
+
+/* {{{ proto string decbin(int decimal_number)
+ Returns a string containing a binary representation of the number */
+void php3_decbin(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg;
+ char *result;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ convert_to_long(arg);
+
+ result = _php3_longtobase(arg, 2);
+ return_value->type = IS_STRING;
+ return_value->value.str.len = strlen(result);
+ return_value->value.str.val = result;
+}
+/* }}} */
+
+/* {{{ proto string decoct(int decimal_number)
+ Returns a string containing an octal representation of the given number */
+void php3_decoct(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg;
+ char *result;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ convert_to_long(arg);
+
+ result = _php3_longtobase(arg, 8);
+ return_value->type = IS_STRING;
+ return_value->value.str.len = strlen(result);
+ return_value->value.str.val = result;
+}
+/* }}} */
+
+/* {{{ proto string dechex(int decimal_number)
+ Returns a string containing a hexadecimal representation of the given number */
+void php3_dechex(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *arg;
+ char *result;
+
+ if (ARG_COUNT(ht) != 1 || getParameters(ht, 1, &arg) == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+
+ convert_to_long(arg);
+
+ result = _php3_longtobase(arg, 16);
+ return_value->type = IS_STRING;
+ return_value->value.str.len = strlen(result);
+ return_value->value.str.val = result;
+}
+/* }}} */
+
+
+/* {{{ proto string base_convert(string number, int frombase, int tobase)
+ Converts a number in a string from any base <= 36 to any base <= 36.
+*/
+void php3_base_convert(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *number, *frombase, *tobase, temp;
+ char *result;
+
+ if (ARG_COUNT(ht) != 3 || getParameters(ht, 3, &number, &frombase, &tobase)
+ == FAILURE) {
+ WRONG_PARAM_COUNT;
+ }
+ convert_to_string(number);
+ convert_to_long(frombase);
+ convert_to_long(tobase);
+ if (frombase->value.lval < 2 || frombase->value.lval > 36) {
+ php3_error(E_WARNING, "base_convert: invalid `from base' (%d)",
+ frombase->value.lval);
+ RETURN_FALSE;
+ }
+ if (tobase->value.lval < 2 || tobase->value.lval > 36) {
+ php3_error(E_WARNING, "base_convert: invalid `to base' (%d)",
+ tobase->value.lval);
+ RETURN_FALSE;
+ }
+ temp.type = IS_LONG;
+ temp.value.lval = _php3_basetolong(number, frombase->value.lval);
+ result = _php3_longtobase(&temp, tobase->value.lval);
+ RETVAL_STRING(result, 0);
+} /* }}} */
+
+
+char *_php3_number_format(double d,int dec,char dec_point,char thousand_sep)
+{
+ char *tmpbuf,*resbuf;
+ char *s,*t; /* source, target */
+ int tmplen,reslen=0;
+ int count=0;
+ int is_negative=0;
+
+ if (d<0) {
+ is_negative=1;
+ d = -d;
+ }
+ dec = MAX(0,dec);
+ tmpbuf = (char *) emalloc(32+dec);
+
+ tmplen=_php3_sprintf(tmpbuf,"%.*f",dec,d);
+
+ for (t=tmpbuf; *t; t++) {
+ if (*t=='.') {
+ *t = dec_point;
+ }
+ }
+ if (dec) {
+ reslen = dec+1 + (tmplen-dec-1) + (tmplen-1-dec-1)/3;
+ } else {
+ reslen = tmplen+(tmplen-1)/3;
+ }
+ if (is_negative) {
+ reslen++;
+ }
+ resbuf = (char *) emalloc(reslen+1);
+
+ s = tmpbuf+tmplen-1;
+ t = resbuf+reslen;
+ *t-- = 0;
+
+ if (dec) {
+ while (*s!=dec_point) {
+ *t-- = *s--;
+ }
+ *t-- = *s--; /* copy that dot */
+ }
+
+ while(s>=tmpbuf) {
+ *t-- = *s--;
+ if ((++count%3)==0 && s>=tmpbuf) {
+ *t-- = thousand_sep;
+ }
+ }
+ if (is_negative) {
+ *t-- = '-';
+ }
+ efree(tmpbuf);
+ return resbuf;
+}
+
+/* {{{ proto string number_format(double number, [,int num_decimal_places [, string dec_seperator, string thousands_seperator)]])
+ Formats a number with grouped thousands */
+void php3_number_format(INTERNAL_FUNCTION_PARAMETERS)
+{
+ pval *num,*dec,*t_s,*d_p;
+ char thousand_sep=',', dec_point='.';
+
+ switch(ARG_COUNT(ht)) {
+ case 1:
+ if (getParameters(ht, 1, &num)==FAILURE) {
+ RETURN_FALSE;
+ }
+ convert_to_double(num);
+ RETURN_STRING(_php3_number_format(num->value.dval,0,dec_point,thousand_sep),0);
+ break;
+ case 2:
+ if (getParameters(ht, 2, &num, &dec)==FAILURE) {
+ RETURN_FALSE;
+ }
+ convert_to_double(num);
+ convert_to_long(dec);
+ RETURN_STRING(_php3_number_format(num->value.dval,dec->value.lval,dec_point,thousand_sep),0);
+ break;
+ case 4:
+ if (getParameters(ht, 4, &num, &dec, &d_p, &t_s)==FAILURE) {
+ RETURN_FALSE;
+ }
+ convert_to_double(num);
+ convert_to_long(dec);
+ convert_to_string(d_p);
+ convert_to_string(t_s);
+ if (d_p->value.str.len==1) {
+ dec_point=d_p->value.str.val[0];
+ }
+ if (t_s->value.str.len==1) {
+ thousand_sep=t_s->value.str.val[0];
+ }
+ RETURN_STRING(_php3_number_format(num->value.dval,dec->value.lval,dec_point,thousand_sep),0);
+ break;
+ default:
+ WRONG_PARAM_COUNT;
+ break;
+ }
+}
+/* }}} */
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */