Hexadecimal XOR with 2 values in PHP and JavaScript - php

I can't find the solution for very easy question.
Code in JavaScript:
var x = -1 ^ 0xF00F9344;
In this case x value is 267414715
Code in PHP:
$x = -1 ^ 0xF00F9344;
The result is -4027552581
Any idea, how to get 267414715 (correct) result in PHP?

While javascript bit operations are always 32-bit, php depends on the platform's word size:
on a 32-bit platform
$n = "11110000000011111001001101000100"
-1^$n = "00001111111100000110110010111011" = 267414715
on a 64 bit platform
$n = "0000000000000000000000000000000011110000000011111001001101000100"
-1^$n = "1111111111111111111111111111111100001111111100000110110010111011" = -4027552581

Related

How to conver bin data to int16 in 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.

Workaround needed, PHP dechex maximum integer [duplicate]

I have some large HEX values that I want to display as regular numbers, I was using hexdec() to convert to float, and I found a function on PHP.net to convert that to decimal, but it seems to hit a ceiling, e.g.:
$h = 'D5CE3E462533364B';
$f = hexdec($h);
echo $f .' = '. Exp_to_dec($f);
Output: 1.5406319846274E+19 = 15406319846274000000
Result from calc.exe = 15406319846273791563
Is there another method to convert large hex values?
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 been 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 ;-)
hexdec() switches from int to float when the result is too large to be represented as an int. If you want arbitrarily long values, you're probably going to have to roll your own conversion function to change the hex string to a GMP integer.
function gmp_hexdec($n) {
$gmp = gmp_init(0);
$mult = gmp_init(1);
for ($i=strlen($n)-1;$i>=0;$i--,$mult=gmp_mul($mult, 16)) {
$gmp = gmp_add($gmp, gmp_mul($mult, hexdec($n[$i])));
}
return $gmp;
}
print gmp_strval(gmp_hexdec("D5CE3E462533364B"));
Output: 15406319846273791563
$num = gmp_init( '0xD5CE3E462533364B' ); // way to input a number in gmp
echo gmp_strval($num, 10); // display value in decimal
That's the module to use. Convert it to a function and then use on your numbers.
Note: provide these hex numbers as strings so:
$num = "0x348726837469972346"; // set variable
$gmpnum = gmp_init("$num"); // gmp number format
echo gmp_strval($gmpnum, 10); // convert to decimal and print out
1.5406319846274E+19 is a limited representation of you number. You can have a more complete one by using printf()
printf("%u\n", hexdec($h));
...will output "15406319846273792000". PHP uses floats for such big numbers, so you may lose a bit of precision. If you have to work with arbitrary precision numbers, you may try the bcmath extension. By splitting the hex into two 32-bit words (which should be safe on most systems) you should be able to get more precision. For instance:
$f = bcadd(bcmul(hexdec(substr($h, 0, -8)), 0x100000000), hexdec(substr($h, 8)));
...would set $f to 15406319846273791563.
Convert HEX to DEC is easy.. But, reconstruct back hexadecimal number is very hard.
Try to use base_convert ..
$hexadecimal = base_convert(2826896153644826, 10, 16);
// result: a0b0c0d0e0f1a
Run into this issue while storing 64-bit keys in MySQL database. I was able to get a bit perfect conversion to a 64-bit signed integer (PHP limitation) using a few binary operators: (This code is 16x faster than bchexdec function and resulting variables are using half the memory on average).
function x64toSignedInt($k){
$left = hexdec(substr($k,0,8));
$right = hexdec(substr($k,8,8));
return (int) ($left << 32) | $right;
}
MySQL signed BIGINT datatype is a great match for this as an index or storage in general. HEX(column) is a simple way to convert it back to HEX within the SQL query for use elsewhere.
This solution also uses the BC Math Functions. However, an algorithm is used which does without the bcpow function. This function is a bit shorter and faster than the accepted solution, tested on PHP 7.4.
function hexDecBc(string $hex) : string
{
for ($dec = '0', $i = 0; $i < strlen($hex); $i++) {
$dec = bcadd(bcmul($dec,'16'),(string)hexdec($hex[$i]));
}
return $dec;
}
Make sure to enable gmp extension. ext-gmp
$number = gmp_strval(gmp_init('0x03....')); // outputs: 1234324....
Doesn't intval(var, base) take care of it?
From the PHP Manual.

Conversion to 64 bit int

So I am working in PHP to convert a Steam Id, which many of you may be familiar with. I have the following steam ID:
STEAM_0:1:1514332
Now, I need to convert this to the 64 bit version, which is also the community ID. After browsing Steams official release on this here: http://developer.valvesoftware.com/wiki/SteamID and after also looking many places online, I have found the following method works for this:
Let X,Y, and Z be defined by the Steam ID: STEAM_X:Y:Z
SteamCommunityID = (Z*2) + 76561197960265728 + Y
So it works! However, where seems to be a mismatch between my ACTUAL community ID, and the one I am generating
Actual: 76561197963294393
PHP generated: 76561197963294000
When reversing the equasion, to get my steam id from the community id, I get: 1514335.5
Here is a simple example of the php in question:
//STEAM_0:1:1514332
$a = (1514332 * 2) + 76561197960265728 + 1;
echo $a; //76561197963294000
Am I doing something wrong?
PHP don't have 64bit int on 32-bit binary. It is using floating point here. see how to have 64 bit integer on PHP?
The question include links to BC Math, which can be used for your problem.
Personally, I use the following code and it works perfectly for splitting the Steam ID and working out the 64-bit community ID:
$split = explode(":", $steamid); // STEAM_?:?:??????? format
$x = substr($split[0], 6, 1);
$y = $split[1];
$z = $split[2];
$w = ($z * 2) + 0x0110000100000000 + $y;
$w will be the correctly formatted ID. I thought this may be helpful since I found this trying to do the same thing :)
I have had the issue. I'm using xampp on windows and its using the 32bit version of php but i just finished making a working script :) it can convert 64bit steamid's to 32bit and back have a mess with it.
<?php
//Starting 64bit steamid
$steamid = "76561198086186258";
echo "Original 64bit steamid: $steamid";
//64bit steamid to 32bit below
$authserver = bcsub($steamid, '76561197960265728') & 1;
$authid = (bcsub($steamid, '76561197960265728')-$authserver)/2;
$steamid = "STEAM_0:$authserver:$authid";
echo "<br/>32bit steamid: $steamid";
//32bit steamid to 64bit below
$id = explode(":", $steamid);
$authserver = $id[1];
$steamid64 = $id[2];
$steamid64 = $steamid64 * 2;
$steamid64 = bcadd($steamid64, 61197960265728);
if ($authserver == 1){$steamid64 = $steamid64 + 1;};
$steamid64 = "765$steamid64";
echo "<br/>new 64bit steamid: $steamid64";
?>
try to add (string) before these calculations
$a = (string) (1514332 * 2) + 76561197960265728 + 1;
and it will work always;
demo
response: 76561197963294393
Using the BCMath extension, you can do the following:
bcadd(bcadd(bcmul('1514332', '2'), '76561197960265728'), 1)
Which is a conversion of the equation above. It returns a string and not an int, thus avoiding the 32bit int problem.
You are not doing anything wrong. The formula is correct (using a calculator I get the 'actual' number).
There must be either a rounding or calculating issue or a simple OS limit for it.
You may use the BC Math PHP extension. Here is a snippet:
//STEAM_0:1:1514332
$a = bcadd(bcadd((1514332 * 2), 76561197960265728), 1);
echo $a; //76561197963294393
Very old topic but just wanted to share how I solved it since I had 32bit PHP and no possibility of using BCMath on my host. (thanks SiPlus for solution)
Here's a snippet:
# Convert Steam ID to Steam64 ID
$idParts = explode(':', $tradeOwnerSteamId32);
$authServer = intval($idParts[1]);
$accountNumber = intval($idParts[2]);
$tradeOwnerSteamId64 = (string) $accountNumber * 2 + $authServer;
//And using it in URL
$depositorInventory = json_decode(file_get_contents("https://steamcommunity.com/profiles/[U:1:$tradeOwnerSteamId64]/inventory/json/730/2"), true);

Getting different results in PHP and JS when bit shifting

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.

Python vs PHP speed

I want to solve a problem from Project Euler (BTW, problem 25), and I found a solution in Python:
fibonacci = 1
old1 = 0
old2 = 1
limit = 1000
i = 1
while len(str(fibonacci)) < limit:
fibonacci = old1 + old2
old1 = old2
old2 = fibonacci
i = i + 1
print(i)
It took 1.5 seconds to calculate.
I implemented the same in PHP, this is the code:
$fibonacci = 1;
$old1 = 0;
$old2 = 1;
$limit = 1000;
$i = 1;
while (strlen((string)$fibonacci) < $limit){
$fibonacci = $old1 + $old2;
$old1 = $old2;
$old2 = $fibonacci;
$i = $i + 1;
}
print($i);
And it took more than 30 minutes, and still calculating...
I know that Python is considered faster than PHP, but still it shouldn't be so big a difference. How to improve my PHP code to get the results faster, if there is a way to do it?
EDIT:
I edit this post based on comments below so first my solution was not going to work.
One solution can be instead of old while to put this one:
while (strlen(number_format($fibonacci, 0, '', '')) < $limit){ ... }
But again is a big speed issue.
So the final solution is using BCMath:
$fibonacci = '1';
$old1 = '0';
$old2 = '1';
$limit = 1000;
$i = 1;
while (strlen($fibonacci) < $limit){
$fibonacci = bcadd($old1, $old2);
$old1 = $old2;
$old2 = $fibonacci;
$i = $i + 1;
}
echo $fibonacci . "<br />";
print($i);
So you can get the results at the same speed as Python in PHP.
Definitely, the PHP is going into an infinite loop. There's no way it could be taking that long if there wasn't something wrong...
I don't think counting the digits of these numbers with strlen is going to work in PHP. PHP is dealing with the numbers in scientific notation, in lower precision than Python.
I added debugging echo statements to PHP, to print out $fibonacci and $i for each step.
A typical Python line looks like
fib is 7540113804746346429
i is 92
In PHP, that's
fib is 7.54011380475E+18
i is 92
To accomplish this in PHP, you'll probably need to use a higher precision math library.
Check out http://www.php.net/manual/en/book.bc.php - you can use the bcadd function to accomplish the addition, and it will work as it does in Python.
It isn't a speed issue, it's a logic problem in the while condition for termination.
It's probably not going to finish. When you convert the current value of $fibonacci to a string in your while test, it will be converted to scientific format and truncated to a limited set of decimal places (dependent on your precision setting) when you cast it to string. That number of digits will be a lot less than 1000, so the while termination condition won't ever be met.
The problem is, that you are working with big numbers. You should use BC Math Functions (php.net/bc). So your code can be:
$fibonacci = "1";
$old1 = "0";
$old2 = "1";
$limit = 1000;
$i = 1;
while (strlen($fibonacci) < $limit){
$fibonacci = bcadd($old1, $old2);
$old1 = $old2;
$old2 = $fibonacci;
$i = $i + 1;
}
print($i);
I have tried it and it takes about 0.095s.
Many of project Euler problems will have to handle big numbers.
PHP will make your big numbers look like 2.579234678963E+12 which is the Exponential representation of the number... It's obviously hard to work with.
So, for most of problems, it's best to go with BCMath Functions. This will keep your number as it is, even if it is a giant number.
Note that using echo bcmul(500,500); will never be as fast as echo 500*500. And, BCMath function return values are always strings.
To fix your problem replace all arithmetic operations with the corresponding BCMath function.
I optimized a bit the Python code. Using len(str()) to check the number of digits is very slow. Replaced by math.log10 run your program much faster
The first term in the Fibonacci sequence to contain 1000 digits is : 4782
Calculated in 0.008573 seconds
import time
from math import log10
def digits(n): # Return the number of digits for n>=1
return int(log10(n))+1
fibonacci = 1L # Thanks to Python to handle very big numbers
old1 = 0
old2 = 1
limit = 1000
i = 1
start = time.time() #Start timer for bench
while digits(fibonacci) < limit:
fibonacci = old1 + old2
old1 = old2
old2 = fibonacci
i += 1
print "The first term in the Fibonacci sequence to contain %s digits is : %s" % (str(limit), str(i))
print "Calculated in %3.6f seconds" % (time.time() - start)
Since the problem seems to be with converting to strings, here's a much faster way to do it that doesn't require it. This is essentially the same algorithm as you have posted (so I don't feel bad showing it to you) but demonstrates how to use division to test the length of an integer instead of converting it to a string.
def fibonacci_digits(limit):
limit = 10**limit
fib = 1
old1 = 0
old2 = 1
i = 1
size = 1
while size < limit:
fib = old1 + old2
if not size//fib: # // is pythons integer division operator, not a comment
size *= 10
old1 = old2
old2 = fib
i += 1
return i
print fibonacci_digits(1000)
Converting to a string is slow and is almost never the right thing to do. Here's the timeit results:
$ python -mtimeit -s'import fib' 'fib.fibonacci_digits(1000)'
10 loops, best of 3: 30.2 msec per loop
$ python -mtimeit -s'import fib' 'fib.fibonacci_digits2(1000)'
10 loops, best of 3: 1.41 sec per loop

Categories