PHP, reading 8 byte integers from a MySQL database? - php

I have a BINARY(40) column in a MySQL and there I store 5 8 byte integers. I am trying to read those numbers in PHP one by one:
$result = mysqli_query($con,"SELECT data FROM list WHERE id=".$id);
$mysql_array = mysqli_fetch_array($result);
$list = str_split($mysql_array["data"], 8);
for($i = 0; $i < 5; $i++)
echo $list[$i]."<br/>";
Instead of the numbers I expect, weird symbols are printed. How can I convert those numbers from binary strings to integers?

Change your query as follows:
$result = mysqli_query($con,"SELECT cast(data as char(40)) FROM list WHERE id=".$id);

OK, because of the way you're storing the numbers, this code will only work if you've got 64 bit support, otherwise you'll have to look at a bc replacement, shouldn't be too difficult:
for($i = 0; $i < 5; $i++) {
$bin_str = $list[$i];
$int_val = 0;
for ($j = 0; $j < 8; ++$j) {
$byte_val = ord(substr($bin_str, $j, 1));
// push the next byte onto our integer:
$int_val = ($int_val << 8) + $byte_val;
}
echo $int_val;
}
EDIT: In all likelyhood this is a BC equiv, I'm unable to test it at the moment though, however the logic remains unchanged.
for($i = 0; $i < 5; $i++) {
$bin_str = $list[$i];
$bc_val = '0';
for ($j = 0; $j < 8; ++$j) {
$byte_val = ord(substr($bin_str, $j, 1));
// push the next byte onto our integer:
$bc_val = bcadd(bcmul($bc_val, 256, 0), "$byte_val", 0);
}
echo $bc_val;
}

Related

String sort in alphabetic order in php8

I am trying to find first element(alphabetical order) from array string using loop without inbuilt functions in php8. My code is below but it is not working a intented. What is the error in my code?
eg: string = "This","is","my","apple";
apple need to print
$arraystring= array("This","is","my","apple");
$count = count($arraystring);
for ($i = 0; $i < $count; $i++) {
for ($j = 1; $j < $count; $j++) {
if(strcmp($arraystring[$i], $arraystring[$j])<0){
$temp = $arraystring[$i];
$arraystring[$i] = $arraystring[$j];
$arraystring[$j] = $temp;
}
}
}
my code not worked as intented

Php binary radix sort implementation

I'm trying to implement a radix sort in binary, because i want to check if the speed of bit shifting operations counterbalance the number of steps required.
My counting sort seems to work, but as soon as i have several passes for the radix sort, the result break.
Any help greatly appreciated.
/*
* bits is to store the value of the current digit for each number in the input array
*/
function countSort(&$arr, $digit) {
$bits = $output = array_fill(0, NB_ELEMS, 0);
$count = [0,0];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$bits[$i] = $bit;
$count[$bit]++;
}
// Cumulative count
$count[1] = NB_ELEMS;
// Rearranging
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = $bits[$i];
$output[$count[$bit] - 1] = $nb;
$count[$bit]--;
}
// Switch arrays
$arr = $output;
}
function radixSort(&$arr, $nb_digits) {
// Do counting sort for every binary digit
for($digit = 0; $digit < $nb_digits; $digit++) {
countSort($arr, $digit);
}
}
$tab = [4,3,12,8,7];
$max_value = max($tab);
$nb_digits = floor(log($max_value, 2)) + 1;
radixSort($tab, $nb_digits);
Ok, thanks to a friend, i found my problem : the counting sort implementation which i use stacks the same digit numbers using the counter as top index, and then decrementing it. And that's ok for counting sort (so one iteration), but it scrambles everything when you use it in radix sort (multiple counting sort iterations).
So i used instead a method in which you shift your counters one time right, which gives you for the n+1 digit your starting point, and then increment it.
And boom you're good to go.
function countSort2(&$arr, $digit) {
$bits = $output = array_fill(0, NB_ELEMS, 0); // output array
$count = [0,0];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$bits[$i] = $bit;
$count[$bit]++;
}
// Cumulative count shifted
$count[1] = $count[0];
$count[0] = 0;
// Rearranging
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = $bits[$i];
$output[$count[$bit]] = $nb;
$count[$bit]++;
}
// Switch arrays
$arr = $output;
}
I also made some tests (1M items, max value 1M, 100 iterations), and a method storing values instead of counting them, and merging thereafter seems twice as fast (function just after that). Anyway, both methods are far under native sort performance.
Any comment appreciated
function byDigitSortArrayMerge(&$arr, $digit) {
$output = array_fill(0, NB_ELEMS - 1, 0); // output array
$bits = array_fill(0, NB_ELEMS - 1, 0); // output array
$by_bit = [[], []];
// Store count of occurrences in count[]
for ($i = 0; $i < NB_ELEMS; $i++) {
$nb = $arr[$i];
$bit = ($nb >> $digit) & 1;
$by_bit[$bit][] = $nb;
}
$arr = array_merge($by_bit[0], $by_bit[1]);
}

Generating random values with restricted digits

What is the best way to generate a random integer with a restricted set of digits?
I want to generate a 4 digit random number, where each digit is in the range [1..6]. I was thinking generate a number in the range [0..1295], then converting to base 6 and incrementing the digits, but that goes through a string.
Without string conversion, and with only one call to a random number generator, you could do this:
function myRandom() {
$num = mt_rand(0, 1295);
$result = 0;
for ($i = 0; $i < 4; $i++) {
$result = $result*10 + $num % 6;
$num = floor($num / 6);
}
return $result + 1111;
}
You could generate each digit separately like this:
$result = '';
for ($i=0; $i < 4; $i++) {
$result .= mt_rand(1, 6);
}
$result = (int) $result;
Or if using a string is not preferred, you could do it with math:
$result = 0;
for ($i=0; $i < 4; $i++) {
$result += mt_rand(1, 6) * 10 ** $i;
// or for PHP versions < 5.6 (no ** exponentiation operator)
// $result += mt_rand(1, 6) * pow(10, $i);
}
<?php
// 216_10 = 1000_6
// 1295_10 = 5555_6
base_convert(mt_rand(216,1295),10,6);

Levenshtein distance with back tracing in PHP

I'm trying to align strings in PHP using Levenshtein distance algorithm. The problem is that my back tracing code does not work properly for all cases. For example when the second array has inserted lines at the beginning. Then the back tracing will only go as far as when i=0.
How to properly implement back tracing for Levenshtein distance?
Levenshtein distance, $s and $t are arrays of strings (rows)
function match_rows($s, $t)
{
$m = count($s);
$n = count($t);
for($i = 0; $i <= $m; $i++) $d[$i][0] = $i;
for($j = 0; $j <= $n; $j++) $d[0][$j] = $j;
for($i = 1; $i <= $m; $i++)
{
for($j = 1; $j <= $n; $j++)
{
if($s[$i-1] == $t[$j-1])
{
$d[$i][$j] = $d[$i-1][$j-1];
}
else
{
$d[$i][$j] = min($d[$i-1][$j], $d[$i][$j-1], $d[$i-1][$j-1]) + 1;
}
}
}
// backtrace
$i = $m;
$j = $n;
while($i > 0 && $j > 0)
{
$min = min($d[$i-1][$j], $d[$i][$j-1], $d[$i-1][$j-1]);
switch($min)
{
// equal or substitution
case($d[$i-1][$j-1]):
if($d[$i][$j] != $d[$i-1][$j-1])
{
// substitution
$sub['i'][] = $i;
$sub['j'][] = $j;
}
$i = $i - 1;
$j = $j - 1;
break;
// insertion
case($d[$i][$j-1]):
$ins[] = $j;
$j = $j - 1;
break;
// deletion
case($d[$i-1][$j]):
$del[] = $i;
$i = $i - 1;
break;
}
}
This is not to be nit-picky, but to help you find the answers you want (and improve your implementation).
The algorithm you are using is the Wagner-Fischer algorithm, not the Levenshtein algorithm. Also, Levenshtein distance is not use to align strings. It is strictly a distance measurement.
There are two types of alignment: global and local. Global alignment is used to minimize the distance between two entire strings. Example: global align "RACE" on "REACH", you get "RxACx". The x's are gaps.
In general, this is the Needleman-Wunsch algorithm, which is very similar to the Wagner-Fischer algorithm. Local alignment finds a substring in a long string and minimizes the difference between a short string and a the substring of the long string.
Example: local align "BELL" on "UMBRELLA" and you get "BxELL" aligned on "BRELL". It is the Smith-Waterman algorithm which, again, is very similar to the Wagner-Fischer algorithm.
I hope that this is helpful in allowing you to better define the exact kind of alignment you want.
I think your bug is exactly what you say in your question that it is: you stop as soon as i==0, instead of going all the way to i==0 && j==0. Simply replace this condition:
while($i > 0 && $j > 0)
with
while ($i > 0 || $j > 0)
and you're halfway to your solution. The tricky bit is that if $i==0, then it's incorrect to use the array index $i-1 in the loop body. So you'll also have to change the body of the loop to something more like
while ($i || $j) {
$min = $d[$i][$j]; // or INT_MAX or something
if ($i && $j && $min > $d[$i-1][$j-1]) {
$newi = $i-1;
$newj = $j-1;
$min = $d[$newi][$newj];
}
if ($i && $min > $d[$i-1][$j]) {
$newi = $i-1;
$newj = $j;
$min = $d[$newi][$newj];
}
if ($j && $min > $d[$i][$j-1]) {
$newi = $i;
$newj = $j-1;
$min = $d[$newi][$newj];
}
// What sort of transformation is this?
if ($newi == $i && $newj == $j) {
assert(false); // should never happen
} else if ($newi == $i) {
// insertion
$ins[] = $j;
} else if ($newj == $j) {
// deletion
$del[] = $i;
} else if ($d[$i][$j] != $d[$newi][$newj]) {
// substitution
$sub['i'][] = $i;
$sub['j'][] = $j;
} else {
// identity
}
assert($newi >= 0); assert($newj >= 0);
$i = $newi;
$j = $newj;
}

php array output problem

In php is there a function to increment the
values of subsequent values twice(*2) in an array
column based on an initial value?
$beta = array(
array('5', '1''1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2'),
array('5','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2')
);
/*Example: '5' will be '10' (5*2 =10 and output 10 to web)
'2' will be '4' (2*2 = 4 and output 4 to web)
The next '2' will be '16' (4*2 = 8 and output 8 to web)
The next '2' will be '32' (8*2 = 16 and output 16 to web)
And so forth? */
Furthermore is there an easier way to construct this array, cause I firmly believe there is, but not something too complicated in terms of construct such that a noob will not understand it, again thanks.
[Disclaimer: I have spent 3 days trying to understand arrays, I now understand them; however, I am still new and am currently having some issues when trying to manipulate the values in my array and output them to the web.And I am still pretty sure I have a lot to read and learn, so please no flamers, I just need some help, found this problem in this C++ book:
[http://books.google.com/books?id=4Fn_P7tdOZgC&pg=PT424&lpg=PT424&dq=subsequent+++column+is+twice+the+value&source=bl&ots=gSvQ_LhxoI&sig=dG_Ilf1iLO86lqX936cT1PpkPc8&hl=en&ei=OEEBS_eODYyotgOFtJD3CQ&sa=X&oi=book_result&ct=result&resnum=1&ved=0CAgQ6AEwAA#v=onepage&q=subsequent%20%20%20column%20is%20twice%20the%20value&f=false][1]
You can try array_map:
<?php
function increase($n) {
return is_array($n) ? array_map('increase', $n) : $n * 2;
}
$new_beta = array_map("increase", $beta);
As for constructing the array, there are other methods to do so but I believe this is the most performent and clean.
Here is an answer for each question in that section of the book, enjoy!
<?php
// Declare an array alpha of 10 rows and 20 columns of type int
// Initialise the array alpha to 0
$alpha = array(array());
for($i = 0; $i < 10; $i++)
{
for($j = 0; $j < 20; $j++)
{
$alpha[$i][$j] = 0;
}
}
// Store 1 in the first row and 2 in the remaining rows
for($i = 0; $i < 10; $i++)
{
for($j = 0; $j < 20; $j++)
{
if($i == 0)
{
$alpha[$i][$j] = 1;
}
else
{
$alpha[$i][$j] = 2;
}
}
}
// Store 5 in the first column, and make sure that the value in
// each subsequent column is twice the value in the previous column
// (Beware this doesn't build off the initial value of 5 in the first
// column but the previously set values above)
for($i = 0; $i < 10; $i++)
{
for($j = 0; $j < 20; $j++)
{
if($j == 0)
{
$alpha[$i][$j] = 5;
}
else
{
if($j - 1 >= 1)
{
$alpha[$i][$j] = $alpha[$i][$j-1] * 2;
}
}
}
}
// Print the array alpha one row per line
print "Printing the array alpha one row per line:<br/>";
for($i = 0; $i < 10; $i++)
{
for($j = 0; $j < 20; $j++)
{
print "[". $alpha[$i][$j] ."] ";
}
print "<br/>";
}
print "<br/>";
// Print the array alpha one column per line
print "Printing the array alpha one column per line:<br/>";
for($j = 0; $j < 20; $j++)
{
for($i = 0; $i < 10; $i++)
{
print "[". $alpha[$i][$j] ."] ";
}
print "<br/>";
}
?>

Categories