Find the highest set bit - php

I have 5 different values which are saved as bits like 10010.
I get the value as an Int from the Database (cannot change that) so like 24 means 11000
I know that i can get the biggest bit here by using
if ((decbin($d) & 16) == 16)
but if the first is 0 i would have to check the next bit, and if that is 0 i would have to ...
So after all i would have a block of ifs and if there were more bits the block was bigger.
Is there a simple way to just get the "id" (or value, would not matter) of the highest bit with a 1?

Yes. Compute the base 2 logarithm of the number and floor it:
$highbit = floor(log($d, 2));
If $highbit, for instance, is 5, it means that the 5th bit is the highest bit set to 1.

The highest bit set in an integer is equal to the integer base-2 logarithm of that integer.
While there exist many different implementations for doing that kind of thing in assembler and C and such, more or less efficiently, the probably easiest way to do it in PHP is to actually use logarithm.
The log() function surely is not the most efficient way of solving the problem, but seeing as you are in a script language, it probably won't be any slower (and quite possibly faster) than implementing one of the "better" algorithms in PHP with 2 dozen statements.
Thus:
$highestbit = (int)(log($value,2));

Interesting ... had to check for rounding-problems immediately and found none in the range of up to 1'000'000, though my test-code revealed problems for less native bases, like 3:
3^5 = 243 but floor(log(243, 3)) gives 4

def hibit(v):
""" uint v -> highest bit: 0101 -> 0100, 01xxxx -> 010000 """
# cf http://graphics.stanford.edu/~seander/bithacks.html
v |= v >> 1
v |= v >> 2
v |= v >> 4
v |= v >> 8
v |= v >> 16
return v ^ (v >> 1)
for v in range(0, 9+1) + range(2**31-1, 2**31+2):
print v, hibit(v)

Related

Why does right shifting -1 always gives -1 in PHP?

I am trying to figure out why if I shift the negative integer -1 I always get -1, e.g.:
echo -1 >> 64; // -1
echo -1 >> 5; // -1
echo -1 >> 43; // -1
echo -1 >> 1; // -1
Whatever second operand of the right shift is given, -1 remains -1... I do understand that when you perform a right shift you're actually doing this:
x >> y = x / 2^y
But in the case of x being -1, if so, I do:
-1 >> 3 = -1 / 2^3
Shouldn't this value be -1/8 = -0.125?
Thanks for the attention.
Bitwise shift operators don't divide. They do what they are supposed to do - shift bits. In particular, the right shift operator does the following:
for each bit starting from the right, set its value to what's on the left of it
for the leftmost bit, which has nothing on the left, keep its current value
For example, if your number is
1011...101
right shift gives you
11011...10
So the rightmost bit (LSB) is lost and the leftmost bit (MSB) is duplicated. This is called "sign propagation", because MSB is used to distinguish positive (MSB=0) from negative (MSB=1) numbers.
Negative numbers are stored as "two's complement", that is, on a 32-bit system, -x is stored as 2^32-x. So, -1 is 10...00 (32 zeroes) - 1 == 1...1 (32 ones). If you shift 32 ones according to the above procedure, you get 32 ones yet again, that is, -1 >> whatever will always be -1.
The difference between the right shift and division by two is that the shift gives same results for odd and even numbers. Since the rightmost bit is lost, when you shift an odd number (which has LSB=1), the result is the same as shifting the next lower even number (the same combination of bits, but with LSB=0). So, you get no halves when you shift, since the dividend is forced to be even. For example,
1010 = 10102, 10 / 2 = 5.0 and 10 >> 1 == 510 == 1012
1110 = 10112, 11 / 2 = 5.5 but 11 >> 1 == 510 == 1012
If you prefer to think about x >> 1 in terms of division, it first "rounds" x down to an even number (x - abs(x) % 2) and then divides that number by two.
For x = -1 this gives you (-1 - abs(-1) % 2)/2 == (-1 - 1)/2 = -2/2 = -1.
It is the same in all languages I know - bitwise arithmetic right shift for -1 will be -1, and as others mentioned, this operation can be applied only to integers.
-1 is represented in binary as all bits filled with value 1. For arithmetic right shift the bits will be shifted to the right, and the highest bit (at the left) will be filled with sign of the value, for negative values it will be 1, and for positive - 0. So it makes -1 again after the shift.
There are other kinds of bitwise shifts, and for logical right shift the highest bit would be filled with zero. You can get some more info here: http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift

modulus operand in ruby compared to php

I'm looking for a simple explanation for how Ruby's modulo operand works and why, in Ruby
puts 4 % 3 # 1
puts -4 % 3 # 2 <--why?
puts -4 % -3 # -1
but in PHP:
<?php
echo 4 % 3; # 1
echo -4 % 3; # -1
echo -4 % -3; # -1
Looks to me like -4 % 3 is actally 8 % 3 (8 being the difference between 4 and -4).
They can both be considered correct, depending on your definition. If a % n == r, then it should hold that:
a == q*n + r
where q == a / n.
Whether r is positive or negative is determined by the value of q. So in your example, either of:
-4 == -1*3 + (-1) // PHP
-4 == -2*3 + 2 // Ruby
To put it another way, the definition of % depends on the definition of /.
See also the table here: http://en.wikipedia.org/wiki/Modulus_operator#Remainder_calculation_for_the_modulo_operation. You'll see that this varies substantially between various programming languages.
Here's a snippet on the topic from The Ruby Programming Language, by Matz and David Flanagan.
When one (but not both) of the operands is negative, Ruby performs the
integer division and modulo operations differently than languages like
C, C++, and Java do (but the same as the languages Python and Tcl).
Consider the quotient -7/3. Ruby rounds toward negative infinity and
returns -3. C and related languages round toward zero instead and
return -2. In Ruby, -a/b equals a/-b but my not equal -(a/b).
Ruby's definition of the module operation also differs from that of C
and Java. In Ruby, -7%3 is 2. In C and Java, the result is -1
instead. The magnitude of the result differs, because the quotient
differed. But the sign of the result differs, too. In Ruby, the sign
of the result is always the sign of the second operand. In C and
Java, the sign of the result is always the sign of the first operand.
(Ruby's remainder method behaves like the C modulo operator.)
It actually boils down to the implementation of the language's integer casting/rounding. Since the actual equation is:
a - (n * int(a/n))
It is the int(a/n) portion of the equation that differs. If a == -4 and n == 3, PHP will return -1, while Ruby will produce -2. Now the equation looks like this in Ruby:
-4 - (3 * -2)
and this in PHP
-4 - (3 * -1)
According to Wolfram Alpha, 2 is correct.
edit: Seems you should be asking why PHP works that way?
edit2: PHP defines it as the remainder from the devision A/B. Whether you consider it a bug, wrong, or a different way of doing things is up to you, I suppose. Personally, I go for the first 2.

GMP Bit shift doesn't work on negative numbers

I found this function at php.net. It seems to work on positive numbers, but fails on negative ones:
function gmp_shiftr($x,$n) { // shift right
return(gmp_div($x,gmp_pow(2,$n)));
}
echo -1 >> 8; //returns -1, presumably correctly
echo "<br />";
echo gmp_strval(gmp_shiftr(-1,8)); //returns 0, presumably incorrectly
How could I fix up the function to work with negatives?
Two ideas I have:
Maybe I could do something along the lines of
if (whatever) { $a >> $b} else{ gmp_shiftr($a, $b) }?
Or, maybe I could subtract something from the negative results depending on their value..?
I just want to get the value that >> would give, but also get it for >32bit numbers when I use GMP.
Looking at the GMP documentation for the division routines, there's a function
void mpz_tdiv_q_2exp (mpz_t q, mpz_t n, unsigned long int b)
that seems like it might be what you want: an arithmetic right shift that treats
n as if it were represented in twos-complement, and (I think) shifts it b places
to the right. Unfortunately, that level of the API doesn't seem to be exposed by PHP GMP.
I found a bit twiddling hack for doing sign extension when the number of bits
in the representation is unknown:
unsigned b; // number of bits representing the number in x
int x; // sign extend this b-bit number to r
int r; // resulting sign-extended number
int const m = 1U << (b - 1); // mask can be pre-computed if b is fixed
x = x & ((1U << b) - 1); // (Skip this if bits in x above position b are already zero.)
r = (x ^ m) - m;
Since bitwise AND and XOR are supported by PHP GMP, you might be able to make
this work...
If you think about this mathematically it makes sense. gmp_shiftr is doing -1/256, which, when rounding towards zero (the gmp default) is 0.
The ">>" method works like it does because negative numbers are represented in sign-extended twos complement form.

What does >> mean in PHP?

Consider:
echo 50 >> 4;
Output:
3
Why does it output 3?
50 in binary is 11 0010, shift right by 4 yields 11 which is equal to 3.
See PHP documentation and Wikipedia.
As documented on php.org, the >> operator is a bitwise shift operator which shifts bits to the right:
$a >> $b - Shift the bits of $a $b steps to the right (each step means "divide by two")
50 in binary is 110010, and the >> operator shifts those bits over 4 places in your example code. Although this happens in a single operation, you could think of it in multiple steps like this:
Step 1 - 00011001
Step 2 - 00001100
Step 3 - 00000110
Step 4 - 00000011
Since binary 11 is equal to 3 in decimal, the code outputs 3.
Arithmetic shift right.
The >> operator is called a binary right shift operator.
Shifting bits to the right 4 times is the same as dividing by two, four times in a row. The result, in this case would be 3.125. Since 50 is an int, bit shifting will return the floor of this, which is 3.
Put another way, 50 is 0b110010 in binary. Shifted 4 times we have 0b11, which is 3 in decimal.
>> is the binary right-shift operator.
Your statement shifts the bits in the numeric value 50 four places to the right. Because all integers are represented in two's complement, this equals 3. An easy way to remember this is that one shift to the right is the same as dividing by 2, and one shift to the left is the same as multiplying by 2.
It's called a right shift.
'The bits of the left operand are shifted right by the number of positions of the right operand. The bit positions vacated on the left are filled with the sign bit, and bits shifted out on the right are discarded.'
Information can be found on it here:
http://php.comsci.us/etymology/operator/rightshift.php
It shifts the bits down four places.
50 in binary is 110010.
Shifted down four places is 11, which is 3.
For your convenience, one of the fastest ways to calculate the outputted value from a bitwise shift is to multiply or divide by 2.
For example echo 50 >> 4;
Given that this is a bitwise right, it literally means that the value will be decrease, then we can get the output by divide 50 for 2 and 4 times.
echo 50 >> 4; // 50/(2*2*2*2) ~ 3.
Given that (from) 48 -> (to) 63/16(2*2*2*2), the result will be more than 2 and less than 4. Then
echo 48 >> 4; // 48/(2*2*2*2) ~ 3.
echo 63 >> 4; // 63/(2*2*2*2) ~ 3.
However, when bitwise left, the result will be totally different as it multiplies by 2 with n times:
If echo 50 << 4; // 50*(2*2*2*2) ~ 800
If echo 51 << 4; // 51*(2*2*2*2) ~ 816
Live example: https://3v4l.org/1hbJe

PHP right shifting and negative result?

I've run into a problem whilst converting some C code to PHP, specifically in the use of the right-shift operator.
edit: in the following examples, bit = 0;
Original C code:
p->param->outBits[bytePtr++] |= codeword >> (9 + bit);
PHP code:
$outBits[$bytePtr++] |= $codeword >> (9 + $bit);
If I start with codeword being 130728, in C I get the expected result of -1. In PHP I get 255. I understand this is something to do with arithmetic/logical shift differences, and the negative sign not being introduced as a result of the MSBs staying at zero.
Is there a "quick" way of doing the above in PHP that doesn't involve the shifting? eg via basic arithmetic or similar, that will give me the expected answer?
Your problem is that PHP doesn't have a type byte, it only has integer which usually is 32 bits (not 8), so if you really need negative value there (the bits are correct anyway, because unsigned 255 is the same as signed -1), then you should probably add the missing 24 ones or use arithmetics to restore the negative value (255 is -1, 254 is -2 and so on i.e. 256 - x = -x).

Categories