12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217 |
- #include "php.h"
- #include "php_math.h"
- #include "zend_multiply.h"
- #include "zend_exceptions.h"
- #include "zend_portability.h"
- #include "zend_bitset.h"
- #include <math.h>
- #include <float.h>
- #include <stdlib.h>
- #include "basic_functions.h"
- static inline int php_intlog10abs(double value) {
- int result;
- value = fabs(value);
- if (value < 1e-8 || value > 1e22) {
- result = (int)floor(log10(value));
- } else {
- static const double values[] = {
- 1e-8, 1e-7, 1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1,
- 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
- 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
- 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
-
- result = 15;
- if (value < values[result]) {
- result -= 8;
- } else {
- result += 8;
- }
- if (value < values[result]) {
- result -= 4;
- } else {
- result += 4;
- }
- if (value < values[result]) {
- result -= 2;
- } else {
- result += 2;
- }
- if (value < values[result]) {
- result -= 1;
- } else {
- result += 1;
- }
- if (value < values[result]) {
- result -= 1;
- }
- result -= 8;
- }
- return result;
- }
- static inline double php_intpow10(int power) {
- static const double powers[] = {
- 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7,
- 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15,
- 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22};
-
- if (power < 0 || power > 22) {
- return pow(10.0, (double)power);
- }
- return powers[power];
- }
- static inline double php_round_helper(double value, int mode) {
- double tmp_value;
- if (value >= 0.0) {
- tmp_value = floor(value + 0.5);
- if ((mode == PHP_ROUND_HALF_DOWN && value == (-0.5 + tmp_value)) ||
- (mode == PHP_ROUND_HALF_EVEN && value == (0.5 + 2 * floor(tmp_value/2.0))) ||
- (mode == PHP_ROUND_HALF_ODD && value == (0.5 + 2 * floor(tmp_value/2.0) - 1.0)))
- {
- tmp_value = tmp_value - 1.0;
- }
- } else {
- tmp_value = ceil(value - 0.5);
- if ((mode == PHP_ROUND_HALF_DOWN && value == (0.5 + tmp_value)) ||
- (mode == PHP_ROUND_HALF_EVEN && value == (-0.5 + 2 * ceil(tmp_value/2.0))) ||
- (mode == PHP_ROUND_HALF_ODD && value == (-0.5 + 2 * ceil(tmp_value/2.0) + 1.0)))
- {
- tmp_value = tmp_value + 1.0;
- }
- }
- return tmp_value;
- }
- PHPAPI double _php_math_round(double value, int places, int mode) {
- double f1, f2;
- double tmp_value;
- int precision_places;
- if (!zend_finite(value) || value == 0.0) {
- return value;
- }
- places = places < INT_MIN+1 ? INT_MIN+1 : places;
- precision_places = 14 - php_intlog10abs(value);
- f1 = php_intpow10(abs(places));
-
- if (precision_places > places && precision_places - 15 < places) {
- int64_t use_precision = precision_places < INT_MIN+1 ? INT_MIN+1 : precision_places;
- f2 = php_intpow10(abs((int)use_precision));
- if (use_precision >= 0) {
- tmp_value = value * f2;
- } else {
- tmp_value = value / f2;
- }
-
- tmp_value = php_round_helper(tmp_value, mode);
- use_precision = places - precision_places;
- use_precision = use_precision < INT_MIN+1 ? INT_MIN+1 : use_precision;
-
- f2 = php_intpow10(abs((int)use_precision));
-
- tmp_value = tmp_value / f2;
- } else {
-
- if (places >= 0) {
- tmp_value = value * f1;
- } else {
- tmp_value = value / f1;
- }
-
- if (fabs(tmp_value) >= 1e15) {
- return value;
- }
- }
-
- tmp_value = php_round_helper(tmp_value, mode);
-
- if (abs(places) < 23) {
- if (places > 0) {
- tmp_value = tmp_value / f1;
- } else {
- tmp_value = tmp_value * f1;
- }
- } else {
-
-
- char buf[40];
- snprintf(buf, 39, "%15fe%d", tmp_value, -places);
- buf[39] = '\0';
- tmp_value = zend_strtod(buf, NULL);
-
- if (!zend_finite(tmp_value) || zend_isnan(tmp_value)) {
- tmp_value = value;
- }
- }
- return tmp_value;
- }
- PHP_FUNCTION(abs)
- {
- zval *value;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_NUMBER(value)
- ZEND_PARSE_PARAMETERS_END();
- if (Z_TYPE_P(value) == IS_DOUBLE) {
- RETURN_DOUBLE(fabs(Z_DVAL_P(value)));
- } else if (Z_TYPE_P(value) == IS_LONG) {
- if (Z_LVAL_P(value) == ZEND_LONG_MIN) {
- RETURN_DOUBLE(-(double)ZEND_LONG_MIN);
- } else {
- RETURN_LONG(Z_LVAL_P(value) < 0 ? -Z_LVAL_P(value) : Z_LVAL_P(value));
- }
- } else {
- ZEND_ASSERT(0 && "Unexpected type");
- }
- }
- PHP_FUNCTION(ceil)
- {
- zval *value;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_NUMBER(value)
- ZEND_PARSE_PARAMETERS_END();
- if (Z_TYPE_P(value) == IS_DOUBLE) {
- RETURN_DOUBLE(ceil(Z_DVAL_P(value)));
- } else if (Z_TYPE_P(value) == IS_LONG) {
- RETURN_DOUBLE(zval_get_double(value));
- } else {
- ZEND_ASSERT(0 && "Unexpected type");
- }
- }
- PHP_FUNCTION(floor)
- {
- zval *value;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_NUMBER(value)
- ZEND_PARSE_PARAMETERS_END();
- if (Z_TYPE_P(value) == IS_DOUBLE) {
- RETURN_DOUBLE(floor(Z_DVAL_P(value)));
- } else if (Z_TYPE_P(value) == IS_LONG) {
- RETURN_DOUBLE(zval_get_double(value));
- } else {
- ZEND_ASSERT(0 && "Unexpected type");
- }
- }
- PHP_FUNCTION(round)
- {
- zval *value;
- int places = 0;
- zend_long precision = 0;
- zend_long mode = PHP_ROUND_HALF_UP;
- double return_val;
- ZEND_PARSE_PARAMETERS_START(1, 3)
- Z_PARAM_NUMBER(value)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(precision)
- Z_PARAM_LONG(mode)
- ZEND_PARSE_PARAMETERS_END();
- if (ZEND_NUM_ARGS() >= 2) {
- #if SIZEOF_ZEND_LONG > SIZEOF_INT
- if (precision >= 0) {
- places = precision > INT_MAX ? INT_MAX : (int)precision;
- } else {
- places = precision <= INT_MIN ? INT_MIN+1 : (int)precision;
- }
- #else
- places = precision;
- #endif
- }
- switch (Z_TYPE_P(value)) {
- case IS_LONG:
-
- if (places >= 0) {
- RETURN_DOUBLE((double) Z_LVAL_P(value));
- }
- ZEND_FALLTHROUGH;
- case IS_DOUBLE:
- return_val = (Z_TYPE_P(value) == IS_LONG) ? (double)Z_LVAL_P(value) : Z_DVAL_P(value);
- return_val = _php_math_round(return_val, (int)places, (int)mode);
- RETURN_DOUBLE(return_val);
- break;
- EMPTY_SWITCH_DEFAULT_CASE()
- }
- }
- PHP_FUNCTION(sin)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(sin(num));
- }
- PHP_FUNCTION(cos)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(cos(num));
- }
- PHP_FUNCTION(tan)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(tan(num));
- }
- PHP_FUNCTION(asin)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(asin(num));
- }
- PHP_FUNCTION(acos)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(acos(num));
- }
- PHP_FUNCTION(atan)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(atan(num));
- }
- PHP_FUNCTION(atan2)
- {
- double num1, num2;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_DOUBLE(num1)
- Z_PARAM_DOUBLE(num2)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(atan2(num1, num2));
- }
- PHP_FUNCTION(sinh)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(sinh(num));
- }
- PHP_FUNCTION(cosh)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(cosh(num));
- }
- PHP_FUNCTION(tanh)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(tanh(num));
- }
- PHP_FUNCTION(asinh)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(asinh(num));
- }
- PHP_FUNCTION(acosh)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(acosh(num));
- }
- PHP_FUNCTION(atanh)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(atanh(num));
- }
- PHP_FUNCTION(pi)
- {
- ZEND_PARSE_PARAMETERS_NONE();
- RETURN_DOUBLE(M_PI);
- }
- PHP_FUNCTION(is_finite)
- {
- double dval;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(dval)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_BOOL(zend_finite(dval));
- }
- PHP_FUNCTION(is_infinite)
- {
- double dval;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(dval)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_BOOL(zend_isinf(dval));
- }
- PHP_FUNCTION(is_nan)
- {
- double dval;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(dval)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_BOOL(zend_isnan(dval));
- }
- PHP_FUNCTION(pow)
- {
- zval *zbase, *zexp;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_ZVAL(zbase)
- Z_PARAM_ZVAL(zexp)
- ZEND_PARSE_PARAMETERS_END();
- pow_function(return_value, zbase, zexp);
- }
- PHP_FUNCTION(exp)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(exp(num));
- }
- PHP_FUNCTION(expm1)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(expm1(num));
- }
- PHP_FUNCTION(log1p)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(log1p(num));
- }
- PHP_FUNCTION(log)
- {
- double num, base = 0;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_DOUBLE(num)
- Z_PARAM_OPTIONAL
- Z_PARAM_DOUBLE(base)
- ZEND_PARSE_PARAMETERS_END();
- if (ZEND_NUM_ARGS() == 1) {
- RETURN_DOUBLE(log(num));
- }
- if (base == 2.0) {
- RETURN_DOUBLE(log2(num));
- }
- if (base == 10.0) {
- RETURN_DOUBLE(log10(num));
- }
- if (base == 1.0) {
- RETURN_DOUBLE(ZEND_NAN);
- }
- if (base <= 0.0) {
- zend_argument_value_error(2, "must be greater than 0");
- RETURN_THROWS();
- }
- RETURN_DOUBLE(log(num) / log(base));
- }
- PHP_FUNCTION(log10)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(log10(num));
- }
- PHP_FUNCTION(sqrt)
- {
- double num;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(num)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(sqrt(num));
- }
- PHP_FUNCTION(hypot)
- {
- double num1, num2;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_DOUBLE(num1)
- Z_PARAM_DOUBLE(num2)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(hypot(num1, num2));
- }
- PHP_FUNCTION(deg2rad)
- {
- double deg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(deg)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE((deg / 180.0) * M_PI);
- }
- PHP_FUNCTION(rad2deg)
- {
- double rad;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_DOUBLE(rad)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE((rad / M_PI) * 180);
- }
- PHPAPI zend_long _php_math_basetolong(zval *arg, int base)
- {
- zend_long num = 0, digit, onum;
- zend_long i;
- char c, *s;
- if (Z_TYPE_P(arg) != IS_STRING || base < 2 || base > 36) {
- return 0;
- }
- s = Z_STRVAL_P(arg);
- for (i = Z_STRLEN_P(arg); i > 0; i--) {
- c = *s++;
- digit = (c >= '0' && c <= '9') ? c - '0'
- : (c >= 'A' && c <= 'Z') ? c - 'A' + 10
- : (c >= 'a' && c <= 'z') ? c - 'a' + 10
- : base;
- if (digit >= base) {
- continue;
- }
- onum = num;
- num = num * base + digit;
- if (num > onum)
- continue;
- {
- php_error_docref(NULL, E_WARNING, "Number %s is too big to fit in long", s);
- return ZEND_LONG_MAX;
- }
- }
- return num;
- }
- PHPAPI void _php_math_basetozval(zend_string *str, int base, zval *ret)
- {
- zend_long num = 0;
- double fnum = 0;
- int mode = 0;
- char c, *s, *e;
- zend_long cutoff;
- int cutlim;
- int invalidchars = 0;
- s = ZSTR_VAL(str);
- e = s + ZSTR_LEN(str);
-
- while (s < e && isspace(*s)) s++;
-
- while (s < e && isspace(*(e-1))) e--;
- if (e - s >= 2) {
- if (base == 16 && s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) s += 2;
- if (base == 8 && s[0] == '0' && (s[1] == 'o' || s[1] == 'O')) s += 2;
- if (base == 2 && s[0] == '0' && (s[1] == 'b' || s[1] == 'B')) s += 2;
- }
- cutoff = ZEND_LONG_MAX / base;
- cutlim = ZEND_LONG_MAX % base;
- while (s < e) {
- c = *s++;
-
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'A' && c <= 'Z')
- c -= 'A' - 10;
- else if (c >= 'a' && c <= 'z')
- c -= 'a' - 10;
- else {
- invalidchars++;
- continue;
- }
- if (c >= base) {
- invalidchars++;
- continue;
- }
- switch (mode) {
- case 0:
- if (num < cutoff || (num == cutoff && c <= cutlim)) {
- num = num * base + c;
- break;
- } else {
- fnum = (double)num;
- mode = 1;
- }
- ZEND_FALLTHROUGH;
- case 1:
- fnum = fnum * base + c;
- }
- }
- if (invalidchars > 0) {
- zend_error(E_DEPRECATED, "Invalid characters passed for attempted conversion, these have been ignored");
- }
- if (mode == 1) {
- ZVAL_DOUBLE(ret, fnum);
- } else {
- ZVAL_LONG(ret, num);
- }
- }
- PHPAPI zend_string * _php_math_longtobase(zend_long arg, int base)
- {
- static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- char buf[(sizeof(zend_ulong) << 3) + 1];
- char *ptr, *end;
- zend_ulong value;
- if (base < 2 || base > 36) {
- return ZSTR_EMPTY_ALLOC();
- }
- value = arg;
- end = ptr = buf + sizeof(buf) - 1;
- *ptr = '\0';
- do {
- ZEND_ASSERT(ptr > buf);
- *--ptr = digits[value % base];
- value /= base;
- } while (value);
- return zend_string_init(ptr, end - ptr, 0);
- }
- static zend_always_inline zend_string * _php_math_longtobase_pwr2(zend_long arg, int base_log2)
- {
- static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- zend_ulong value;
- size_t len;
- zend_string *ret;
- char *ptr;
- value = arg;
- if (value == 0) {
- len = 1;
- } else {
- len = ((sizeof(value) * 8 - zend_ulong_nlz(value)) + (base_log2 - 1)) / base_log2;
- }
- ret = zend_string_alloc(len, 0);
- ptr = ZSTR_VAL(ret) + len;
- *ptr = '\0';
- do {
- ZEND_ASSERT(ptr > ZSTR_VAL(ret));
- *--ptr = digits[value & ((1 << base_log2) - 1)];
- value >>= base_log2;
- } while (value);
- return ret;
- }
- PHPAPI zend_string * _php_math_zvaltobase(zval *arg, int base)
- {
- static const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) {
- return ZSTR_EMPTY_ALLOC();
- }
- if (Z_TYPE_P(arg) == IS_DOUBLE) {
- double fvalue = floor(Z_DVAL_P(arg));
- char *ptr, *end;
- char buf[(sizeof(double) << 3) + 1];
-
- if (fvalue == ZEND_INFINITY || fvalue == -ZEND_INFINITY) {
- zend_value_error("An infinite value cannot be converted to base %d", base);
- return NULL;
- }
- end = ptr = buf + sizeof(buf) - 1;
- *ptr = '\0';
- do {
- *--ptr = digits[(int) fmod(fvalue, base)];
- fvalue /= base;
- } while (ptr > buf && fabs(fvalue) >= 1);
- return zend_string_init(ptr, end - ptr, 0);
- }
- return _php_math_longtobase(Z_LVAL_P(arg), base);
- }
- PHP_FUNCTION(bindec)
- {
- zend_string *arg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(arg)
- ZEND_PARSE_PARAMETERS_END();
- _php_math_basetozval(arg, 2, return_value);
- }
- PHP_FUNCTION(hexdec)
- {
- zend_string *arg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(arg)
- ZEND_PARSE_PARAMETERS_END();
- _php_math_basetozval(arg, 16, return_value);
- }
- PHP_FUNCTION(octdec)
- {
- zend_string *arg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(arg)
- ZEND_PARSE_PARAMETERS_END();
- _php_math_basetozval(arg, 8, return_value);
- }
- PHP_FUNCTION(decbin)
- {
- zend_long arg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_LONG(arg)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_STR(_php_math_longtobase_pwr2(arg, 1));
- }
- PHP_FUNCTION(decoct)
- {
- zend_long arg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_LONG(arg)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_STR(_php_math_longtobase_pwr2(arg, 3));
- }
- PHP_FUNCTION(dechex)
- {
- zend_long arg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_LONG(arg)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_STR(_php_math_longtobase_pwr2(arg, 4));
- }
- PHP_FUNCTION(base_convert)
- {
- zval temp;
- zend_string *number;
- zend_long frombase, tobase;
- zend_string *result;
- ZEND_PARSE_PARAMETERS_START(3, 3)
- Z_PARAM_STR(number)
- Z_PARAM_LONG(frombase)
- Z_PARAM_LONG(tobase)
- ZEND_PARSE_PARAMETERS_END();
- if (frombase < 2 || frombase > 36) {
- zend_argument_value_error(2, "must be between 2 and 36 (inclusive)");
- RETURN_THROWS();
- }
- if (tobase < 2 || tobase > 36) {
- zend_argument_value_error(3, "must be between 2 and 36 (inclusive)");
- RETURN_THROWS();
- }
- _php_math_basetozval(number, (int)frombase, &temp);
- result = _php_math_zvaltobase(&temp, (int)tobase);
- if (!result) {
- RETURN_THROWS();
- }
- RETVAL_STR(result);
- }
- PHPAPI zend_string *_php_math_number_format(double d, int dec, char dec_point, char thousand_sep)
- {
- return _php_math_number_format_ex(d, dec, &dec_point, 1, &thousand_sep, 1);
- }
- PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, const char *dec_point,
- size_t dec_point_len, const char *thousand_sep, size_t thousand_sep_len)
- {
- zend_string *res;
- zend_string *tmpbuf;
- char *s, *t;
- char *dp;
- size_t integral;
- size_t reslen = 0;
- int count = 0;
- int is_negative=0;
- if (d < 0) {
- is_negative = 1;
- d = -d;
- }
- dec = MAX(0, dec);
- d = _php_math_round(d, dec, PHP_ROUND_HALF_UP);
- tmpbuf = strpprintf(0, "%.*F", dec, d);
- if (tmpbuf == NULL) {
- return NULL;
- } else if (!isdigit((int)ZSTR_VAL(tmpbuf)[0])) {
- return tmpbuf;
- }
-
- if (is_negative && d == 0) {
- is_negative = 0;
- }
-
- if (dec) {
- dp = strpbrk(ZSTR_VAL(tmpbuf), ".,");
- } else {
- dp = NULL;
- }
-
- if (dp) {
- integral = (dp - ZSTR_VAL(tmpbuf));
- } else {
-
- integral = ZSTR_LEN(tmpbuf);
- }
-
- if (thousand_sep) {
- integral = zend_safe_addmult((integral-1)/3, thousand_sep_len, integral, "number formatting");
- }
- reslen = integral;
- if (dec) {
- reslen += dec;
- if (dec_point) {
- reslen = zend_safe_addmult(reslen, 1, dec_point_len, "number formatting");
- }
- }
-
- if (is_negative) {
- reslen++;
- }
- res = zend_string_alloc(reslen, 0);
- s = ZSTR_VAL(tmpbuf) + ZSTR_LEN(tmpbuf) - 1;
- t = ZSTR_VAL(res) + reslen;
- *t-- = '\0';
-
- if (dec) {
- size_t declen = (dp ? s - dp : 0);
- size_t topad = (size_t)dec > declen ? dec - declen : 0;
-
- while (topad--) {
- *t-- = '0';
- }
- if (dp) {
- s -= declen + 1;
- t -= declen;
-
- memcpy(t + 1, dp + 1, declen);
- }
-
- if (dec_point) {
- t -= dec_point_len;
- memcpy(t + 1, dec_point, dec_point_len);
- }
- }
-
- while (s >= ZSTR_VAL(tmpbuf)) {
- *t-- = *s--;
- if (thousand_sep && (++count%3)==0 && s >= ZSTR_VAL(tmpbuf)) {
- t -= thousand_sep_len;
- memcpy(t + 1, thousand_sep, thousand_sep_len);
- }
- }
-
- if (is_negative) {
- *t-- = '-';
- }
- ZSTR_LEN(res) = reslen;
- zend_string_release_ex(tmpbuf, 0);
- return res;
- }
- PHP_FUNCTION(number_format)
- {
- double num;
- zend_long dec = 0;
- char *thousand_sep = NULL, *dec_point = NULL;
- size_t thousand_sep_len = 0, dec_point_len = 0;
- ZEND_PARSE_PARAMETERS_START(1, 4)
- Z_PARAM_DOUBLE(num)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(dec)
- Z_PARAM_STRING_OR_NULL(dec_point, dec_point_len)
- Z_PARAM_STRING_OR_NULL(thousand_sep, thousand_sep_len)
- ZEND_PARSE_PARAMETERS_END();
- if (dec_point == NULL) {
- dec_point = ".";
- dec_point_len = 1;
- }
- if (thousand_sep == NULL) {
- thousand_sep = ",";
- thousand_sep_len = 1;
- }
- RETURN_STR(_php_math_number_format_ex(num, (int)dec, dec_point, dec_point_len, thousand_sep, thousand_sep_len));
- }
- PHP_FUNCTION(fmod)
- {
- double num1, num2;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_DOUBLE(num1)
- Z_PARAM_DOUBLE(num2)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(fmod(num1, num2));
- }
- #ifdef __clang__
- __attribute__((no_sanitize("float-divide-by-zero")))
- #endif
- PHP_FUNCTION(fdiv)
- {
- double dividend, divisor;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_DOUBLE(dividend)
- Z_PARAM_DOUBLE(divisor)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_DOUBLE(dividend / divisor);
- }
- PHP_FUNCTION(intdiv)
- {
- zend_long dividend, divisor;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_LONG(dividend)
- Z_PARAM_LONG(divisor)
- ZEND_PARSE_PARAMETERS_END();
- if (divisor == 0) {
- zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Division by zero");
- RETURN_THROWS();
- } else if (divisor == -1 && dividend == ZEND_LONG_MIN) {
-
- zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Division of PHP_INT_MIN by -1 is not an integer");
- RETURN_THROWS();
- }
- RETURN_LONG(dividend / divisor);
- }
|