Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expression for setting lowest n bits that works even when n equals word size

Tags:

perl

NB: the purpose of this question is to understand Perl's bitwise operators better. I know of ways to compute the number U described below.

Let $i be a nonnegative integer. I'm looking for a simple expression E<$i>1 that will evaluate to the unsigned int U, whose $i lowest bits are all 1's, and whose remaining bits are all 0's. E.g. E<8> should be 255. In particular, if $i equals the machine's word size (W), E<$i> should equal ~02.

The expressions (1 << $i) - 1 and ~(~0 << $i) both do the right thing, except when $i equals W, in which case they both take on the value 0, rather than ~0.

I'm looking for a way to do this that does not require computing W first.


EDIT: OK, I thought of an ugly, plodding solution

$i < 1 ? 0 : do { my $j = 1 << $i - 1; $j < $j << 1 ? ( $j << 1 ) - 1 : ~0 }

or

$i < 1 ? 0 : ( 1 << ( $i - 1 ) ) < ( 1 << $i ) ? ( 1 << $i ) - 1 : ~0

(Also impractical, of course.)


1 I'm using the strange notation E<$i> as shorthand for "expression based on $i".

2 I don't have a strong preference at the moment for what E<$i> should evaluate to when $i is strictly greater than W.

like image 429
kjo Avatar asked Mar 11 '16 20:03

kjo


Video Answer


1 Answers

On systems where eval($Config{nv_overflows_integers_at}) >= 2**($Config{ptrsize*8}) (which excludes one that uses double-precision floats and 64-bit ints),

2**$i - 1

On all systems,

( int(2**$i) - 1 )|0
  • When i<W, int will convert the NV into an IV/UV, allowing the subtraction to work on systems with the precision of NVs is less than the size of UVs. |0 has no effect in this case.

  • When i≥W, int has no effect, so the subtraction has no effect. |0 therefore overflows, in which case Perl returns the largest integer.

I don't know how reliable that |0 behaviour is. It could be compiler-specific. Don't use this!

like image 68
ikegami Avatar answered Nov 08 '22 14:11

ikegami