1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Jim Winstead <jimw@php.net> |
16 : | Stig Sæther Bakken <ssb@php.net> |
17 : | Zeev Suraski <zeev@zend.com> |
18 : | PHP 4.0 patches by Thies C. Arntzen <thies@thieso.net> |
19 : +----------------------------------------------------------------------+
20 : */
21 :
22 : /* $Id: math.c,v 1.131.2.2.2.5 2007/01/01 09:36:08 sebastian Exp $ */
23 :
24 : #include "php.h"
25 : #include "php_math.h"
26 : #include "zend_multiply.h"
27 :
28 : #include <math.h>
29 : #include <float.h>
30 : #include <stdlib.h>
31 :
32 : #ifndef PHP_ROUND_FUZZ
33 : # ifndef PHP_WIN32
34 : # define PHP_ROUND_FUZZ 0.50000000001
35 : # else
36 : # define PHP_ROUND_FUZZ 0.5
37 : # endif
38 : #endif
39 :
40 : #define PHP_ROUND_WITH_FUZZ(val, places) { \
41 : double tmp_val=val, f = pow(10.0, (double) places); \
42 : tmp_val *= f; \
43 : if (tmp_val >= 0.0) { \
44 : tmp_val = floor(tmp_val + PHP_ROUND_FUZZ); \
45 : } else { \
46 : tmp_val = ceil(tmp_val - PHP_ROUND_FUZZ); \
47 : } \
48 : tmp_val /= f; \
49 : val = !zend_isnan(tmp_val) ? tmp_val : val; \
50 : } \
51 :
52 : /* {{{ proto int abs(int number)
53 : Return the absolute value of the number */
54 : PHP_FUNCTION(abs)
55 0 : {
56 : zval **value;
57 :
58 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &value) == FAILURE) {
59 0 : WRONG_PARAM_COUNT;
60 : }
61 :
62 0 : convert_scalar_to_number_ex(value);
63 :
64 0 : if (Z_TYPE_PP(value) == IS_DOUBLE) {
65 0 : RETURN_DOUBLE(fabs(Z_DVAL_PP(value)));
66 0 : } else if (Z_TYPE_PP(value) == IS_LONG) {
67 0 : if (Z_LVAL_PP(value) == LONG_MIN) {
68 0 : RETURN_DOUBLE(-(double)LONG_MIN);
69 : } else {
70 0 : RETURN_LONG(Z_LVAL_PP(value) < 0 ? -Z_LVAL_PP(value) : Z_LVAL_PP(value));
71 : }
72 : }
73 0 : RETURN_FALSE;
74 : }
75 : /* }}} */
76 :
77 : /* {{{ proto float ceil(float number)
78 : Returns the next highest integer value of the number */
79 : PHP_FUNCTION(ceil)
80 0 : {
81 : zval **value;
82 :
83 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &value) == FAILURE) {
84 0 : WRONG_PARAM_COUNT;
85 : }
86 :
87 0 : convert_scalar_to_number_ex(value);
88 :
89 0 : if (Z_TYPE_PP(value) == IS_DOUBLE) {
90 0 : RETURN_DOUBLE(ceil(Z_DVAL_PP(value)));
91 0 : } else if (Z_TYPE_PP(value) == IS_LONG) {
92 0 : convert_to_double_ex(value);
93 0 : RETURN_DOUBLE(Z_DVAL_PP(value));
94 : }
95 :
96 0 : RETURN_FALSE;
97 : }
98 : /* }}} */
99 :
100 : /* {{{ proto float floor(float number)
101 : Returns the next lowest integer value from the number */
102 : PHP_FUNCTION(floor)
103 0 : {
104 : zval **value;
105 :
106 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &value) == FAILURE) {
107 0 : WRONG_PARAM_COUNT;
108 : }
109 :
110 0 : convert_scalar_to_number_ex(value);
111 :
112 0 : if (Z_TYPE_PP(value) == IS_DOUBLE) {
113 0 : RETURN_DOUBLE(floor(Z_DVAL_PP(value)));
114 0 : } else if (Z_TYPE_PP(value) == IS_LONG) {
115 0 : convert_to_double_ex(value);
116 0 : RETURN_DOUBLE(Z_DVAL_PP(value));
117 : }
118 :
119 0 : RETURN_FALSE;
120 : }
121 : /* }}} */
122 :
123 : /* {{{ proto float round(float number [, int precision])
124 : Returns the number rounded to specified precision */
125 : PHP_FUNCTION(round)
126 108 : {
127 : zval **value, **precision;
128 108 : int places = 0;
129 : double return_val;
130 :
131 108 : if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
132 : zend_get_parameters_ex(ZEND_NUM_ARGS(), &value, &precision) == FAILURE) {
133 0 : WRONG_PARAM_COUNT;
134 : }
135 :
136 108 : if (ZEND_NUM_ARGS() == 2) {
137 108 : convert_to_long_ex(precision);
138 108 : places = (int) Z_LVAL_PP(precision);
139 : }
140 :
141 108 : convert_scalar_to_number_ex(value);
142 :
143 108 : switch (Z_TYPE_PP(value)) {
144 : case IS_LONG:
145 : /* Simple case - long that doesn't need to be rounded. */
146 26 : if (places >= 0) {
147 26 : RETURN_DOUBLE((double) Z_LVAL_PP(value));
148 : }
149 : /* break omitted intentionally */
150 :
151 : case IS_DOUBLE:
152 82 : return_val = (Z_TYPE_PP(value) == IS_LONG) ?
153 : (double)Z_LVAL_PP(value) : Z_DVAL_PP(value);
154 :
155 82 : PHP_ROUND_WITH_FUZZ(return_val, places);
156 :
157 82 : RETURN_DOUBLE(return_val);
158 : break;
159 :
160 : default:
161 0 : RETURN_FALSE;
162 : break;
163 : }
164 : }
165 : /* }}} */
166 :
167 : /* {{{ proto float sin(float number)
168 : Returns the sine of the number in radians */
169 : PHP_FUNCTION(sin)
170 0 : {
171 : zval **num;
172 :
173 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
174 0 : WRONG_PARAM_COUNT;
175 : }
176 0 : convert_to_double_ex(num);
177 0 : Z_DVAL_P(return_value) = sin(Z_DVAL_PP(num));
178 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
179 : }
180 : /* }}} */
181 :
182 : /* {{{ proto float cos(float number)
183 : Returns the cosine of the number in radians */
184 : PHP_FUNCTION(cos)
185 0 : {
186 : zval **num;
187 :
188 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
189 0 : WRONG_PARAM_COUNT;
190 : }
191 0 : convert_to_double_ex(num);
192 0 : Z_DVAL_P(return_value) = cos(Z_DVAL_PP(num));
193 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
194 : }
195 : /* }}} */
196 :
197 : /* {{{ proto float tan(float number)
198 : Returns the tangent of the number in radians */
199 : PHP_FUNCTION(tan)
200 0 : {
201 : zval **num;
202 :
203 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
204 0 : WRONG_PARAM_COUNT;
205 : }
206 0 : convert_to_double_ex(num);
207 0 : Z_DVAL_P(return_value) = tan(Z_DVAL_PP(num));
208 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
209 : }
210 : /* }}} */
211 :
212 : /* {{{ proto float asin(float number)
213 : Returns the arc sine of the number in radians */
214 : PHP_FUNCTION(asin)
215 0 : {
216 : zval **num;
217 :
218 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
219 0 : WRONG_PARAM_COUNT;
220 : }
221 0 : convert_to_double_ex(num);
222 0 : Z_DVAL_P(return_value) = asin(Z_DVAL_PP(num));
223 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
224 : }
225 : /* }}} */
226 :
227 : /* {{{ proto float acos(float number)
228 : Return the arc cosine of the number in radians */
229 : PHP_FUNCTION(acos)
230 0 : {
231 : zval **num;
232 :
233 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
234 0 : WRONG_PARAM_COUNT;
235 : }
236 0 : convert_to_double_ex(num);
237 0 : Z_DVAL_P(return_value) = acos(Z_DVAL_PP(num));
238 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
239 : }
240 : /* }}} */
241 :
242 : /* {{{ proto float atan(float number)
243 : Returns the arc tangent of the number in radians */
244 : PHP_FUNCTION(atan)
245 0 : {
246 : zval **num;
247 :
248 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
249 0 : WRONG_PARAM_COUNT;
250 : }
251 0 : convert_to_double_ex(num);
252 0 : Z_DVAL_P(return_value) = atan(Z_DVAL_PP(num));
253 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
254 : }
255 : /* }}} */
256 :
257 : /* {{{ proto float atan2(float y, float x)
258 : Returns the arc tangent of y/x, with the resulting quadrant determined by the signs of y and x */
259 : PHP_FUNCTION(atan2)
260 0 : {
261 : zval **num1, **num2;
262 :
263 0 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &num1, &num2) == FAILURE) {
264 0 : WRONG_PARAM_COUNT;
265 : }
266 0 : convert_to_double_ex(num1);
267 0 : convert_to_double_ex(num2);
268 0 : Z_DVAL_P(return_value) = atan2(Z_DVAL_PP(num1), Z_DVAL_PP(num2));
269 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
270 : }
271 : /* }}} */
272 :
273 : /* {{{ proto float sinh(float number)
274 : Returns the hyperbolic sine of the number, defined as (exp(number) - exp(-number))/2 */
275 : PHP_FUNCTION(sinh)
276 0 : {
277 : zval **num;
278 :
279 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
280 0 : WRONG_PARAM_COUNT;
281 : }
282 0 : convert_to_double_ex(num);
283 0 : Z_DVAL_P(return_value) = sinh(Z_DVAL_PP(num));
284 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
285 : }
286 : /* }}} */
287 :
288 : /* {{{ proto float cosh(float number)
289 : Returns the hyperbolic cosine of the number, defined as (exp(number) + exp(-number))/2 */
290 : PHP_FUNCTION(cosh)
291 0 : {
292 : zval **num;
293 :
294 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
295 0 : WRONG_PARAM_COUNT;
296 : }
297 0 : convert_to_double_ex(num);
298 0 : Z_DVAL_P(return_value) = cosh(Z_DVAL_PP(num));
299 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
300 : }
301 : /* }}} */
302 :
303 : /* {{{ proto float tanh(float number)
304 : Returns the hyperbolic tangent of the number, defined as sinh(number)/cosh(number) */
305 : PHP_FUNCTION(tanh)
306 0 : {
307 : zval **num;
308 :
309 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
310 0 : WRONG_PARAM_COUNT;
311 : }
312 0 : convert_to_double_ex(num);
313 0 : Z_DVAL_P(return_value) = tanh(Z_DVAL_PP(num));
314 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
315 : }
316 : /* }}} */
317 :
318 : #if !defined(PHP_WIN32) && !defined(NETWARE)
319 : #ifdef HAVE_ASINH
320 : /* {{{ proto float asinh(float number)
321 : Returns the inverse hyperbolic sine of the number, i.e. the value whose hyperbolic sine is number */
322 : PHP_FUNCTION(asinh)
323 0 : {
324 : zval **num;
325 :
326 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
327 0 : WRONG_PARAM_COUNT;
328 : }
329 0 : convert_to_double_ex(num);
330 0 : Z_DVAL_P(return_value) = asinh(Z_DVAL_PP(num));
331 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
332 : }
333 : /* }}} */
334 : #endif /* HAVE_ASINH */
335 :
336 : #ifdef HAVE_ACOSH
337 : /* {{{ proto float acosh(float number)
338 : Returns the inverse hyperbolic cosine of the number, i.e. the value whose hyperbolic cosine is number */
339 : PHP_FUNCTION(acosh)
340 0 : {
341 : zval **num;
342 :
343 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
344 0 : WRONG_PARAM_COUNT;
345 : }
346 0 : convert_to_double_ex(num);
347 0 : Z_DVAL_P(return_value) = acosh(Z_DVAL_PP(num));
348 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
349 : }
350 : /* }}} */
351 : #endif /* HAVE_ACOSH */
352 :
353 : #ifdef HAVE_ATANH
354 : /* {{{ proto float atanh(float number)
355 : Returns the inverse hyperbolic tangent of the number, i.e. the value whose hyperbolic tangent is number */
356 : PHP_FUNCTION(atanh)
357 0 : {
358 : zval **num;
359 :
360 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
361 0 : WRONG_PARAM_COUNT;
362 : }
363 0 : convert_to_double_ex(num);
364 0 : Z_DVAL_P(return_value) = atanh(Z_DVAL_PP(num));
365 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
366 : }
367 : /* }}} */
368 : #endif /* HAVE_ATANH */
369 : #endif /* !defined(PHP_WIN32) && !defined(NETWARE) */
370 :
371 : /* {{{ proto float pi(void)
372 : Returns an approximation of pi */
373 : PHP_FUNCTION(pi)
374 0 : {
375 0 : Z_DVAL_P(return_value) = M_PI;
376 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
377 0 : }
378 : /* }}} */
379 :
380 : /* {{{ proto bool is_finite(float val)
381 : Returns whether argument is finite */
382 : PHP_FUNCTION(is_finite)
383 0 : {
384 : double dval;
385 :
386 :
387 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
388 0 : return;
389 : }
390 0 : RETURN_BOOL(zend_finite(dval));
391 : }
392 : /* }}} */
393 :
394 : /* {{{ proto bool is_infinite(float val)
395 : Returns whether argument is infinite */
396 : PHP_FUNCTION(is_infinite)
397 0 : {
398 : double dval;
399 :
400 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
401 0 : return;
402 : }
403 0 : RETURN_BOOL(zend_isinf(dval));
404 : }
405 : /* }}} */
406 :
407 : /* {{{ proto bool is_nan(float val)
408 : Returns whether argument is not a number */
409 : PHP_FUNCTION(is_nan)
410 0 : {
411 : double dval;
412 :
413 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &dval) == FAILURE) {
414 0 : return;
415 : }
416 0 : RETURN_BOOL(zend_isnan(dval));
417 : }
418 : /* }}} */
419 :
420 : /* {{{ proto number pow(number base, number exponent)
421 : Returns base raised to the power of exponent. Returns integer result when possible */
422 : PHP_FUNCTION(pow)
423 0 : {
424 : zval *zbase, *zexp;
425 :
426 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/", &zbase, &zexp) == FAILURE) {
427 0 : return;
428 : }
429 :
430 : /* make sure we're dealing with numbers */
431 0 : convert_scalar_to_number(zbase TSRMLS_CC);
432 0 : convert_scalar_to_number(zexp TSRMLS_CC);
433 :
434 : /* if both base and exponent were longs, we'll try to get a long out */
435 0 : if (Z_TYPE_P(zbase) == IS_LONG && Z_TYPE_P(zexp) == IS_LONG && Z_LVAL_P(zexp) >= 0) {
436 0 : long l1 = 1, l2 = Z_LVAL_P(zbase), i = Z_LVAL_P(zexp);
437 :
438 0 : if (i == 0) {
439 0 : RETURN_LONG(1L);
440 0 : } else if (l2 == 0) {
441 0 : RETURN_LONG(0);
442 : }
443 :
444 : /* calculate pow(long,long) in O(log exp) operations, bail if overflow */
445 0 : while (i >= 1) {
446 : int overflow;
447 0 : double dval = 0.0;
448 :
449 0 : if (i % 2) {
450 0 : --i;
451 0 : ZEND_SIGNED_MULTIPLY_LONG(l1,l2,l1,dval,overflow);
452 0 : if (overflow) RETURN_DOUBLE(dval * pow(l2,i));
453 : } else {
454 0 : i /= 2;
455 0 : ZEND_SIGNED_MULTIPLY_LONG(l2,l2,l2,dval,overflow);
456 0 : if (overflow) RETURN_DOUBLE((double)l1 * pow(dval,i));
457 : }
458 0 : if (i == 0) {
459 0 : RETURN_LONG(l1);
460 : }
461 : }
462 : }
463 0 : convert_to_double(zbase);
464 0 : convert_to_double(zexp);
465 :
466 0 : RETURN_DOUBLE( pow(Z_DVAL_P(zbase),Z_DVAL_P(zexp)) );
467 : }
468 : /* }}} */
469 :
470 : /* {{{ proto float exp(float number)
471 : Returns e raised to the power of the number */
472 : PHP_FUNCTION(exp)
473 0 : {
474 : zval **num;
475 :
476 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
477 0 : WRONG_PARAM_COUNT;
478 : }
479 0 : convert_to_double_ex(num);
480 0 : Z_DVAL_P(return_value) = exp(Z_DVAL_PP(num));
481 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
482 : }
483 : /* }}} */
484 :
485 : #if !defined(PHP_WIN32) && !defined(NETWARE)
486 : /* {{{ proto float expm1(float number)
487 : Returns exp(number) - 1, computed in a way that accurate even when the value of number is close to zero */
488 : /*
489 : WARNING: this function is expermental: it could change its name or
490 : disappear in the next version of PHP!
491 : */
492 : PHP_FUNCTION(expm1)
493 0 : {
494 : zval **num;
495 :
496 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
497 0 : WRONG_PARAM_COUNT;
498 : }
499 0 : convert_to_double_ex(num);
500 0 : Z_DVAL_P(return_value) = expm1(Z_DVAL_PP(num));
501 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
502 : }
503 : /* }}} */
504 :
505 : #ifdef HAVE_LOG1P
506 : /* {{{ proto float log1p(float number)
507 : Returns log(1 + number), computed in a way that accurate even when the value of number is close to zero */
508 : /*
509 : WARNING: this function is expermental: it could change its name or
510 : disappear in the next version of PHP!
511 : */
512 : PHP_FUNCTION(log1p)
513 0 : {
514 : zval **num;
515 :
516 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
517 0 : WRONG_PARAM_COUNT;
518 : }
519 0 : convert_to_double_ex(num);
520 0 : Z_DVAL_P(return_value) = log1p(Z_DVAL_PP(num));
521 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
522 : }
523 : /* }}} */
524 : #endif /* HAVE_LOG1P */
525 : #endif /* !defined(PHP_WIN32) && !defined(NETWARE) */
526 :
527 : /* {{{ proto float log(float number, [float base])
528 : Returns the natural logarithm of the number, or the base log if base is specified */
529 : PHP_FUNCTION(log)
530 0 : {
531 : zval **num, **base;
532 :
533 0 : switch (ZEND_NUM_ARGS()) {
534 : case 1:
535 0 : if (zend_get_parameters_ex(1, &num) == FAILURE) {
536 0 : WRONG_PARAM_COUNT;
537 : }
538 0 : convert_to_double_ex(num);
539 0 : RETURN_DOUBLE(log(Z_DVAL_PP(num)));
540 : case 2:
541 0 : if (zend_get_parameters_ex(2, &num, &base) == FAILURE) {
542 0 : WRONG_PARAM_COUNT;
543 : }
544 0 : convert_to_double_ex(num);
545 0 : convert_to_double_ex(base);
546 :
547 0 : if (Z_DVAL_PP(base) <= 0.0) {
548 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "base must be greater than 0");
549 0 : RETURN_FALSE;
550 : }
551 0 : RETURN_DOUBLE(log(Z_DVAL_PP(num)) / log(Z_DVAL_PP(base)));
552 : default:
553 0 : WRONG_PARAM_COUNT;
554 : }
555 : }
556 : /* }}} */
557 :
558 : /* {{{ proto float log10(float number)
559 : Returns the base-10 logarithm of the number */
560 : PHP_FUNCTION(log10)
561 0 : {
562 : zval **num;
563 :
564 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
565 0 : WRONG_PARAM_COUNT;
566 : }
567 0 : convert_to_double_ex(num);
568 0 : Z_DVAL_P(return_value) = log10(Z_DVAL_PP(num));
569 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
570 : }
571 : /* }}} */
572 :
573 : /* {{{ proto float sqrt(float number)
574 : Returns the square root of the number */
575 : PHP_FUNCTION(sqrt)
576 0 : {
577 : zval **num;
578 :
579 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
580 0 : WRONG_PARAM_COUNT;
581 : }
582 0 : convert_to_double_ex(num);
583 0 : Z_DVAL_P(return_value) = sqrt(Z_DVAL_PP(num));
584 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
585 : }
586 : /* }}} */
587 :
588 : /* {{{ proto float hypot(float num1, float num2)
589 : Returns sqrt(num1*num1 + num2*num2) */
590 : PHP_FUNCTION(hypot)
591 0 : {
592 : zval **num1, **num2;
593 :
594 0 : if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &num1, &num2) == FAILURE) {
595 0 : WRONG_PARAM_COUNT;
596 : }
597 0 : convert_to_double_ex(num1);
598 0 : convert_to_double_ex(num2);
599 : #if HAVE_HYPOT
600 0 : Z_DVAL_P(return_value) = hypot(Z_DVAL_PP(num1), Z_DVAL_PP(num2));
601 : #elif defined(_MSC_VER)
602 : Z_DVAL_P(return_value) = _hypot(Z_DVAL_PP(num1), Z_DVAL_PP(num2));
603 : #else
604 : Z_DVAL_P(return_value) = sqrt((Z_DVAL_PP(num1) * Z_DVAL_PP(num1)) +
605 : (Z_DVAL_PP(num2) * Z_DVAL_PP(num2)));
606 : #endif
607 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
608 : }
609 : /* }}} */
610 :
611 : /* {{{ proto float deg2rad(float number)
612 : Converts the number in degrees to the radian equivalent */
613 : PHP_FUNCTION(deg2rad)
614 0 : {
615 : zval **deg;
616 :
617 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, °) == FAILURE) {
618 0 : WRONG_PARAM_COUNT;
619 : }
620 0 : convert_to_double_ex(deg);
621 0 : RETVAL_DOUBLE((Z_DVAL_PP(deg) / 180.0) * M_PI);
622 : }
623 : /* }}} */
624 :
625 : /* {{{ proto float rad2deg(float number)
626 : Converts the radian number to the equivalent number in degrees */
627 : PHP_FUNCTION(rad2deg)
628 0 : {
629 : zval **rad;
630 :
631 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &rad) == FAILURE) {
632 0 : WRONG_PARAM_COUNT;
633 : }
634 0 : convert_to_double_ex(rad);
635 0 : RETVAL_DOUBLE((Z_DVAL_PP(rad) / M_PI) * 180);
636 : }
637 : /* }}} */
638 :
639 : /* {{{ _php_math_basetolong */
640 : /*
641 : * Convert a string representation of a base(2-36) number to a long.
642 : */
643 : PHPAPI long _php_math_basetolong(zval *arg, int base)
644 0 : {
645 0 : long num = 0, digit, onum;
646 : int i;
647 : char c, *s;
648 :
649 0 : if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
650 0 : return 0;
651 : }
652 :
653 0 : s = Z_STRVAL_P(arg);
654 :
655 0 : for (i = Z_STRLEN_P(arg); i > 0; i--) {
656 0 : c = *s++;
657 :
658 0 : digit = (c >= '0' && c <= '9') ? c - '0'
659 : : (c >= 'A' && c <= 'Z') ? c - 'A' + 10
660 : : (c >= 'a' && c <= 'z') ? c - 'a' + 10
661 : : base;
662 :
663 0 : if (digit >= base) {
664 0 : continue;
665 : }
666 :
667 0 : onum = num;
668 0 : num = num * base + digit;
669 0 : if (num > onum)
670 0 : continue;
671 :
672 : {
673 : TSRMLS_FETCH();
674 :
675 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number '%s' is too big to fit in long", s);
676 0 : return LONG_MAX;
677 : }
678 : }
679 :
680 0 : return num;
681 : }
682 : /* }}} */
683 :
684 : /* {{{ _php_math_basetozval */
685 : /*
686 : * Convert a string representation of a base(2-36) number to a zval.
687 : */
688 : PHPAPI int _php_math_basetozval(zval *arg, int base, zval *ret)
689 0 : {
690 0 : long num = 0;
691 0 : double fnum = 0;
692 : int i;
693 0 : int mode = 0;
694 : char c, *s;
695 : long cutoff;
696 : int cutlim;
697 :
698 0 : if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
699 0 : return FAILURE;
700 : }
701 :
702 0 : s = Z_STRVAL_P(arg);
703 :
704 0 : cutoff = LONG_MAX / base;
705 0 : cutlim = LONG_MAX % base;
706 :
707 0 : for (i = Z_STRLEN_P(arg); i > 0; i--) {
708 0 : c = *s++;
709 :
710 : /* might not work for EBCDIC */
711 0 : if (c >= '0' && c <= '9')
712 0 : c -= '0';
713 0 : else if (c >= 'A' && c <= 'Z')
714 0 : c -= 'A' - 10;
715 0 : else if (c >= 'a' && c <= 'z')
716 0 : c -= 'a' - 10;
717 : else
718 : continue;
719 :
720 0 : if (c >= base)
721 0 : continue;
722 :
723 0 : switch (mode) {
724 : case 0: /* Integer */
725 0 : if (num < cutoff || (num == cutoff && c <= cutlim)) {
726 0 : num = num * base + c;
727 0 : break;
728 : } else {
729 0 : fnum = num;
730 0 : mode = 1;
731 : }
732 : /* fall-through */
733 : case 1: /* Float */
734 0 : fnum = fnum * base + c;
735 : }
736 : }
737 :
738 0 : if (mode == 1) {
739 0 : ZVAL_DOUBLE(ret, fnum);
740 : } else {
741 0 : ZVAL_LONG(ret, num);
742 : }
743 0 : return SUCCESS;
744 : }
745 : /* }}} */
746 :
747 : /* {{{ _php_math_longtobase */
748 : /*
749 : * Convert a long to a string containing a base(2-36) representation of
750 : * the number.
751 : */
752 : PHPAPI char * _php_math_longtobase(zval *arg, int base)
753 0 : {
754 : static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
755 : char buf[(sizeof(unsigned long) << 3) + 1];
756 : char *ptr, *end;
757 : unsigned long value;
758 :
759 0 : if (Z_TYPE_P(arg) != IS_LONG || base < 2 || base > 36) {
760 0 : return STR_EMPTY_ALLOC();
761 : }
762 :
763 0 : value = Z_LVAL_P(arg);
764 :
765 0 : end = ptr = buf + sizeof(buf) - 1;
766 0 : *ptr = '\0';
767 :
768 : do {
769 0 : *--ptr = digits[value % base];
770 0 : value /= base;
771 0 : } while (ptr > buf && value);
772 :
773 0 : return estrndup(ptr, end - ptr);
774 : }
775 : /* }}} */
776 :
777 : /* {{{ _php_math_zvaltobase */
778 : /*
779 : * Convert a zval to a string containing a base(2-36) representation of
780 : * the number.
781 : */
782 : PHPAPI char * _php_math_zvaltobase(zval *arg, int base TSRMLS_DC)
783 0 : {
784 : static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
785 :
786 0 : if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) {
787 0 : return STR_EMPTY_ALLOC();
788 : }
789 :
790 0 : if (Z_TYPE_P(arg) == IS_DOUBLE) {
791 0 : double fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */
792 : char *ptr, *end;
793 : char buf[(sizeof(double) << 3) + 1];
794 :
795 : /* Don't try to convert +/- infinity */
796 0 : if (fvalue == HUGE_VAL || fvalue == -HUGE_VAL) {
797 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number too large");
798 0 : return STR_EMPTY_ALLOC();
799 : }
800 :
801 0 : end = ptr = buf + sizeof(buf) - 1;
802 0 : *ptr = '\0';
803 :
804 : do {
805 0 : *--ptr = digits[(int) fmod(fvalue, base)];
806 0 : fvalue /= base;
807 0 : } while (ptr > buf && fabs(fvalue) >= 1);
808 :
809 0 : return estrndup(ptr, end - ptr);
810 : }
811 :
812 0 : return _php_math_longtobase(arg, base);
813 : }
814 : /* }}} */
815 :
816 : /* {{{ proto int bindec(string binary_number)
817 : Returns the decimal equivalent of the binary number */
818 : PHP_FUNCTION(bindec)
819 0 : {
820 : zval **arg;
821 :
822 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
823 0 : WRONG_PARAM_COUNT;
824 : }
825 :
826 0 : convert_to_string_ex(arg);
827 0 : if(_php_math_basetozval(*arg, 2, return_value) != SUCCESS) {
828 0 : RETURN_FALSE;
829 : }
830 : }
831 : /* }}} */
832 :
833 : /* {{{ proto int hexdec(string hexadecimal_number)
834 : Returns the decimal equivalent of the hexadecimal number */
835 : PHP_FUNCTION(hexdec)
836 0 : {
837 : zval **arg;
838 :
839 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
840 0 : WRONG_PARAM_COUNT;
841 : }
842 :
843 0 : convert_to_string_ex(arg);
844 :
845 0 : if(_php_math_basetozval(*arg, 16, return_value) != SUCCESS) {
846 0 : RETURN_FALSE;
847 : }
848 : }
849 : /* }}} */
850 :
851 : /* {{{ proto int octdec(string octal_number)
852 : Returns the decimal equivalent of an octal string */
853 : PHP_FUNCTION(octdec)
854 0 : {
855 : zval **arg;
856 :
857 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
858 0 : WRONG_PARAM_COUNT;
859 : }
860 :
861 0 : convert_to_string_ex(arg);
862 :
863 0 : if(_php_math_basetozval(*arg, 8, return_value) != SUCCESS) {
864 0 : RETURN_FALSE;
865 : }
866 : }
867 : /* }}} */
868 :
869 : /* {{{ proto string decbin(int decimal_number)
870 : Returns a string containing a binary representation of the number */
871 : PHP_FUNCTION(decbin)
872 0 : {
873 : zval **arg;
874 : char *result;
875 :
876 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
877 0 : WRONG_PARAM_COUNT;
878 : }
879 :
880 0 : convert_to_long_ex(arg);
881 :
882 0 : result = _php_math_longtobase(*arg, 2);
883 0 : Z_TYPE_P(return_value) = IS_STRING;
884 0 : Z_STRLEN_P(return_value) = strlen(result);
885 0 : Z_STRVAL_P(return_value) = result;
886 : }
887 : /* }}} */
888 :
889 : /* {{{ proto string decoct(int decimal_number)
890 : Returns a string containing an octal representation of the given number */
891 : PHP_FUNCTION(decoct)
892 0 : {
893 : zval **arg;
894 : char *result;
895 :
896 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
897 0 : WRONG_PARAM_COUNT;
898 : }
899 :
900 0 : convert_to_long_ex(arg);
901 :
902 0 : result = _php_math_longtobase(*arg, 8);
903 0 : Z_TYPE_P(return_value) = IS_STRING;
904 0 : Z_STRLEN_P(return_value) = strlen(result);
905 0 : Z_STRVAL_P(return_value) = result;
906 : }
907 : /* }}} */
908 :
909 : /* {{{ proto string dechex(int decimal_number)
910 : Returns a string containing a hexadecimal representation of the given number */
911 : PHP_FUNCTION(dechex)
912 0 : {
913 : zval **arg;
914 : char *result;
915 :
916 0 : if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
917 0 : WRONG_PARAM_COUNT;
918 : }
919 :
920 0 : convert_to_long_ex(arg);
921 :
922 0 : result = _php_math_longtobase(*arg, 16);
923 0 : Z_TYPE_P(return_value) = IS_STRING;
924 0 : Z_STRLEN_P(return_value) = strlen(result);
925 0 : Z_STRVAL_P(return_value) = result;
926 : }
927 : /* }}} */
928 :
929 : /* {{{ proto string base_convert(string number, int frombase, int tobase)
930 : Converts a number in a string from any base <= 36 to any base <= 36 */
931 : PHP_FUNCTION(base_convert)
932 0 : {
933 : zval **number, **frombase, **tobase, temp;
934 : char *result;
935 :
936 0 : if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &number, &frombase, &tobase) == FAILURE) {
937 0 : WRONG_PARAM_COUNT;
938 : }
939 0 : convert_to_string_ex(number);
940 0 : convert_to_long_ex(frombase);
941 0 : convert_to_long_ex(tobase);
942 0 : if (Z_LVAL_PP(frombase) < 2 || Z_LVAL_PP(frombase) > 36) {
943 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `from base' (%ld)", Z_LVAL_PP(frombase));
944 0 : RETURN_FALSE;
945 : }
946 0 : if (Z_LVAL_PP(tobase) < 2 || Z_LVAL_PP(tobase) > 36) {
947 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid `to base' (%ld)", Z_LVAL_PP(tobase));
948 0 : RETURN_FALSE;
949 : }
950 :
951 0 : if(_php_math_basetozval(*number, Z_LVAL_PP(frombase), &temp) != SUCCESS) {
952 0 : RETURN_FALSE;
953 : }
954 0 : result = _php_math_zvaltobase(&temp, Z_LVAL_PP(tobase) TSRMLS_CC);
955 0 : RETVAL_STRING(result, 0);
956 : }
957 : /* }}} */
958 :
959 : /* {{{ _php_math_number_format
960 : */
961 : PHPAPI char *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep)
962 0 : {
963 0 : char *tmpbuf = NULL, *resbuf;
964 : char *s, *t; /* source, target */
965 : char *dp;
966 : int integral;
967 0 : int tmplen, reslen=0;
968 0 : int count=0;
969 0 : int is_negative=0;
970 :
971 0 : if (d < 0) {
972 0 : is_negative = 1;
973 0 : d = -d;
974 : }
975 :
976 0 : dec = MAX(0, dec);
977 0 : PHP_ROUND_WITH_FUZZ(d, dec);
978 :
979 0 : tmplen = spprintf(&tmpbuf, 0, "%.*F", dec, d);
980 :
981 0 : if (tmpbuf == NULL || !isdigit((int)tmpbuf[0])) {
982 0 : return tmpbuf;
983 : }
984 :
985 : /* find decimal point, if expected */
986 0 : if (dec) {
987 0 : dp = strpbrk(tmpbuf, ".,");
988 : } else {
989 0 : dp = NULL;
990 : }
991 :
992 : /* calculate the length of the return buffer */
993 0 : if (dp) {
994 0 : integral = dp - tmpbuf;
995 : } else {
996 : /* no decimal point was found */
997 0 : integral = tmplen;
998 : }
999 :
1000 : /* allow for thousand separators */
1001 0 : if (thousand_sep) {
1002 0 : integral += (integral-1) / 3;
1003 : }
1004 :
1005 0 : reslen = integral;
1006 :
1007 0 : if (dec) {
1008 0 : reslen += dec;
1009 :
1010 0 : if (dec_point) {
1011 0 : reslen++;
1012 : }
1013 : }
1014 :
1015 : /* add a byte for minus sign */
1016 0 : if (is_negative) {
1017 0 : reslen++;
1018 : }
1019 0 : resbuf = (char *) emalloc(reslen+1); /* +1 for NUL terminator */
1020 :
1021 0 : s = tmpbuf+tmplen-1;
1022 0 : t = resbuf+reslen;
1023 0 : *t-- = '\0';
1024 :
1025 : /* copy the decimal places.
1026 : * Take care, as the sprintf implementation may return less places than
1027 : * we requested due to internal buffer limitations */
1028 0 : if (dec) {
1029 0 : int declen = dp ? s - dp : 0;
1030 0 : int topad = dec > declen ? dec - declen : 0;
1031 :
1032 : /* pad with '0's */
1033 0 : while (topad--) {
1034 0 : *t-- = '0';
1035 : }
1036 :
1037 0 : if (dp) {
1038 0 : s -= declen + 1; /* +1 to skip the point */
1039 0 : t -= declen;
1040 :
1041 : /* now copy the chars after the point */
1042 0 : memcpy(t + 1, dp + 1, declen);
1043 : }
1044 :
1045 : /* add decimal point */
1046 0 : if (dec_point) {
1047 0 : *t-- = dec_point;
1048 : }
1049 : }
1050 :
1051 : /* copy the numbers before the decimal point, adding thousand
1052 : * separator every three digits */
1053 0 : while(s >= tmpbuf) {
1054 0 : *t-- = *s--;
1055 0 : if (thousand_sep && (++count%3)==0 && s>=tmpbuf) {
1056 0 : *t-- = thousand_sep;
1057 : }
1058 : }
1059 :
1060 : /* and a minus sign, if needed */
1061 0 : if (is_negative) {
1062 0 : *t-- = '-';
1063 : }
1064 :
1065 0 : efree(tmpbuf);
1066 :
1067 0 : return resbuf;
1068 : }
1069 : /* }}} */
1070 :
1071 : /* {{{ proto string number_format(float number [, int num_decimal_places [, string dec_seperator, string thousands_seperator]])
1072 : Formats a number with grouped thousands */
1073 : PHP_FUNCTION(number_format)
1074 0 : {
1075 : zval **num, **dec, **t_s, **d_p;
1076 0 : char thousand_sep=',', dec_point='.';
1077 :
1078 0 : switch(ZEND_NUM_ARGS()) {
1079 : case 1:
1080 0 : if (zend_get_parameters_ex(1, &num)==FAILURE) {
1081 0 : RETURN_FALSE;
1082 : }
1083 0 : convert_to_double_ex(num);
1084 0 : RETURN_STRING(_php_math_number_format(Z_DVAL_PP(num), 0, dec_point, thousand_sep), 0);
1085 : break;
1086 : case 2:
1087 0 : if (zend_get_parameters_ex(2, &num, &dec)==FAILURE) {
1088 0 : RETURN_FALSE;
1089 : }
1090 0 : convert_to_double_ex(num);
1091 0 : convert_to_long_ex(dec);
1092 0 : RETURN_STRING(_php_math_number_format(Z_DVAL_PP(num), Z_LVAL_PP(dec), dec_point, thousand_sep), 0);
1093 : break;
1094 : case 4:
1095 0 : if (zend_get_parameters_ex(4, &num, &dec, &d_p, &t_s)==FAILURE) {
1096 0 : RETURN_FALSE;
1097 : }
1098 0 : convert_to_double_ex(num);
1099 0 : convert_to_long_ex(dec);
1100 :
1101 0 : if (Z_TYPE_PP(d_p) != IS_NULL) {
1102 0 : convert_to_string_ex(d_p);
1103 0 : if (Z_STRLEN_PP(d_p)>=1) {
1104 0 : dec_point=Z_STRVAL_PP(d_p)[0];
1105 0 : } else if (Z_STRLEN_PP(d_p)==0) {
1106 0 : dec_point=0;
1107 : }
1108 : }
1109 0 : if (Z_TYPE_PP(t_s) != IS_NULL) {
1110 0 : convert_to_string_ex(t_s);
1111 0 : if (Z_STRLEN_PP(t_s)>=1) {
1112 0 : thousand_sep=Z_STRVAL_PP(t_s)[0];
1113 0 : } else if(Z_STRLEN_PP(t_s)==0) {
1114 0 : thousand_sep=0;
1115 : }
1116 : }
1117 0 : RETURN_STRING(_php_math_number_format(Z_DVAL_PP(num), Z_LVAL_PP(dec), dec_point, thousand_sep), 0);
1118 : break;
1119 : default:
1120 0 : WRONG_PARAM_COUNT;
1121 : break;
1122 : }
1123 : }
1124 : /* }}} */
1125 :
1126 : /* {{{ proto float fmod(float x, float y)
1127 : Returns the remainder of dividing x by y as a float */
1128 : PHP_FUNCTION(fmod)
1129 0 : {
1130 : double num1, num2;
1131 :
1132 0 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd", &num1, &num2) == FAILURE) {
1133 0 : return;
1134 : }
1135 :
1136 0 : Z_DVAL_P(return_value) = fmod(num1, num2);
1137 0 : Z_TYPE_P(return_value) = IS_DOUBLE;
1138 : }
1139 : /* }}} */
1140 :
1141 :
1142 :
1143 : /*
1144 : * Local variables:
1145 : * tab-width: 4
1146 : * c-basic-offset: 4
1147 : * End:
1148 : * vim600: fdm=marker
1149 : * vim: noet sw=4 ts=4
1150 : */
|