cvs: php4 /ext/standard math.c
| From: | Sascha Schumann | Date: | Thu, 20 Sep 2001 08:22:45 +0000 |
| Subject: | cvs: php4 /ext/standard math.c | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-7490@lists.php.net to get a copy of this message | ||
sas Thu Sep 20 04:22:45 2001 EDT
Modified files:
/php4/ext/standard math.c
Log:
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)
Index: php4/ext/standard/math.c
diff -u php4/ext/standard/math.c:1.61 php4/ext/standard/math.c:1.62
--- php4/ext/standard/math.c:1.61 Wed Sep 19 07:03:58 2001
+++ php4/ext/standard/math.c Thu Sep 20 04:22:44 2001
@@ -19,7 +19,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: math.c,v 1.61 2001/09/19 11:03:58 sas Exp $ */
+/* $Id: math.c,v 1.62 2001/09/20 08:22:44 sas Exp $ */
#include "php.h"
#include "php_math.h"
@@ -664,7 +664,7 @@
*/
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 @@
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 @@
_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 @@
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 @@
_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 (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];
+
+ end = ptr = buf + sizeof(buf) - 1;
+ *ptr = '\0';
+
+ do {
+ *--ptr = digits[(int) fmod(fvalue, base)];
+ fvalue /= base;
+ } while (ptr > buf && fabs(fvalue) >= 1);
- if(f_mode) {
- fvalue = floor(Z_DVAL_P(arg)); /* floor it just in case */
- } else {
- value = Z_LVAL_P(arg);
+ return estrndup(ptr, end - ptr);
}
-
- /* 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);
-
- ptr = result + len - 1;
- *ptr-- = '\0';
-
- 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;
- }
- }
- while (ptr-- > result && (f_mode?(fabs(fvalue)>=1):value));
- ptr++;
- ret = estrdup(ptr);
- efree(result);
-
- return ret;
+
+ return _php_math_longtobase(arg, base);
}
/* }}} */