Good day,
Trust all is well.
I want to duplicate the Move function from Pascal to PHP.
Here is what I have In Pascal:
function Encode(const S: AnsiString): AnsiString;
const
Map: array [0 .. 63] of Char = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
'abcdefghijklmnopqrstuvwxyz0123456789+/';
var
i: LongInt;
begin
i := 0; ;
Move(S[1], i, Length(S));
Result := Map[i mod 64] + Map[(i shr 6) mod 64];
end;
Here is what I have in PHP:
private function Encode($pass)
{
$map = str_split('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/');
$i = 0;
$this->MoveFunction($pass[0], $i, mb_strlen($pass));
$result = $map[$i % 63] . $map[($i >> 6) % 64];
return $result;
}
Now I now know that the Move function is used to copy a section of memory from one place to another, just not sure where to begin and how it would be done. I could not replicate the results from Pascal in PHP. I have tried sub strings ens. to no avail.
The "$this->MoveFunction" is the function that I will need to write in order to duplicate the functionality of the Move function from pascal. I need to use the same outcome of the Move from pascal in order to use the same encryption field from a similar DB.
I think this is an easy way to test in Pascal:
var
A: array[1..4] of Char;
B: Integer;
begin
A[1] := 'W';
A[2] := 'H';
A[3] := 'A';
A[4] := 'T';
B := 5;
Move(A, B, SizeOf(B));
showmessage(B.ToString()); // 4718679
Any help would be greatly appreciated.
Thank you in advance.
Pascal code moves some AnsiChars into 32-bit Int variable. Note that the first char becomes the least significant byte of integer (due to byte order), and result is just equal to
Result := Map[Byte(S[1]) mod 64];
so Move is not needed at all, all other symbols of string aren't involved in work.
If you can cast the first symbol of $pass as byte/int variable in PHP - work is done.
P.S. I see ord() function, so code might look like this:
(I also changed % to bitwise &)
private function Encode($pass)
{
$map = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$i = ord($pass[0]);
$result = $map[$i & 63];
return $result;
}
For shr:
Result := Map[i mod 64] + Map[(i shr 6) mod 64]; =>
$a = ord($pass[0]) & 63;
$b = ord($pass[0]) >> 6; //two ms bits
$b = $b & 3; //to clear ms bits
$c = ord($pass[1]) & 15; //four ls bits
$d = $b | ($c << 2); //combine them
$result = $map[$a].$map[$d];
I have this code in Qt c++
const unsigned char *packed = reinterpret_cast<const unsigned char*>(data.constData());
res.type = static_cast<int>(packed[0]);
res.period = static_cast<int>(packed[1]);
res.rate = static_cast<qint16>(packed[2] | (packed[3] << 8)) / 100.;
res.edge = static_cast<qint16>(packed[4] | (packed[5] << 8)) / 100.;
return res;
How to convert it from c++ to php
I try this:
$a = unpack ("C*", $data);
$eventList = [];
for ($i=0; $i < $a[1]; $i++)
{
$event = array ();
$index = $i * 6 + 2;
$event["type"] = $a[$index];
$event["period"] = $a[$index+1];
$event["rate"] = ($a[$index+2] | ($a[$index+3] << 8)) / 100;
$event["edge"] = ($a[$index+4] | ($a[$index+5] << 8)) / 100;
}
Edge conver wrong
Very big value.
[edge] => 650.86
must be -4.5
Type, period and rate is good;
Help me please
Don't know the exact answer but some of possible ways to solve the problem:
Check $a[$index+4] and $a[$index+5] value by using var_dump to get its value and type:
var_dump($a[$index+4]);
var_dump($a[$index+5]);
is the data type and its value as expected? Probably good idea is to check as above all data before/after calculation to exactly know what you are dealing with.
Double check your conversion type, perhaps you should't use C* but other, perhaps S or s?
conversion types
If you need type conversion in php you can check how it is done here: Type Juggling and Casting
Note that in PHP you can use a string with ASCII digit that can be treated as digit for calculations:
$foo = 5 * "10 Little Piggies"; // $foo is integer (50)
Which is something you probably don't want.
If you expect negative value but you get positive you have problem because your'e not setting MSB by shifting bits:
The MSB can also correspond to the sign bit of a signed binary number
read-wiki
in case packed[5] should be negative but it isn't
If this not helps then provide data sample and expected values for Edge, Type, period and rate.
I just found the similar_text function and was playing around with it, but the percentage output always suprises me. See the examples below.
I tried to find information on the algorithm used as mentioned on php: similar_text()Docs:
<?php
$p = 0;
similar_text('aaaaaaaaaa', 'aaaaa', $p);
echo $p . "<hr>";
//66.666666666667
//Since 5 out of 10 chars match, I would expect a 50% match
similar_text('aaaaaaaaaaaaaaaaaaaa', 'aaaaa', $p);
echo $p . "<hr>";
//40
//5 out of 20 > not 25% ?
similar_text('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'aaaaa', $p);
echo $p . "<hr>";
//9.5238095238095
//5 out of 100 > not 5% ?
//Example from PHP.net
//Why is turning the strings around changing the result?
similar_text('PHP IS GREAT', 'WITH MYSQL', $p);
echo $p . "<hr>"; //27.272727272727
similar_text('WITH MYSQL', 'PHP IS GREAT', $p);
echo $p . "<hr>"; //18.181818181818
?>
Can anybody explain how this actually works?
Update:
Thanks to the comments I found that the percentage is actually calculated using the number of similar charactors * 200 / length1 + lenght 2
Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len);
So that explains why the percenatges are higher then expected. With a string with 5 out of 95 it turns out 10, so that I can use.
similar_text('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', 'aaaaa', $p);
echo $p . "<hr>";
//10
//5 out of 95 = 5 * 200 / (5 + 95) = 10
But I still cant figure out why PHP returns a different result on turning the strings around. The JS code provided by dfsq doesn't do this. Looking at the source code in PHP I can only find a difference in the following line, but i'm not a c programmer. Some insight in what the difference is, would be appreciated.
In JS:
for (l = 0;(p + l < firstLength) && (q + l < secondLength) && (first.charAt(p + l) === second.charAt(q + l)); l++);
In PHP: (php_similar_str function)
for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
Source:
/* {{{ proto int similar_text(string str1, string str2 [, float percent])
Calculates the similarity between two strings */
PHP_FUNCTION(similar_text)
{
char *t1, *t2;
zval **percent = NULL;
int ac = ZEND_NUM_ARGS();
int sim;
int t1_len, t2_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Z", &t1, &t1_len, &t2, &t2_len, &percent) == FAILURE) {
return;
}
if (ac > 2) {
convert_to_double_ex(percent);
}
if (t1_len + t2_len == 0) {
if (ac > 2) {
Z_DVAL_PP(percent) = 0;
}
RETURN_LONG(0);
}
sim = php_similar_char(t1, t1_len, t2, t2_len);
if (ac > 2) {
Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len);
}
RETURN_LONG(sim);
}
/* }}} */
/* {{{ php_similar_str
*/
static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
{
char *p, *q;
char *end1 = (char *) txt1 + len1;
char *end2 = (char *) txt2 + len2;
int l;
*max = 0;
for (p = (char *) txt1; p < end1; p++) {
for (q = (char *) txt2; q < end2; q++) {
for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
if (l > *max) {
*max = l;
*pos1 = p - txt1;
*pos2 = q - txt2;
}
}
}
}
/* }}} */
/* {{{ php_similar_char
*/
static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2)
{
int sum;
int pos1, pos2, max;
php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
if ((sum = max)) {
if (pos1 && pos2) {
sum += php_similar_char(txt1, pos1,
txt2, pos2);
}
if ((pos1 + max < len1) && (pos2 + max < len2)) {
sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
txt2 + pos2 + max, len2 - pos2 - max);
}
}
return sum;
}
/* }}} */
Source in Javascript: similar text port to javascript
This was actually a very interesting question, thank you for giving me a puzzle that turned out to be very rewarding.
Let me start out by explaining how similar_text actually works.
Similar Text: The Algorithm
It's a recursion based divide and conquer algorithm. It works by first finding the longest common string between the two inputs and breaking the problem into subsets around that string.
The examples you have used in your question, actually all perform only one iteration of the algorithm. The only ones not using one iteration and the ones giving different results are from the php.net comments.
Here is a simple example to understand the main issue behind simple_text and hopefully give some insight into how it works.
Similar Text: The Flaw
eeeefaaaaafddddd
ddddgaaaaagbeeee
Iteration 1:
Max = 5
String = aaaaa
Left : eeeef and ddddg
Right: fddddd and geeeee
I hope the flaw is already apparent. It will only check directly to the left and to the right of the longest matched string in both input strings. This example
$s1='eeeefaaaaafddddd';
$s2='ddddgaaaaagbeeee';
echo similar_text($s1, $s2).'|'.similar_text($s2, $s1);
// outputs 5|5, this is due to Iteration 2 of the algorithm
// it will fail to find a matching string in both left and right subsets
To be honest, I'm uncertain how this case should be treated. It can be seen that only 2 characters are different in the string.
But both eeee and dddd are on opposite ends of the two strings, uncertain what NLP enthusiasts or other literary experts have to say about this specific situation.
Similar Text: Inconsistent results on argument swapping
The different results you were experiencing based on input order was due to the way the alogirthm actually behaves (as mentioned above).
I'll give a final explination on what's going on.
echo similar_text('test','wert'); // 1
echo similar_text('wert','test'); // 2
On the first case, there's only one Iteration:
test
wert
Iteration 1:
Max = 1
String = t
Left : and wer
Right: est and
We only have one iteration because empty/null strings return 0 on recursion. So this ends the algorithm and we have our result: 1
On the second case, however, we are faced with multiple Iterations:
wert
test
Iteration 1:
Max = 1
String = e
Left : w and t
Right: rt and st
We already have a common string of length 1. The algorithm on the left subset will end in 0 matches, but on the right:
rt
st
Iteration 1:
Max = 1
String = t
Left : r and s
Right: and
This will lead to our new and final result: 2
I thank you for this very informative question and the opportunity to dabble in C++ again.
Similar Text: JavaScript Edition
The short answer is: The javascript code is not implementing the correct algorithm
sum += this.similar_text(first.substr(0, pos2), second.substr(0, pos2));
Obviously it should be first.substr(0,pos1)
Note: The JavaScript code has been fixed by eis in a previous commit. Thanks #eis
Demystified!
It would indeed seem the function uses different logic depending of the parameter order. I think there are two things at play.
First, see this example:
echo similar_text('test','wert'); // 1
echo similar_text('wert','test'); // 2
It seems to be that it is testing "how many times any distinct char on param1 is found in param2", and thus result would be different if you swap the params around. It has been reported as a bug, which has been closed as "working as expected".
Now, the above is the same for both PHP and javascript implementations - paremeter order has an impact, so saying that JS code wouldn't do this is wrong. This is argued in the bug entry as intended behaviour.
Second - what doesn't seem correct is the MYSQL/PHP word example. With that, javascript version gives 3 irrelevant of the order of params, whereas PHP gives 2 and 3 (and due to that, percentage is equally different). Now, the phrases "PHP IS GREAT" and "WITH MYSQL" should have 5 characters in common, irrelevant of which way you compare: H, I, S and T, one each, plus one for empty space. In order they have 3 characters, 'H', ' ' and 'S', so if you look at the ordering, correct answer should be 3 both ways. I modified the C code to a runnable version, and added some output, so one can see what is happening there (codepad link):
#include<stdio.h>
/* {{{ php_similar_str
*/
static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
{
char *p, *q;
char *end1 = (char *) txt1 + len1;
char *end2 = (char *) txt2 + len2;
int l;
*max = 0;
for (p = (char *) txt1; p < end1; p++) {
for (q = (char *) txt2; q < end2; q++) {
for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
if (l > *max) {
*max = l;
*pos1 = p - txt1;
*pos2 = q - txt2;
}
}
}
}
/* }}} */
/* {{{ php_similar_char
*/
static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2)
{
int sum;
int pos1, pos2, max;
php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
if ((sum = max)) {
if (pos1 && pos2) {
printf("txt here %s,%s\n", txt1, txt2);
sum += php_similar_char(txt1, pos1,
txt2, pos2);
}
if ((pos1 + max < len1) && (pos2 + max < len2)) {
printf("txt here %s,%s\n", txt1+ pos1 + max, txt2+ pos2 + max);
sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
txt2 + pos2 + max, len2 - pos2 - max);
}
}
return sum;
}
/* }}} */
int main(void)
{
printf("Found %d similar chars\n",
php_similar_char("PHP IS GREAT", 12, "WITH MYSQL", 10));
printf("Found %d similar chars\n",
php_similar_char("WITH MYSQL", 10,"PHP IS GREAT", 12));
return 0;
}
the result is output:
txt here PHP IS GREAT,WITH MYSQL
txt here P IS GREAT, MYSQL
txt here IS GREAT,MYSQL
txt here IS GREAT,MYSQL
txt here GREAT,QL
Found 3 similar chars
txt here WITH MYSQL,PHP IS GREAT
txt here TH MYSQL,S GREAT
Found 2 similar chars
So one can see that on the first comparison, the function found 'H', ' ' and 'S', but not 'T', and got the result of 3. The second comparison found 'I' and 'T' but not 'H', ' ' or 'S', and thus got the result of 2.
The reason for these results can be seen from the output: algorithm takes the first letter in the first string that second string contains, counts that, and throws away the chars before that from the second string. That is why it misses the characters in-between, and that's the thing causing the difference when you change the character order.
What happens there might be intentional or it might not. However, that's not how javascript version works. If you print out the same things in the javascript version, you get this:
txt here: PHP, WIT
txt here: P IS GREAT, MYSQL
txt here: IS GREAT, MYSQL
txt here: IS, MY
txt here: GREAT, QL
Found 3 similar chars
txt here: WITH, PHP
txt here: W, P
txt here: TH MYSQL, S GREAT
Found 3 similar chars
showing that javascript version does it in a different way. What the javascript version does is that it finds 'H', ' ' and 'S' being in the same order in the first comparison, and the same 'H', ' ' and 'S' also on the second one - so in this case the order of params doesn't matter.
As the javascript is meant to duplicate the code of PHP function, it needs to behave identically, so I submitted bug report based on analysis of #Khez and the fix, which has been merged now.
first String = aaaaaaaaaa = 10 letters
second String = aaaaa = 5 letters
first five letters are similar
a+a
a+a
a+a
a+a
a+a
a
a
a
a
a
( <similar_letters> * 200 ) / (<letter_count_first_string> + <letter_count_second_string>)
( 5 * 200 ) / (10 + 5);
= 66.6666666667
Description
int similar_text ( string $first , string $second [, float &$percent ] )
This calculates the similarity between two strings as described in Oliver [1993]. Note that this implementation does not use a stack as in Oliver's pseudo code, but recursive calls which may or may not speed up the whole process. Note also that the complexity of this algorithm is O(N**3) where N is the length of the longest string.
Parameters
first
The first string.
second
The second string.
percent
By passing a reference as third argument, similar_text() will calculate the similarity in percent for you.
For example, if the pattern is as follows:
bit [10010][1011][1000]
position 54321 4321 4321
result 2 1 4
I want to get the result from right to left position as [2] [1] [4]
If I understand your question correctly, you are looking for a function that returns the index of the least significant 1-bit in an integer. If so, check whether your platform implements the function ffs() ("find first set"). On Linux, you can do man ffs to get the full documentation. On other programming platforms the function may be named differently, e.g. in NVIDIA's CUDA, it exists as a device function __ffs().
Assuming the bit pattern is represented by an int you could do something like
if(bitPattern == 0) {
return 0;
}
int count = 1;
while(bitPattern % 2 == 0) {
bitPattern >>= 1;
count++;
}
return count;
$n = log($x & (~$x+1))/log(2)
~x + 1 is exact the same as -x, as the result of the 2's complement. So why would you use the more complex and slower?
And there are many bithacks to quickly find integer log2x instead of using the much more slower floating point log as above. No slowly divide is needed too. Since x & -x yields only the last bit which is a power of 2, you can use the following function to get log2
unsigned int log2p2(unsigned int v) // 32-bit value to find the log2 of v
{
static const unsigned int b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0,
0xFF00FF00, 0xFFFF0000};
register unsigned int r = (v & b[0]) != 0;
for (i = 4; i > 0; i--) // unroll for speed...
{
r |= ((v & b[i]) != 0) << i;
}
}
There are many other ways to calculate log2x which you can find here
So your code is now simply
log2p2(x & -x);
I'm getting some odd results where 2 identical functions (one in PHP and one in javascript) are returning different results.
The input for both of these lines of code is identical:
a = 4653896912;
b = 13;
I have double checked the variable types and both variables are numbers in JS and integers in PHP.
The line of code for PHP is this:
$a = $a >> $b;
For Javascript it's this:
a = a >> b;
You'd expect a to have the same value after both, but I'm getting the following:
PHP: $a = 568102
JS: a = 43814
Which has completely baffled me at this point.
Turns out this is definitely an issue of PHP using 64 bit integers and JS only using 32 bit. The problem I face now is that I need to get PHP to use 32-bit integers for these calculations. I found a function someone else wrote that looks like it should work, but it doesn't seem to be changing the output at all for me.
private static function toInt32(&$x) {
$z = hexdec(80000000);
$y = (int) $x;
if($y ==- $z && $x <- $z){
$y = (int) ((-1) * $x);
$y = (-1) * $y;
}
$x = $y;
}
The below code demonstrates masking the upper 32 bits of the number to retrieve only the lower 32 bits to use in your calculations. 4294967295 is 2^32 - 1. I think that if you mask all values that could be greater than 32 bits in this manner, then you can get the same results from your php and javascript.
<?php
$php_a = 4653896912;
$php_b = 13;
//convert $php_a into a 32 bit val
$php_a = $php_a & 4294967295;
$a = $php_a >> $php_b;
echo "PHP: \$a = $a <br />";
?>
<script type="text/javascript">
var a = 4653896912;
var b = 13;
var a = a >> b;
alert('Javascript A value is ' + a);
</script>
4653896912 is more than 32 bits.. unpredictable results are likely. I get $a = 43814 for PHP, but that is actually 358929617 >> 13, so in all likelihood PHP is doing 64 bit operations but JavaScript is only 32 bit.
I believe it's because you're a is above the limit of a 32-bit signed integer for [PHP][1].
The highest value possible is about 2 million, and a is over 4 billion.
When you're rolling over because of space limitations, results can be unpredictable (or at least, very difficult to figure out).
If your server is on a 64-bit version of PHP then it'll max out much higher than than, but javascript is limited by what the end-user is running.
You can read up on PHP on their integers page.