summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSascha Schumann <sas@php.net>2001-09-20 08:22:44 +0000
committerSascha Schumann <sas@php.net>2001-09-20 08:22:44 +0000
commitf45555e62f578854b5862e6a3b84c0a21a053850 (patch)
treeae73c8d1baf5bc9b754218bfe7c856fc75cbfcdd
parenta16eadb1ef5be2fb935e4eb1ad47905498d4674a (diff)
downloadphp-git-f45555e62f578854b5862e6a3b84c0a21a053850.tar.gz
Rework some string-to-number and vice-versa functions to work smarter
(e.g. without using functions that use slow locales, without allocating extra memory and with fewer integer/float operations)
-rw-r--r--ext/standard/math.c104
1 files changed, 38 insertions, 66 deletions
diff --git a/ext/standard/math.c b/ext/standard/math.c
index 28ca255721..805a4e1e06 100644
--- a/ext/standard/math.c
+++ b/ext/standard/math.c
@@ -664,7 +664,7 @@ PHP_FUNCTION(rad2deg)
*/
PHPAPI long
_php_math_basetolong(zval *arg, int base) {
- long mult = 1, num = 0, digit;
+ long num = 0, digit, onum;
int i;
char c, *s;
@@ -674,23 +674,25 @@ _php_math_basetolong(zval *arg, int base) {
s = Z_STRVAL_P(arg);
- for (i = Z_STRLEN_P(arg) - 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;
- }
+ 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;
}
- if(!mult || digit > LONG_MAX/mult || num > LONG_MAX-mult*digit) {
- php_error(E_WARNING, "base_to_long: number '%s' is too big to fit in long", s);
- return LONG_MAX;
- }
- num += mult * digit;
+
+ onum = num;
+ num = num * base + digit;
+ if (num > onum)
+ continue;
+
+ php_error(E_WARNING, "base_to_long: number '%s' is too big to fit in long", s);
+ return LONG_MAX;
}
return num;
@@ -764,8 +766,8 @@ PHPAPI char *
_php_math_longtobase(zval *arg, int base)
{
static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- char *result, *ptr, *ret;
- int len, digit;
+ char buf[(sizeof(unsigned long) << 3) + 1];
+ char *ptr, *end;
unsigned long value;
if (Z_TYPE_P(arg) != IS_LONG || base < 2 || base > 36) {
@@ -774,25 +776,16 @@ _php_math_longtobase(zval *arg, int base)
value = Z_LVAL_P(arg);
- /* allocates space for the longest possible result with the lowest base */
- len = (sizeof(Z_LVAL_P(arg)) * 8) + 1;
- result = emalloc((sizeof(Z_LVAL_P(arg)) * 8) + 1);
-
- ptr = result + len - 1;
- *ptr-- = '\0';
+ end = ptr = buf + sizeof(buf) - 1;
+ *ptr = '\0';
do {
- digit = value % base;
- *ptr = digits[digit];
+ *--ptr = digits[value % base];
value /= base;
- }
- while (ptr-- > result && value);
- ptr++;
- ret = estrdup(ptr);
- efree(result);
+ } while (ptr > buf && value);
- return ret;
-}
+ return estrndup(ptr, end - ptr);
+}
/* }}} */
/* {{{ _php_math_zvaltobase */
@@ -805,49 +798,28 @@ PHPAPI char *
_php_math_zvaltobase(zval *arg, int base)
{
static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
- char *result, *ptr, *ret;
- int len, digit;
- unsigned long value;
- double fvalue;
- int f_mode;
if ((Z_TYPE_P(arg) != IS_LONG && Z_TYPE_P(arg) != IS_DOUBLE) || base < 2 || base > 36) {
return empty_string;
}
- f_mode = (Z_TYPE_P(arg) == IS_DOUBLE);
-
- if(f_mode) {
- fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */
- } else {
- value = Z_LVAL_P(arg);
- }
+ if (Z_TYPE_P(arg) == IS_DOUBLE) {
+ double fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */
+ char *ptr, *end;
+ char buf[(sizeof(double) << 3) + 1];
- /* allocates space for the longest possible result with the lowest base */
- len = (sizeof(Z_DVAL_P(arg)) * 8) + 1;
- result = emalloc((sizeof(Z_DVAL_P(arg)) * 8) + 1);
+ end = ptr = buf + sizeof(buf) - 1;
+ *ptr = '\0';
- ptr = result + len - 1;
- *ptr-- = '\0';
+ do {
+ *--ptr = digits[(int) fmod(fvalue, base)];
+ fvalue /= base;
+ } while (ptr > buf && fabs(fvalue) >= 1);
- do {
- if(f_mode) {
- double d = floor(fvalue/base);
- digit = (int)ceil(fvalue - d*base);
- *ptr = digits[digit];
- fvalue = d;
- } else {
- digit = value % base;
- *ptr = digits[digit];
- value /= base;
- }
+ return estrndup(ptr, end - ptr);
}
- while (ptr-- > result && (f_mode?(fabs(fvalue)>=1):value));
- ptr++;
- ret = estrdup(ptr);
- efree(result);
-
- return ret;
+
+ return _php_math_longtobase(arg, base);
}
/* }}} */