On Sun, 2004-05-16 at 17:17, Ard Biesheuvel wrote:
> Hi Timm,
>
> I have an old Alpha PWS433 running FreeBSD which I use for this kind of
> stuff.
>
> > If so, what does this print?
> > --------------------------------------------------------------------------
> > #define LONG_MAX 2147483647L
> > #define LONG_MIN (- LONG_MAX - 1)
>
> Use this for portability
>
> #define LONG_MIN (1L << 8*sizeof(long)-1)
> #define LONG_MAX ~LONG_MIN
Urm... yes:) LONG_MAX is definitely not 2147483647L on 64-bit:)
> > int main(int argc, char* argv)
> > {
> > printf("1) %s\n", (double)LONG_MAX + 1 > LONG_MAX ? "+OK" : "-ERR");
> > printf("2) %s\n", (double)LONG_MIN - 1 < LONG_MIN ? "+OK" : "-ERR");
> > }
>
> 1) -ERR
> 2) -ERR
OK, I found some discussion on this topic using Google. If I understand
correctly, double on 64-bit platforms isn't accurate enough to hold a
long, right?
> > I thought this code was OK by looking at the following:
> >
> > Zend/zend_operators.c:#define DVAL_TO_LVAL(d, l) (l) = (d) > LONG_MAX ?
> > (unsigned long) (d) : (long) (d)
>
> The problem in your code wasn't the comparison per se, but the
> conversion from long to double and back. You will lose accuracy by doing
> that. The value you're converting started out as a long, didn't it ?
Nope, before the first conversion it's actually a string (see
php_sybase_ct.c, lines 1131 to 1123).
To bring this discussion to an end: How does the portable solution look
like? Or, to be more specific, what would need to be done for this to
work portably:
-- snip --
Z_STRLEN(result->data[i][j]) = result->lengths[j]-1;
Z_STRVAL(result->data[i][j]) = estrndup(result->tmp_buffer[j],
result->lengths[j]);
Z_TYPE(result->data[i][j]) = IS_STRING;
/* Now I want to figure out whether this fits into a long,
* and if it does, make it one, a double otherwise
*/
-- snip --
Possible ideas would be to use strtol and check for ERANGE (sample
attached).
- Timm
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#define STRTOLD(str, fits, l, d) \
errno = 0; \
l= strtol(argv[1], NULL, 10); \
if (errno == ERANGE) { \
d= strtod(argv[1], NULL); \
fits = 0; \
} else { \
fits = 1; \
} \
int main(int argc, char** argv)
{
long l;
double d;
int fits;
if (argc != 2) {
fprintf(stderr, "Usage: %s <number>\n", argv[0]);
return 1;
}
STRTOLD(argv[1], fits, l, d);
if (fits) {
printf("Fits into a long: %ld\n", l);
} else {
printf("Does not fit into a long, made it a double: %.0f\n", d);
}
return 0;
}
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php