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 ~0
2.
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.
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With