How to conver bin data to int16 in php - php

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.

Related

Convert string to consistent but random 1 of 10 options

I have many strings. Each string something like:
"i_love_pizza_123"
"whatever_this_is_now_later"
"programming_is_awesome"
"stack_overflow_ftw"
...etc
I need to be able to convert each string to a random number, 1-10. Each time that string gets converted, it should consistently be the same number. A sampling of strings, even with similar text should result in a fairly even spread of values 1-10.
My first thought was to do something like md5($string), then break down a-f,0-9 into ten roughly-equal groups, determine where the first character of the hash falls, and put it in that group. But doing so seems to have issues when converting 16 down to 10 by multiplying by 0.625, but that causes the spread to be uneven.
Thoughts on a good method to consistently convert a string to a random/repeatable number, 1-10? There has to be an easier way.
Here's a quick demo how you can do it.
function getOneToTenHash($str) {
$hash = hash('sha256', $str, true);
$unpacked = unpack("L", $hash); // convert first 4 bytes of hash to 32-bit unsigned int
$val = $unpacked[1];
return ($val % 10) + 1; // get 1 - 10 value
}
for ($i = 0; $i < 100; $i++) {
echo getOneToTenHash('str' . $i) . "\n";
}
How it works:
Basically you get the output of a hash function and downscale it to desired range (1..10 in this case).
In the example above, I used sha256 hash function which returns 32 bytes of arbitrary binary data. Then I extract just first 4 bytes as integer value (unpack()).
At this point I have a 4 bytes integer value (0..4294967295 range). In order to downscale it to 1..10 range I just take the remainder of division by 10 (0..9) and add 1.
It's not the only way to downscale the range but an easy one.
So, the above example consists of 3 steps:
get the hash value
convert the hash value to integer
downscale integer range
A much shorter example with crc32() function which returns integer value right away thus allowing us to omit step 2:
function getOneToTenHash($str) {
$int = crc32($str); // 0..4294967295
return ($int % 10) + 1; // 1..10
}
below maybe what u want
$inStr = "hello world";
$md5Str = md5($inStr);
$len = strlen($md5Str);
$out = 0;
for($i=0; $i<$len; $i++) {
$out = 7*$out + intval($md5Str[$i]); // if you want more random, can and random() here
}
$out = ($out % 10 + 9)%10; // scope= [1,10]

Convert four bytes to 32bit unsigned integer

I have a large binary buffer in PHP script, finding a specific position. I need to convert 4-byte value to 32bit integer.
$seg = hex2bin("AABBCC00010014AABBCC");
$findStart=3;
echo bin2hex($seg[$findStart+0]);
echo bin2hex($seg[$findStart+1]);
echo bin2hex($seg[$findStart+2]);
echo bin2hex($seg[$findStart+3]);
Prints:
00010014
I need to convert seg[findStart+0 .. findStart+3] to 32bit integer. How to do it in PHP script? This example is a decimal number 65556.
This is exactly the purpose of the unpack function, which takes a format string and extracts data from a binary string.
Looking at the list of format codes, and your example, I believe you want
N: unsigned long (always 32 bit, big endian byte order)
So it would look something like this:
$int = unpack('Nvalue', $seg, $findStart)['value'];
For compatibility with older versions of PHP (<7.1), you can emulate the offset argument by consuming a fixed number of bytes into an ignored variable:
$int = unpack("c{$findStart}ignore/Nvalue", $seg)['value'];
You can use ord() to convert a single byte into an integer, then use the left shift and the bitwise-or operator. The first byte you will shift 24 bits to the left, the second byte you will shift 16 bytes to the left, the third 8 bytes.
$a = ord($seg[$findStart+0]);
$b = ord($seg[$findStart+1]);
$c = ord($seg[$findStart+2]);
$d = ord($seg[$findStart+3]);
$newInt = ($a << 24) | ($b << 16) | ($c << 8) | $d;

Get negative numbers after conversion to float [duplicate]

I am trying to convert a hex string into a signed integer.
I am able to easily transfer it into an unsigned value with hexdec() but this does not give a signed value.
Edit:
code in VB - the two "AA" hex values are representative.
Dim bs(2) As Byte
bs(1) = "AA"
bs(2) = "AA"
Dim s As Short
s = BitConverter.ToInt16(bs, 1)
Check out this comment via php.net:
hexdec() returns unsigned integers. For example hexdec("FFFFFFFE") returns 4294967294, not -2. To convert to signed 32-bit integer you may do:
<?php
echo reset(unpack("l", pack("l", hexdec("FFFFFFFE"))));
?>
As said on the hexdec manual page :
The function can now convert values
that are to big for the platforms
integer type, it will return the value
as float instead in that case.
If you want to get some kind of big integer (not float), you'll need it stored inside a string... This might be possible using BC Math functions.
For instance, if you look in the comments of the hexdec manual page, you'll find this note
If you adapt that function a bit, to avoid a notice, you'll get :
function bchexdec($hex)
{
$dec = 0;
$len = strlen($hex);
for ($i = 1; $i <= $len; $i++) {
$dec = bcadd($dec, bcmul(strval(hexdec($hex[$i - 1])), bcpow('16', strval($len - $i))));
}
return $dec;
}
(This function has be copied from the note I linked to ; and only a bit adapted by me)
And using it on your number :
$h = 'D5CE3E462533364B';
$f = bchexdec($h);
var_dump($f);
The output will be :
string '15406319846273791563' (length=20)
So, not the kind of big float you had ; and seems OK with what you are expecting :
Result from calc.exe =
15406319846273791563
Hope this help ;-)
And, yes, user notes on the PHP documentation are sometimes a real gold mine ;-)
I've been trying to find a decent answer to this question and so I wrote this function which works well for a Hex string input, returning a signed decimal value.
public function hex_to_signed_int($hex_str){
$dec = hexdec($hex_str);
//test is value negative
if($dec & pow(16,strlen($hex_str))/2 ){ return $dec-pow(16,strlen($hex_str));}
return $dec;
}

PHP bcmod or gmp_mod input type issue

I'm using bcmod and gmp_mod functions in php for handling large numbers.
This works fine:
// large number must be string
$n = "10000000000000000000001";
$y = 1025;
$c = 1025;
// Both works the same (also tested in python)
$y = gmp_mod( (bcpowmod($y, 2, $n) + $c) , $n);
$y = bcmod ( (bcpowmod($y, 2, $n) + $c) , $n);
But the input $n is not static. So I must use type casting like:
$n = (string)10000000000000000000001;
This doesn't work anymore.
for gmp gives this error:
gmp_mod(): Unable to convert variable to GMP - string is not an integer
And about bc, gives me this error:
bcmod(): Division by zero
The problem is, (string) doesn't convert it to string fine. Any idea?
Edit: I found a solution here, but still the input is string:
$bigint = gmp_init("9999999999999999999");
$bigint_string = gmp_strval($bigint);
var_dump($bigint_string);
If You are taking an input for $n it would give you as a string not as int and if you have type casted as int at any point ... taking care the max size of int, the above given no is converted to 1.0E+22 now what happens when you try to type cast (string)1.0E+22 it becomes "1.0E+22" which is obviously just a string and can not be converted to gmp number.
So You need to convert scientific notation to string which will auto include , hence you also need to replace those commas
$n = 10000000000000000000001;
$n = str_replace(",", "", number_format($n));

How to get number of digits in both right, left sides of a decimal number

I wonder if is there a good way to get the number of digits in right/left side of a decimal number PHP. For example:
12345.789 -> RIGHT SIDE LENGTH IS 3 / LEFT SIDE LENGTH IS 5
I know it is readily attainable by helping string functions and exploding the number. I mean is there a mathematically or programmatically way to perform it better than string manipulations.
Your answers would be greatly appreciated.
Update
The best solution for left side till now was:
$left = floor(log10($x))+1;
but still no sufficient for right side.
Still waiting ...
To get the digits on the left side you can do this:
$left = floor(log10($x))+1;
This uses the base 10 logarithm to get the number of digits.
The right side is harder. A simple approach would look like this, but due to floating point numbers, it would often fail:
$decimal = $x - floor($x);
$right = 0;
while (floor($decimal) != $decimal) {
$right++;
$decimal *= 10; //will bring in floating point 'noise' over time
}
This will loop through multiplying by 10 until there are no digits past the decimal. That is tested with floor($decimal) != $decimal.
However, as Ali points out, giving it the number 155.11 (a hard to represent digit in binary) results in a answer of 14. This is because as the number is stored as something like 155.11000000000001 with the 32 bits of floating precision we have.
So instead, a more robust solution is needed. (PoPoFibo's solutions above is particularly elegant, and uses PHPs inherit float comparison functions well).
The fact is, we can never distinguish between input of 155.11 and 155.11000000000001. We will never know which number was originally given. They will both be represented the same. However, if we define the number of zeroes that we can see in a row before we just decide the decimal is 'done' than we can come up with a solution:
$x = 155.11; //the number we are testing
$LIMIT = 10; //number of zeroes in a row until we say 'enough'
$right = 0; //number of digits we've checked
$empty = 0; //number of zeroes we've seen in a row
while (floor($x) != $x) {
$right++;
$base = floor($x); //so we can see what the next digit is;
$x *= 10;
$base *= 10;
$digit = floor($x) - $base; //the digit we are dealing with
if ($digit == 0) {
$empty += 1;
if ($empty == $LIMIT) {
$right -= $empty; //don't count all those zeroes
break; // exit the loop, we're done
}
} else {
$zeros = 0;
}
}
This should find the solution given the reasonable assumption that 10 zeroes in a row means any other digits just don't matter.
However, I still like PopoFibo's solution better, as without any multiplication, PHPs default comparison functions effectively do the same thing, without the messiness.
I am lost on PHP semantics big time but I guess the following would serve your purpose without the String usage (that is at least how I would do in Java but hopefully cleaner):
Working code here: http://ideone.com/7BnsR3
Non-string solution (only Math)
Left side is resolved hence taking the cue from your question update:
$value = 12343525.34541;
$left = floor(log10($value))+1;
echo($left);
$num = floatval($value);
$right = 0;
while($num != round($num, $right)) {
$right++;
}
echo($right);
Prints
85
8 for the LHS and 5 for the RHS.
Since I'm taking a floatval that would make 155.0 as 0 RHS which I think is valid and can be resolved by String functions.
php > $num = 12345.789;
php > $left = strlen(floor($num));
php > $right = strlen($num - floor($num));
php > echo "$left / $right\n";
5 / 16 <--- 16 digits, huh?
php > $parts = explode('.', $num);
php > var_dump($parts);
array(2) {
[0]=>
string(5) "12345"
[1]=>
string(3) "789"
As you can see, floats aren't the easiest to deal with... Doing it "mathematically" leads to bad results. Doing it by strings works, but makes you feel dirty.
$number = 12345.789;
list($whole, $fraction) = sscanf($number, "%d.%d");
This will always work, even if $number is an integer and you’ll get two real integers returned. Length is best done with strlen() even for integer values. The proposed log10() approach won't work for 10, 100, 1000, … as you might expect.
// 5 - 3
echo strlen($whole) , " - " , strlen($fraction);
If you really, really want to get the length without calling any string function here you go. But it's totally not efficient at all compared to strlen().
/**
* Get integer length.
*
* #param integer $integer
* The integer to count.
* #param boolean $count_zero [optional]
* Whether 0 is to be counted or not, defaults to FALSE.
* #return integer
* The integer's length.
*/
function get_int_length($integer, $count_zero = false) {
// 0 would be 1 in string mode! Highly depends on use case.
if ($count_zero === false && $integer === 0) {
return 0;
}
return floor(log10(abs($integer))) + 1;
}
// 5 - 3
echo get_int_length($whole) , " - " , get_int_length($fraction);
The above will correctly count the result of 1 / 3, but be aware that the precision is important.
$number = 1 / 3;
// Above code outputs
// string : 1 - 10
// math : 0 - 10
$number = bcdiv(1, 3);
// Above code outputs
// string : 1 - 0 <-- oops
// math : 0 - INF <-- 8-)
No problem there.
I would like to apply a simple logic.
<?php
$num=12345.789;
$num_str="".$num; // Converting number to string
$array=explode('.',$num_str); //Explode number (String) with .
echo "Left side length : ".intval(strlen($array[0])); // $array[0] contains left hand side then check the string length
echo "<br>";
if(sizeof($array)>1)
{
echo "Left side length : ".intval(strlen($array[1]));// $array[1] contains left hand check the string length side
}
?>

Categories