Calculating decimal from most significant bits & least significant bits in PHP - php

I'm a little stumped here. I have 2 32-bit integers, one for the most significant bits & the other is the least. How do I find the decimal equivalent from those two in PHP?
Update:
I have tried the suggestion from #bwoebi and modified it a little. Here's the code:
$value=get64($msb, $lsb);
function get64($msb, $lsb) {
$count = count($lsb);
for($i=0; $i < $count; $i++) {
$value[$i] = bcadd(bcmul($msb[$i], bcpow(2, 32)), $lsb[$i] > 0?$lsb[$i]:bcadd(bcsub(bcpow(2, 32), $lsb[$i]), 2 << 30)); // $a most significant bits, $b least significant bits
}
}
Output:
msb=Array ( [0] => INTEGER: 0 [1] => INTEGER: 0 )
lsb=Array ( [0] => INTEGER: 143 [1] => INTEGER: 0 )
value=Array ( [0] => 2147483648 [1] => 2147483648 )
The output does not look right...I would have expected 143 as value[0]. Any input?

bcadd(bcmul($a, bcpow(2, 32)), $b >= 0?$b:bcsub(bcpow(2, 32), $b)); // $a most significant bits, $b least significant bits
should do the job. I am using the bc library as there maybe imprecisions when working with normal operators on the 32 bit systems (It would be converted to float).

You can use the BC Math or GNU Multiple Precision extensions to perform arithmetic with values too large for native PHP variables.

Related

Converting long strings to decimals with more than 13 places

This function is converting an array which may contain strings to numbers which may or may not have a decimal.
function toNumberArray(array $stringArray) {
print_r ($stringArray);
echo "<hr>";
$n = [];
for ($i = 0; $i < count($stringArray); $i++) {
$n[] = settype ( $stringArray[$i],"float");
$x = (float) $stringArray[$i];
echo $x;
echo "<br>";
}
return $n;
}
print_r (toNumberArray(["1.123456789012345","2.2000000000000002","3.2999999999999998"]));
Results:
Array ( [0] => 1.123456789012345 [1] => 2.2000000000000002 [2] => 3.2999999999999998 )
1.1234567890123
2.2
3.3
Array ( [0] => 1 [1] => 1 [2] => 1 )
Question:
Why is settype not converting the string to a float?
How to convert if there are 14 or more places after the decimal?
It is converting to a PHP float which is a 64-bit IEEE floating point number. You are probably expecting that PHP uses a 32-bit IEEE floating point number for float and a 64-bit IEEE floating point number for a double'. But, in PHPfloatanddouble` are synonyms. (see the link in jorgonor's comment).
You could use PHP's round function to convert the 64-bit number to 6 or 7 decimal points to simulate the effect you are probably looking for. See http://php.net/manual/en/function.round.php

Unexpected behaviour in an array with some values

My code is:
$arr=[02,05,07,08,09];
print_r($arr)
and output is:
Array
(
[0] => 2
[1] => 5
[2] => 7
[3] => 0
[4] => 0
)
Why it converts 08 and 09 to 0??
Numbers beginning with a zero are considered to be in base 8.
See PHP docs: Integers - Syntax.
To use octal notation, precede the number with a 0 (zero). To use hexadecimal notation precede the number with 0x. To use binary notation precede the number with 0b.
its considered as octal number. because you are starting it from zero.
$a = 1234; // decimal number
$a = -123; // a negative number
$a = 0123; // octal number (equivalent to 83 decimal)
$a = 0x1A; // hexadecimal number (equivalent to 26 decimal)
$a = 0b11111111; // binary number (equivalent to 255 decimal)

Why for with float step dont do last iteration?

Why does my for loop with a float step (0.1) don't do the last iteration in PHP - any version?
My test code:
$procents_list = [];
for($i = 0.5; $i <= 1.5; $i += 0.1)
{
$procents_list[] = $i;
}
print_r($procents_list);
Iteration from 5 to 15 with step 1 all ok.
Why that print:
Array
(
[0] => 0.5
[1] => 0.6
[2] => 0.7
[3] => 0.8
[4] => 0.9
[5] => 1
[6] => 1.1
[7] => 1.2
[8] => 1.3
[9] => 1.4
)
Computers use Base-2 (0,1) instead of Base-10 (0,1,2,...9) to represent numbers. In Base-10, some numbers cannot be represented exactly (like 1/3=0.33333). In Base-2, a different set of numbers cannot be represented exactly. In fact, 1/10, which is 0.1 in decimal, has no exact representation in binary. So, math with floats can do weird things and should never be taken as exact values.
I couldn't figure out how to get PHP to print out all the digits without rounding, but writing the same example in Java prints out the following values:
0.5
0.6
0.70000005
0.8000001
0.9000001
1.0000001
1.1000001
1.2000002
1.3000002
1.4000002
So, the value you were getting was slightly larger than 1.5 and the loop thus ended.
In this case, one alternative is to just use integers for the loop and divide by 10 when putting them in the array:
$procents_list = [];
for ($i = 5; $i <= 15; $i += 1)
{
$procents_list[] = $i / 10;
}
print_r($procents_list);

php : result of sum array values is wrong

I have an array:
$test =array('49'=> '-0','51'=> '-0','50'=> '0','53'=> '-1.69','55'=> '0','57'=> '-2','59'=> '-6','60'=> '-12','65'=> '0','66'=> '0','67'=> '21.69','69'=> '0','70'=> '0','71'=> '0',);
echo "\n".'===== First Method ========';
echo "\n\n".print_r($test);
echo "\n array_sum: ".array_sum($test);
echo "\n\n".'===== Second Method ========';
$total = 0;foreach($test as $value) $total += $value;
echo "\n foreach:".$total."\n";
the result is
gd#gd:~/Desktop$ php test.php
===== First Method ========Array
(
[49] => -0
[51] => -0
[50] => 0
[53] => -1.69
[55] => 0
[57] => -2
[59] => -6
[60] => -12
[65] => 0
[66] => 0
[67] => 21.69
[69] => 0
[70] => 0
[71] => 0
)
1
array_sum: 3.5527136788005E-15
===== Second Method ========
foreach:3.5527136788005E-15
it is wrong, the result should be 0, not 3.5527136788E-15, how to fix it ?
This is just your standard floating point arithmetic precision error.
php -r "echo -1.69 + -2 + -6 + -12 +21.69;"
3.5527136788005E-15%
You can fix it by using ints rather than floats. For example, if you always expect 2 digits of precision, multiply all your numbers by 100, round them off to ints, sum them, and divide by 100.
php -r "echo (-169 + -200 -1200 +2169 + -600) / 100;"
0%
You are doing array_sum with strings. Remove the quotes on the values, or covert them to integers before using array_sum - I imagine it is converting the strings to integers incorrectly - only on my phone so can't check specifics.
Hope this helps.
Why not just give the values as floating point numbers rather than enclosing them in quotes. That would basically make it a string summation and strange result is expected. I think in before PHP version 4.something it used to convert the string to numbers. It might especially be problem with decimal numbers.
This is just an example of floating point imprecision. It's impossible to represent .69 exactly in binary (much like it's impossible to represent 1/3 exactly in decimal).
If you need exact numbers, you can look into using the bcmath php extension.

Split an array into two evenly by it's values

array
1703 => float 15916.19738
5129 => float 11799.15419
33 => float 11173.49945
1914 => float 8439.45987
2291 => float 6284.22271
5134 => float 5963.14065
5509 => float 5169.85755
4355 => float 5153.80867
2078 => float 3932.79341
31 => float 3924.09928
5433 => float 2718.7711
3172 => float 2146.1932
1896 => float 2141.36021
759 => float 1453.5501
2045 => float 1320.74681
5873 => float 1222.7448
2044 => float 1194.4903
6479 => float 1074.1714
5299 => float 950.872
3315 => float 878.06602
6193 => float 847.3372
1874 => float 813.816
1482 => float 330.6422
6395 => float 312.1545
6265 => float 165.9224
6311 => float 122.8785
6288 => float 26.5426
I would like to distribute this array into two arrays both ending up with a grand total (from the float values) to be about the same. I tried K-Clustering but that distributes higher values onto one array and lower values onto the other array. I'm pretty much trying to create a baseball team with even player skills.
Step 1: Split the players into two teams. It doesn't really matter how you do this, but you could do every other one.
Step 2: Randomly switch two players only if it makes the teams more even.
Step 3: Repeat step 2 until it converges to equality.
$diff = array_sum($teams[0]) - array_sum($teams[1]);
for ($i = 0; $i < 1000 && $diff != 0; ++$i)
{
$r1 = rand(0, 8); // assumes nine players on each team
$r2 = rand(0, 8);
$new_diff = $diff - ($teams[0][$r1] - $teams[1][$r2]) * 2;
if (abs($new_diff) < abs($diff))
{
// if the switch makes the teams more equal, then swap
$tmp = $teams[0][$r1];
$teams[0][$r1] = $teams[1][$r2];
$teams[1][$r2] = $tmp;
var_dump(abs($new_diff));
$diff = $new_diff;
}
}
You'll have to adapt that code to your own structures, but it should be simple.
Here's a sample output:
int(20)
int(4)
int(0)
I was using integers from 0 to 100 to rate each player. Notice how it gradually converges to equality, although an end result of 0 is not guaranteed.
You can stop the process after a fixed interval or until it reaches some threshold.
There are more scientific methods you could use, but this works well.
This is extremely simplistic, but have you considered just doing it like a draft? With the array sorted as in your example, Team A gets array[0], Team B gets array[1] and array[2] the next two picks go to Team A, and so on.
For the example you give, I got one team with ~50,000 and the other with ~45,000.

Categories