[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-block] [Qemu-devel] [PATCH v3 2/5] qapi: Add qobject_is_equal(

From: Max Reitz
Subject: Re: [Qemu-block] [Qemu-devel] [PATCH v3 2/5] qapi: Add qobject_is_equal()
Date: Wed, 5 Jul 2017 19:04:11 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.2.0

On 2017-07-05 19:00, Max Reitz wrote:
> On 2017-07-05 18:29, Eric Blake wrote:
>> On 07/05/2017 11:22 AM, Max Reitz wrote:
>>>>>>     return (double)x == x && x == y;
>>>>> Yes, that would do, too; and spares me of having to think about how well
>>>>> comparing an arbitrary double to UINT64_MAX actually works. :-)
>>>> On second thought, this won't do, because (double)x == x is always true
>>>> if x is an integer (because this will implicitly cast the second x to a
>>>> double, too). However, (uint64_t)(double)x == x should work.
>>> Hm, well, the nice thing with this is that (double)UINT64_MAX is
>>> actually UINT64_MAX + 1, and now (uint64_t)(UINT64_MAX + 1) is
>>> undefined... Urgs.
>> (uint64_t)(UINT64_MAX + 1) is well-defined - it is 0.
>> (Adding in unsigned integers is always well-defined - it wraps around on
>> mathematical overflow modulo the integer size.  You're thinking of
>> overflow addition on signed integers, which is indeed undefined)
> It's not. See the standard:

Or, well, yes, it is in this case, but I meant literally UINT64_MAX + 1,
not the uint64_t value. I meant the natural number 2^64.

Because the issue is that (double)UINT64_MAX will (or may, depending on
the environment and such) give us 2.0^64 == 0x1p64.

And this is where the quotation I gave below comes in. When casting an
integer to a double we may end up with a value that is not representable
in the original integer type, so we cannot easily cast it back.


> When a finite value of real floating type is converted to an integer
> type other than _Bool, the fractional part is discarded (i.e., the value
> is truncated toward zero). If the value of the integral part cannot be
> represented by the integer type, the behavior is undefined. [61]
> [61] The remaindering operation performed when a value of integer type
> is converted to unsigned type need not be performed when a value of real
> floating type is converted to unsigned type. Thus, the range of portable
> real floating values is (−1, Utype_MAX+1).
> See for yourself:
> printf("%i\n", (uint64_t)(double)UINT64_MAX == UINT64_MAX);
> This yields 1 with gcc and -O3.
>>> So I guess one thing that isn't very obvious but that should *always*
>>> work (and is always well-defined) is this:
>>> For uint64_t: y < 0x1p64 && (uint64_t)y == x
>>> For int64_t: y >= -0x1p63 && y < 0x1p63 && (int64_t)y == x
>> That's harder to read, compared to the double-cast method which is
>> well-defined after all.
>>> I hope. :-/
>>> (But finally a chance to use binary exponents! Yay!)
>> Justifying the use of binary exponents is going to be harder than that,
>> and would need a really good comment in the code, compared to just using
>> a safe double-cast.
> It's not safe.
> Max

Attachment: signature.asc
Description: OpenPGP digital signature

reply via email to

[Prev in Thread] Current Thread [Next in Thread]