Extracting two lowest bits and adding to another word - php

I've spent the last hour going around in circles on this so it's finally time to ask for help. I have two binary 8-bit words such as these:
$words[0]="00000101";
$words[1]="01111001";
I want to take the two right bits (01) of $words[0] and append it to the start of $words[1] to make 0101111001 = 377 in decimal.
The easiest way would be to use PHPs string functions to do a substr() but I'd rather learn how to do it using bitwise operators as I need to do this for lots of other examples as well.
What I thought I'd do is to to do 00000101 AND 0x03 to give me 64 and then shift the bits 8 places to the right so that I can add them to $words[1] using OR.
In code that would be:
($array[0] & 0x03 << 8) | $array[1]
but I just get the value of $array[1] back. It seems that it's not possible to shift a value to left more than 8 bits as it gets set to zero (which makes sense).
So, how can accomplish what I want to do ?

You didn't use binaries. Binaries starts with 0b... without "".
This code works:
$words[0]=0b00000101;
$words[1]=0b01111001;
$last = $words[0] & 0b11;
$shift = $last << 8;
$newWord = $shift | $words[1];
echo $newWord;
Or in short form:
echo ($words[0] & 0b11) << 8 | $words[1];
I use the bitwise & 0b11 to get the last two digits from the first word, shift it with <<8 and use the bitwise or |.
For the last | you can use + instead, if you want.
EDIT:
If you want the result as binary just use decbin:
echo decbin($newWord);

Related

PHP two different result localhost and live host from a function

I have no idea why i get two different results from the same function, When i use it in local host i get a result and when i upload file to my host i get different result.
I test it, i give it the same word and i get two different results.
it's a function from CAPTCHA library: Captcha library
function rpHash($value) {
$hash = 5381;
$value = strtoupper($value);
for($i = 0; $i < strlen($value); $i++) {
$hash = (($hash << 5) + $hash) + ord(substr($value, $i));
}
return $hash;
}
The problem is that your localhost is 32bit and your host is 64bit. To understand why, read the accepted answer on this post. To summarize:
The << operator does a Left shift
Integers are stored, in memory, as a series of bits. For example, the number 6 stored as a 32-bit int would be represented in base 2 as:
00000000 00000000 00000000 00000110
Shifting this bit pattern to the left one position (6 << 1) would result in the number 12 and represented in base 2 as:
00000000 00000000 00000000 00001100
As you can see, the digits have shifted to the left by one position, and the last digit on the right is filled with a zero.
When you shift left, you are increasing the number by an order of ^2 for each shift.
On a 32 bit system, the maximum integer you can have is 2,147,483,647 (which is 01111111 11111111 11111111 11111111 (there are 31 bits available). That is how much room you have to shift left before you run out of room to store the number.
Your starting hash of 5381 is 13 bits long
Your function shifts FIVE bits for each letter in the $value.
You get to 31 bits after 3 letters (3*5) + 13 = 28
So you can only have 3 letters max in your CAPTCHA before it breaks.
Your OPTIONS:
Restrict your CAPTCHA to 3 characters or less and use the
existing function.
Shift using $hash << 3. This will get you 5
characters
Shift using $hash << 2. This will get you 7
characters
Use a different method
For example:
function rpHash($value) {
$hash = 5381;
$value = strtoupper($value);
for($i = 0; $i < strlen($value); $i++) {
$hash = (($hash << 2) + $hash) + ord(substr($value, $i));
}
return $hash;
}
It may have to do with whether or not the operating system is 32-bit or 64-bit. If you shift $hash too far left, you could end up with an overflow error, and wrap around to negative numbers.
The solution depends on your needs. If all you need is a positive integer, and it doesn't matter if the values are consistent across operating systems, just wrap the returned value with abs() to make sure the result is positive.
If you need the result to always be consistent, you'll probably need to truncate the result to be stored in 32 bits at most. Using something like:
$32bitresult = rphash($value) & 0xFFFFFFFF;
should work.
NOTE: You may want to add a check to see if the result of rphash is negative before AND-ing the two.
Take a look at this similar problem/answer:
Force PHP integer overflow
I haven't been able to test the code out, but maybe it'll help you on your way at least.

Why does 2e3 return 2000? Isn't 2 to the 3rd power equal to 8?

This code:
$g = 2e3;
echo $g;
echo <br>;
echo "var_dump g gives:<br>";
Displays:
2000
float(2000)
I don't understand why it wouldn't display "8" and "float(8)"? Isn't 2 to the 3rd power equal to 8 ??
I tried looking for this question on this website already. Any help would be greatly appreciated. I did figure out that for 2e2 it displays 200. So it sounds like it just adds that many zeros to the end of the number instead of finding the 3rd power of 2. When I search for how to write exponential in php, the answers I've found said to use 'e' or 'E', but that doesn't seem to work or I've forgotten basic math. I'm sure somebody on here has a very simple answer for me.
Ok so why does $g = 2^3; give me 1? How can I write 2 to the 3rd power in php?
It's called scientific notation (or in this case "E notation").
2e3 is the same as 2 x 10^3, which is 2000.
If you want 2^3, you can use
$g = pow(2, 3);
Or in PHP 5.6+:
$g = 2**3;
Note: You need to use pow() (or **) because in PHP, when you do $g = 2^3;, you are doing 2 XOR 3.
When you read something like xey that is called scientific notation. It represents x times 10 to the power of y, or essentilly, add y zeroes to x (for positive values of y). So in this case, it's 2 * 10^3 = 2,000
2e3 is scientific notation for 2000.0. It is the same as 2.0e03. Use the pow() function:
echo pow(2, 3); // 8

Using levenshtein to match target string + extra text

I'm working on a website conversion project, and I need to match inexact strings. I'm looking at using leveshtein, but I don't know what parameters I should set for my task.
Say I have a target string elephant. The match I would want to pull is elephant mouse, for example
<?
$target = "elephant";
$data = array(
'elephant mouse',
'rhinoceros',
'alligator',
'hippopotamus',
'rat',
);
foreach ( $data as $datum ) {
echo "$target >> $datum == " . levenshtein($target, $datum) . "\n";
}
And I get the result
elephant >> elephant mouse == 6
elephant >> rhinoceros == 10
elephant >> alligator == 7
elephant >> hippopotamus == 10
elephant >> rat == 7
So while rhino and hippo are at 10, in my actual data set, I couldn't really tell the difference between elephant mouse, rat and alligator, which are neck-and-neck at 6 and 7. This is bogus data, but in my data set, words that are closer in length only get a much lower score than words that are target + extra.
How should I configure the options of levenshtein()? I can set new integer values for the cost of insertion, replacement, and deletion. What weighting will give me what I want?
(If you can think of a better title please edit my post).
The weighting levenshtein($target, $datum, 1, 10, 10) gives me
elephant >> elephant mouse == 6
elephant >> rhinoceros == 65
elephant >> alligator == 52
elephant >> hippopotamus == 64
elephant >> rat == 60
Which works very well :) Insertion is a low cost, while both replacement and deletion are high. This means that target + extra has a low score, where strings of equal or shorter length, but different characters, have a high cost.
You should probably try to match individual words with levenshtein() rather than entire phrases, since you apparently want to consider a phrase a good match if it contains something that resembles the word being searched for. In other words, split each string in $datum into individual words, run levenshtein($target, $word) for each word, and pick the lowest number. (If $target also can consist of multiple words, you need to split that one too.)
I strongly doubt that you can achieve the desired effect by tweaking the insertion/deletion/replacement costs, because the Levenshtein doesn't consider individual words, only the string as a whole. You could try to make insertion very cheap, but that would also give a good score to e.g. "qwErtyLasdEdgfhdPasdxcHdfjAlkjNlkhTkjh" since it contains all the right letters.

Reading top nibble and bottom nibble in a byte

What's the correct way to handle two distinct values being stored in one byte of data. I have a byte that contains two nibbles each containing their own data. I want to read the top nibble and the bottom nibble into their own variables.
11110000 = High 4 bits throttle, to be read into $throttle, and should be a value from 0 to 15.
00001111 = Low 4 bits brake, to be read into $brake, and should be a value from 0 to 15.
Don't forget, drivers can apply the throttle and the brake at the same time, so you might get a value like 11000111. I've myself come up with a solution for the high 4 bits, and it's as simple as pushing the lower 4 bits out of the way with the >> (bit shift right) operator 4 times. $Throttle = $ThrBrk >> 4, but as I can't do that in one move for the lower four bits it looks kinda bad in my source code.
Use ANDoperators for both and shift the top nibble four bits to the right.
$brake = $value & 0x0F;
$throttle = ($value & 0xF0) >> 4;
Check out the & operator, which is a bitwise AND. To get the first (least significant bit), do this:
$lsb = $bits & 1;
So, to get the whole "nibble":
$break = $bits & 15;

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