Getting different results in PHP and JS when bit shifting - php

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.

Related

Pearson Correlation returns 0 on exact matchs

I am using this PHP routine to calc Pearson Correlation:
function correlation ($x,$y) {
$length = count($x);
$mean1 = array_sum($x)/$length;
$mean2 = array_sum($y)/$length;
$a = $b = 0;
$a2 = $b2 = 0;
$axb = 0;
for ($i = 0; $i < $length; $i++) {
$a = $x[$i]-$mean1;
$b = $y[$i]-$mean2;
$axb +=$a*$b;
$a2 += pow($a,2);
$b2 += pow($b,2);
}
if ($sqrt = sqrt($a2*$b2))
return $axb/$sqrt;
return 0;
}
When I test it for several conditions it returns 0 on exact matchs:
echo correlation([0,0,0,0,0],[0,0,0,0,0]); // Returns 0!!
echo correlation([0,0,0,0,0],[1,1,1,1,1]); // Returns 0!!
echo correlation([1,1,1,1,1],[1,1,1,1,1]); // Returns 0!!
echo correlation([0,0,0,0,0],[9,9,9,9,9]); // Returns 0!!
echo correlation([0,0,0,0,0],[0,1,2,3,4]); // Returns 0 OK
echo correlation([9,9,9,9,9],[0,1,2,3,4]); // Returns 0 OK
echo correlation([0,1,2,3,4],[0,1,2,3,4]); // Returns 1 OK
Why? and How to accomplish that? Thank you!
For info:
A Pearson correlation is a number between -1 and 1 that indicates the
extent to which two variables are linearly related. The Pearson
correlation is also known as the “product moment correlation
coefficient” (PMCC) or simply “correlation”.
Approach 1 (doing at your own):
Using PHP to statistics is a hard path.
First of all, as you're using a weak typed language (you don't need to specify the types on variables), the language can interpret as int so, you need to set all of your variables on type float and execute again to run this. You can have some problems with float in PHP, see here why I talking this: https://3v4l.org/1FU9J
But if you don't mind about high precision, you can modify your precision you can set your round() function or you can set ini_set('precision', 3); to get the precision on your data.
Another thing. If you need precision, you need to use bc extension because floating point in PHP is a problem and can affect your results.
Look more about bc math extension here: https://www.php.net/manual/en/book.bc.php or try to use another language.
Some references about the floating point:
https://www.leaseweb.com/labs/2013/06/the-php-floating-point-precision-is-wrong-by-default/
Problem with Floats! (in PHP)
Approach 2 (using language functions):
And, PHP have some functions to help in this. So, if this isn't a homework to learn or something like this, you can try this: https://www.php.net/manual/en/function.stats-stat-correlation.php

Is there a clever way to do this with pure math

I've got this spot of code that seems it could be done cleaner with pure math (perhaps a logarigthms?). Can you help me out?
The code finds the first power of 2 greater than a given input. For example, if you give it 500, it returns 9, because 2^9 = 512 > 500. 2^8 = 256, would be too small because it's less than 500.
function getFactor($iMaxElementsPerDir)
{
$aFactors = range(128, 1);
foreach($aFactors as $i => $iFactor)
if($iMaxElementsPerDir > pow(2, $iFactor) - 1)
break;
if($i == 0)
return false;
return $aFactors[$i - 1];
}
The following holds true
getFactor(500) = 9
getFactor(1000) = 10
getFactor(2500) = 12
getFactor(5000) = 13
You can get the same effect by shifting the bits in the input to the right and checking against 0. Something like this.
i = 1
while((input >> i) != 0)
i++
return i
The same as jack but shorter. Log with base 2 is the reverse function of 2^x.
echo ceil(log(500, 2));
If you're looking for a "math only" solution (that is a single expression or formula), you can use log() and then take the ceiling value of its result:
$factors = ceil(log(500) / log(2)); // 9
$factors = ceil(log(5000) / log(2)); // 13
I seem to have not noticed that this function accepts a second argument (since PHP 4.3) with which you can specify the base; though internally the same operation is performed, it does indeed make the code shorter:
$factors = ceil(log(500, 2)); // 9
To factor in some inaccuracies, you may need some tweaking:
$factors = floor(log($nr - 1, 2)) + 1;
There are a few ways to do this.
Zero all but the most significant bit of the number, maybe like this:
while (x & x-1) x &= x-1;
and look the answer up in a table. Use a table of length 67 and mod your power of two by 67.
Binary search for the high bit.
If you're working with a floating-point number, inspect the exponent field. This field contains 1023 plus your answer, except in the case where the number is a perfect power of two. You can detect the perfect power case by checking whether the significand field is exactly zero.
If you aren't working with a floating-point number, convert it to floating-point and look at the exponent like in 3. Check for a power of two by testing (x & x-1) == 0 instead of looking at the significand; this is true exactly when x is a power of two.
Note that log(2^100) is the same double as log(nextafter(2^100, 1.0/0.0)), so any solution based on floating-point natural logarithms will fail.
Here's (nonconformant C++, not PHP) code for 4:
int ceillog2(unsigned long long x) {
if (x < 2) return x-1;
double d = x-1;
int ans = (long long &)d >> 52;
return ans - 1022;
}

Less than operator not working correctly in PHP 5.3.1

For the purpose of the example, var 2 is preset from a database as "147.22" type STRING. var 1 is calculated previously in the script and has 147.22 type FLOAT.
Script:
<?
$var1 = (float)$var1;
$var2 = (float)$var2;
var_dump($var1);
var_dump($var2);
if($var1 < $var2) { echo "hello"; }
?>
My expected results would be that the script NOT echo "hello" since the two values are equal in amount and type.
However here is the output I'm getting:
float(197.22)
float(197.22)
hello
If I do not mess with the types and leave the one a float and the other a string, then it still does not work (this is how I got here in the first place).
If i force the values at the time of execution like this:
$var1 = 147.22;
$var2 = 147.22;
var_dump($var1);
var_dump($var2);
if($var1 < $var2) { echo "hello"; }
?>
I get this, (and it works):
float(197.22)
float(197.22)
Notice no "hello"....
Anyone have any clue wth is going on here?
If one of the floats is calculated numerically, and one is created from string assignment, they could be different. Try the following:
$x = 147.22;
$y = 147.2200000000001;
printf("%.40f\n", $x);
printf("%.40f\n", $y);
var_dump($x);
var_dump($y);
var_dump($x < $y);
outputs
147.2199999999999988631316227838397026062012
147.2200000000001125499693443998694419860840
float(147.22)
float(147.22)
bool(true)
Cast them to a string with a specified precision for comparison.
If you are dealing with floats, then it's not safe to compare them directly, because there may be rounding or representation issues.
You'd better to check if the difference between those numbers is less than some predefined and very minimal epsilon, and then determine if they're equal, or which is the greater one.
This discussion may be worth reading: Is casting to float destructive?
EDIT:
More discussions to read:
PHP: Floating point numbers
php integer and float comparison mismatch

Hexadecimal XOR with 2 values in PHP and JavaScript

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

Why does the '<<' operator sometimes behave differently in Javascript and PHP?

Take the following code snippet:
<script>
var x = 25;
document.write(x << 9);
</script>
<?php
$x = 25;
echo ($x << 9);
?>
This outputs: 12800 12800
OK. Normal so far... Now lets try this:
<script>
var x = 12345678;
document.write(x << 9);
</script>
<?php
$x = 12345678;
echo ($x << 9);
?>
This time the output is 2026019840 6320987136
Why are the latter two values different? And, most importantly (to me), how do I get the PHP implementation to do what the Javascript implementation does? In other words, I want my PHP code to output 2026019840 instead of 6320987136
use (x << 9) % 0x100000000 or its PHP equivalent. (or what you just said)
PHP is giving you a 64 bit result. Javascript is just giving you the lower 32bits. If you use (x << 9) & 0xFFFFFFFF in PHP you'll get the low 32 bits.
you may run into problems with the sign bit though. Try (23456789 << 9)

Categories