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

Reply via email to