Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Portable way to mask the LSB (http://www.velocityreviews.com/forums/t724360-portable-way-to-mask-the-lsb.html)

Francis Moreau 05-29-2010 12:32 PM

Portable way to mask the LSB
 
Hello,

I just realize that I'm not sure how to do this in a portable way.

Consider this piece of code:

unsigned long u;
/* ... */
u = u & ~1; /* mask the LSB */

In my understanding, this only works if the value of the expression
'~1' is -2. So it depends on how object with signed integer type are
encoded (2's complement, 1's complement ...).

Is this correct ?

If so, how should I rewrite the code to make it portable ?

u = u & ~1UL;
u = u & ~(unsigned long)1;
or
u = u & (ULONG_MAX - 1);

Are these alternatives correct ?

Thanks

Moi 05-29-2010 01:06 PM

Re: Portable way to mask the LSB
 
On Sat, 29 May 2010 05:32:12 -0700, Francis Moreau wrote:

> Hello,
>
> I just realize that I'm not sure how to do this in a portable way.
>
> Consider this piece of code:
>
> unsigned long u;
> /* ... */
> u = u & ~1; /* mask the LSB */
>
> In my understanding, this only works if the value of the expression '~1'
> is -2. So it depends on how object with signed integer type are encoded
> (2's complement, 1's complement ...).
>
> Is this correct ?
>
> If so, how should I rewrite the code to make it portable ?
>
> u = u & ~1UL;


This one seems reasonable to me.

> u = u & ~(unsigned long)1;
> or
> u = u & (ULONG_MAX - 1);
>
> Are these alternatives correct ?
>
> Thanks


Don't forget
u = ((u >>1) <<1);

HTH,
AvK

Eric Sosman 05-29-2010 01:52 PM

Re: Portable way to mask the LSB
 
On 5/29/2010 8:32 AM, Francis Moreau wrote:
> Hello,
>
> I just realize that I'm not sure how to do this in a portable way.
>
> Consider this piece of code:
>
> unsigned long u;
> /* ... */
> u = u& ~1; /* mask the LSB */
>
> In my understanding, this only works if the value of the expression
> '~1' is -2. So it depends on how object with signed integer type are
> encoded (2's complement, 1's complement ...).
>
> Is this correct ?


Yes. `~1' yields the bitwise complement of `1', consisting
of a low-order zero bit and all the other bits set (including the
sign bit). The numeric value of this batch of bits depends on how
the system encodes negative integers: You could get -2 (two's
complement), -1 (ones' complement), or 1-INT_MAX (signed magnitude).

To apply the `&', `~1' is first converted to unsigned long,
and this conversion is defined in terms of the numeric values of
`~1' and of `ULONG_MAX'. Since there are three possible values
for `~1', there are three possible outcomes for the conversion
(only one outcome on any one machine, of course).

> If so, how should I rewrite the code to make it portable ?
>
> u = u& ~1UL;
> u = u& ~(unsigned long)1;
> or
> u = u& (ULONG_MAX - 1);
>
> Are these alternatives correct ?


Yes. I would vote for `u &= ~1UL'. More generally, to clear
the k'th bit, `u &= ~(1UL << k)'.

--
Eric Sosman
esosman@ieee-dot-org.invalid

Francis Moreau 05-30-2010 07:44 PM

Re: Portable way to mask the LSB
 
On 29 mai, 15:06, Moi <r...@invalid.address.org> wrote:
> On Sat, 29 May 2010 05:32:12 -0700, Francis Moreau wrote:
> > Hello,

>
> > I just realize that I'm not sure how to do this in a portable way.

>
> > Consider this piece of code:

>
> > * * unsigned long u;
> > * * /* ... */
> > * * u = u & ~1; /* mask the LSB */

>
> > In my understanding, this only works if the value of the expression '~1'
> > is -2. So it depends on how object with signed integer type are encoded
> > (2's complement, 1's complement ...).

>
> > Is this correct ?

>
> > If so, how should I rewrite the code to make it portable ?

>
> > * * u = u & ~1UL;

>
> This one seems reasonable to me.
>
> > * * u = u & ~(unsigned long)1;
> > or
> > * * u = u & (ULONG_MAX - 1);

>
> > Are these alternatives correct ?

>
> > Thanks

>
> Don't forget
> u = ((u >>1) <<1);


Do you think that this version could be faster ?

Thanks

Moi 05-30-2010 09:10 PM

Re: Portable way to mask the LSB
 
On Sun, 30 May 2010 12:44:45 -0700, Francis Moreau wrote:

> On 29 mai, 15:06, Moi <r...@invalid.address.org> wrote:
>> On Sat, 29 May 2010 05:32:12 -0700, Francis Moreau wrote:
>> > Hello,

>>
>> > I just realize that I'm not sure how to do this in a portable way.

>>
>> > Consider this piece of code:

>>
>> > * * unsigned long u;
>> > * * /* ... */
>> > * * u = u & ~1; /* mask the LSB */

>>
>> > In my understanding, this only works if the value of the expression
>> > '~1' is -2. So it depends on how object with signed integer type are
>> > encoded (2's complement, 1's complement ...).

>>
>> > Is this correct ?

>>
>> > If so, how should I rewrite the code to make it portable ?

>>
>> > * * u = u & ~1UL;

>>
>> This one seems reasonable to me.
>>
>> > * * u = u & ~(unsigned long)1;
>> > or
>> > * * u = u & (ULONG_MAX - 1);

>>
>> > Are these alternatives correct ?

>>
>> > Thanks

>>
>> Don't forget
>> u = ((u >>1) <<1);

>
> Do you think that this version could be faster ?


No.
Basically, I don't care about speed.
In trivial operations like this, it is the speed of access to the
memory (or caches) that dominates the overall speed.
In all cases it winds down to fetch+"some operations"+ one store.

My suggestion has the advantage that there is no possible size mismatch;
other ways to perform the same operation may be sensitive to the size of the
bitmask-constant (~1 vs ~1ul vs ~1ull).
Also, the bitmask constant may be compiled into a literal constant
in the instruction stream, which may cost a 32 bit or 64 bit constant to be
emitted. (GCC on intel mostly uses immediate 0xfe which gets sign-extended)

BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
instruction sequence as the &= ~1 or &= -1ull - versions.

HTH,
AvK

Tom St Denis 05-31-2010 10:56 AM

Re: Portable way to mask the LSB
 
On May 30, 5:10*pm, Moi <r...@invalid.address.org> wrote:
> BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
> instruction sequence as the &= ~1 or &= -1ull - versions.


There is no such thing as -O6 in GCC. It goes up to 3 only.

I suggest you read the GCC manpage sometime.

Tom

Francis Moreau 05-31-2010 07:52 PM

Re: Portable way to mask the LSB
 
On 31 mai, 12:56, Tom St Denis <t...@iahu.ca> wrote:
> On May 30, 5:10*pm, Moi <r...@invalid.address.org> wrote:
>
> > BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
> > instruction sequence as the &= ~1 or &= -1ull - versions.

>
> There is no such thing as -O6 in GCC. *It goes up to 3 only.
>
> I suggest you read the GCC manpage sometime.


Next time I suggest you just stop sending such useless posts.

Keith Thompson 05-31-2010 08:11 PM

Re: Portable way to mask the LSB
 
Tom St Denis <tom@iahu.ca> writes:
> On May 30, 5:10*pm, Moi <r...@invalid.address.org> wrote:
>> BTW: GCC -O6 compiles my shiftR-shiftL code into exactly the same
>> instruction sequence as the &= ~1 or &= -1ull - versions.

>
> There is no such thing as -O6 in GCC. It goes up to 3 only.
>
> I suggest you read the GCC manpage sometime.


<OT>
gcc quietly accepts "-O6". It doesn't seem to be documented, but
as far as I can tell it's equivalent to "-O3". In fact, -On for
any n greater than 3 appears to be equivalent to "-O3".
</OT>

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"


All times are GMT. The time now is 12:36 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.