Le 10/02/2013 05:54, Stas Malyshev a écrit :
> Hi!
> 
>> About
>> http://git.php.net/?p=php-src.git;a=commitdiff;h=79956330fe17cfd5f60de456497541b21a89bddf
>> (For now, I have reverted this fix)
>>
>> Here some explanations.
>>
>> LONG_MAX is 9223372036854775807 (0x7fffffffffffffff)
>> double representation of LONG_MAX is 9223372036854775808
> 
> I see what's going on here. We have precision loss due to the fact that
> the range of double (53 bits) is smaller than the range of long (63
> bits) on 64-bit system. When it's converted back to long, I guess it has
> to be expanded back to 63 bits.
> 
>> 9223372036854775807 on ppc64
>> 9223372036854775808 on x86_64 (gcc without optimization)
>> 9223372036854775807 on x86_64 (gcc -O2)
>>
>> PHP expected value is 9223372036854775808
> 
> Not sure how value of long can be expected to be 9223372036854775808 -
> 9223372036854775808 is not representable in signed long. If you do
> (long)(unsigned long), you'd get -9223372036854775808.

Yes; I mean -9223372036854775808 (0x8000000000000000)

(sorry, I have use %lu format instead of %ld in my tests)

> 
>> (Btw, I don't understand why PHP, build on x86_64, with -O2, gives the
>> good result, some environment mystery)
> 
> With -O2, gcc probably pre-calculates the result of the operation if you
> use simple test program. So, if I write:
> 
> double b = LONG_MAX;
> printf("%ld", (long)b);
> 
> Then without -O2, I'm getting:
> 
>         movsd   -16(%rbp), %xmm0
>         cvttsd2siq      %xmm0, %rsi
> 
> But with -O2, it's just:
> 
>         movabsq $9223372036854775807, %rsi
> 
> So the difference in results may stem from the fact that the
> calculations go in different way here.
> 
>> Obviously, we could have different result on different platform,
>> compiler, architecture.
>>
>> I will be very interested by result on other platform (mac, windows),
>> compiler (Visual C), architecture.
>>
>> If we switch to the unsigned cast:
>>      (long)(unsigned long)d;
>>
>> The result is always 9223372036854775808 (which is expected)
> 
> Wait, long can not be 9223372036854775808, how the result of long
> conversion can be that?

Yes, -9223372036854775808 (0x8000000000000000)


>> From my tests, this doesn't change anything on x86_64, and improves
> 
> Well, for the value of (double)LONG_MAX the code actually changes
> substantially, and if I test this code:
> 
> double b = LONG_MAX;
> printf("%ld %ld", (long)(unsigned long)b, (long)b);
> 
> Then with -O2 I get different results:
> 
> -9223372036854775808 9223372036854775807
> 
> But that may be an optimization artifact.

Yes I also think.
But is this couldn't occurs in real PHP, with another compiler or
another gcc version ?

> With real PHP, the result of
> converting 9223372036854775807 to double and then back to int seems to
> always be -9223372036854775808 on Intel, with or without the patch. I
> don't have access to ppc64 machine so no idea what's going on there.
> 

That's exactly the problem.
On Intel, we always get  -9223372036854775808 (when 9223372036854775807
could be expected, with -O2, from you previous test)

On ppc64, we always get 9223372036854775807.

This is exactly what I'd like to fix.

And, as you said, the patch doesn't change result on Intel.

I could make this change conditionnal on PPC, but I think it will also
protect us from any compiler optimization change.

Remi



-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to