Velocity Reviews > Portable way to mask the LSB

# Portable way to mask the LSB

Francis Moreau
Guest
Posts: n/a

 05-29-2010
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
Guest
Posts: n/a

 05-29-2010
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
Guest
Posts: n/a

 05-29-2010
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
http://www.velocityreviews.com/forums/(E-Mail Removed)lid

Francis Moreau
Guest
Posts: n/a

 05-30-2010
On 29 mai, 15:06, Moi <(E-Mail Removed)> 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
Guest
Posts: n/a

 05-30-2010
On Sun, 30 May 2010 12:44:45 -0700, Francis Moreau wrote:

> On 29 mai, 15:06, Moi <(E-Mail Removed)> 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
Guest
Posts: n/a

 05-31-2010
On May 30, 5:10*pm, Moi <(E-Mail Removed)> 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
Guest
Posts: n/a

 05-31-2010
On 31 mai, 12:56, Tom St Denis <(E-Mail Removed)> wrote:
> On May 30, 5:10*pm, Moi <(E-Mail Removed)> 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
Guest
Posts: n/a

 05-31-2010
Tom St Denis <(E-Mail Removed)> writes:
> On May 30, 5:10Â*pm, Moi <(E-Mail Removed)> 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) (E-Mail Removed) <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"