PHP array product combinations - php

I have produced an array of prime factors of a number - this is supposed to be the hard part! However, in order to create a list of the divisors of the same number the prime factors need to be combined in every which possible way. Something that I'm struggling to do with php.
For example I have an array of:
2
2
2
3
3
41
53
...for the number 156456; multiply them all together and you get back to the number. What I need to do is to multiply all of the duos together e.g. 2x2, 2x3, 2x53 etc and then all of the triplets together and so on until I finally multiply the 7 blocks of six together.
As you can see this will give a very large array with all of the divisors in, 4, 6, 8, 9, 12 etc. with many duplicates. I just can't seem to get from the array I have above to this array of divisors that I want. It's a case of multiplying out every possible combination of elements in the array, is there a php function for this, my search so far has been fruitless?

After reading this page: http://mathcentral.uregina.ca/QQ/database/QQ.02.06/joe1.html, I tried to build something that might work, It may not be the most efficient solution and its also limited to count($primes) <= 32 on 32 bit systems. If you need more, feel free to use a Bitset:
$primes = Array(2, 2, 2, 3, 3, 41, 53);
$num_primes = count($primes); // 7, if this is over 32, it won't work on 32bit systems
$divisors = Array();
// number of possible combinations
$limit = pow(2, $num_primes) - 1; // 127
// count a number up and use the binary
// representation to say which index is
// part of the current divisor
for($number = 0; $number <= $limit; $number++) {
$divisor = 1;
// only multiply activated bits in $number to the divisor
for($i = 0; $i < $num_primes; $i++) {
$divisor *= ($number >> $i) & 1 ? $primes[$i] : 1;
}
$divisors[] = $divisor;
}
echo implode(", ", array_unique($divisors));
This results into the following divisors:
1, 2, 4, 8, 3, 6, 12, 24, 9, 18, 36, 72, 41, 82, 164, 328, 123, 246, 492,
984, 369, 738, 1476, 2952, 53, 106, 212, 424, 159, 318, 636, 1272, 477,
954, 1908, 3816, 2173, 4346, 8692, 17384, 6519, 13038, 26076, 52152, 19557,
39114, 78228, 156456
To find all divisors you need to multiply each prime factor with each other in every possible combination. To do this I calculate the number of possible combinations ($limit). If you now count a number up to this limit the binary representation looks something like this:
7 bit
<----->
0000000 0
0000001 1
0000010 2
0000011 3
0000100 4
0000101 5
0000110 6
0000111 7
0001000 8
0001001 9
...
1111110 126
1111111 127
The current binary representation of $number represents which indexes of $primes are used to calculate the current $divisor. To show this better let's say $number = 5, which is 0000101 in binary. And the calculation for $divisor would be 2 * 1 * 2 * 1 * 1 * 1 * 1 = 4. Only the first and the third bit is set, so only the first and the third element in the array is used for the calculation.
I hope this makes it a little bit clearer.

Related

How to create an array of numbers prefixed with 0 using str_pad()?

How can I generate an array of numbers using str_pad()?
For example, from 000 to 090 or from 100 to 200.
$n2 = str_pad($n + 1, 3, 0, STR_PAD_LEFT);
The above just adds 1 to $n.
I want to create an array using this method. For example: 000, 001, 002, 003, 004 ...
For my requirements, numbers start at 000 and not 0.
Here's one way, using range. Basically just loop through the range and pad each number as you go. There may be more direct ways but this is a simple approach:
$arr = [];
foreach (range(0, 90) as $n)
{
$arr[] = str_pad($n, 3, 0, STR_PAD_LEFT);
}
var_export($arr);

Get number by knowing chance

I don't think the article title is correct so I will try to explain what I need.
ATM I have array:
array(
'start' => 1,
'end' => 10,
'lucky_numbers' => 6
);
and knowing this array I can define that chance to win is 60% out of 100%. The next part is the second array:
array(0, 1.25, 0.5, 1.25, 0, 3, 0, 1, 0.5, 1.25, 0.5, 1.25, 0, 2, 0.5, 2)
and this is the hard part. I don't have any clue how to pick one number knowing that chance to pick not a zero is 60%. Any ideas?
EDIT
this is the wheel numbers. when user spins the wheel i need to give him 60% chance to win. So 60% chance to spin not the 0
Let me see if i understand:
-This is a "slots like" winnings multiplier minigame for a game where you roll a "wheel" showing the possibles multipliers the player can win, this wheel is the second array, this array is variable in lenght.
-You want to give the player a variable chance to win (sometimes 60%, sometimes 80%, sometimes 20%).
If you only want to be sure the player doesn't get a "0%" multiplier, do the opposite, take the possibility of a "0%" to appear and put them the equivalent in the array and then fill the array with random multipliers and shuffle it.
$multipliers = [0.5, 1.25, 2, 3];
$wheel = [];
for ($i = 0; $i < $arraylenght; $i++) {
if ($i < floor($arraylenght * (1 - ((float)$luckyNumbers/10)))){
$wheel[] = 0;
} else {
$wheel[] = array_rand($multipliers);
}
}
shuffle($wheel);
Now if you also want to control the probabilities of each multiplier... That's another beast.

How to format number 300 to 3.0 in php

I have a MySQL table which contains whole number.
Units
300,
900,
600,
125,
225,
I want it to display using PHP like thus
Units
3.0,
9.0,
6.0,
1.25,
2.25,
I have tried using number_format but doesn't do the trick.
This is basic math:
echo $num * .01;
If you always want two decimal points:
echo number_format($num * .01, 2, '.', '');
If you want one decimal for x00 numbers just use make the third parameter a variable that is either 1 or 2 based on the last two digits of the original number or use the modulus operator to determine if the number is divisible by 100.
$round = ($num % 100) ? 2 : 1;
echo number_format($num * .01, $round, '.', '');

PHP Choose Random Number With Weights

Assume I want to choose a number from 1-10 at random, but there are weights to each number.
1 - 15% chance
2 - 15% chance
3 - 12% chance
4 - 12% chance
5 - 10% chance
6 - 10% chance
7 - 8% chance
8 - 8% chance
9 - 5% chance
10 - 5% chance
How would I go about coding this up in PHP?
I assume your percentages add up to 100%?
Build an array with
15 times a '1' value,
15 times a '2' value,
...
10 times a '6' value,
8 times a '7' value,
...
5 times 1 '10' value
You'll end up with a single array which contains 100 elements.
Pick an element randomly (and pop it from the array).
an example echoing value with OPs weight with the below class:
echo 1+Rand::get_weighted_rand(array(15,15,12,12,10,10,8,8,5,5));
and the class:
class Rand
{
/*
* generates a random value based on weight
* #RETURN MIXED: returns the key of an array element
* #PARAM $a ARRAY:
* the array key is the value returned and the array value is the weight
* if the values sum up to less than 100 than the last element of the array
* is the default value when the number is out of the range of other values
* #PARAM $p INT: number of digits after decimal
*
* i.e array(1=>20, 'foo'=>80): has an 80 chance of returning Foo
* i.e array('bar'=>0.5, 2=>1, 'default'=>0), 1: 98.5% chance of returning default
*/
public static function get_weighted_rand($a, $p=0)
{
if(array_sum($a)>100)
return FALSE;#total must be less than 100
$p=pow(10, $p+2);
$n=mt_rand(1,$p)*(100/$p);
$range=100;
foreach($a as $k=>$v)
{
$range-=$v;
if($n>$range)
return $k;
}
#returning default value
end($a);
return key($a);
}
}
If your weights are in percentages, pick a random number between 0 and 100, then iteratively subtract the percentages until you cross zero:
<?php
function getWeightedRandom() {
$weights = array(15, 15, 12, ...); // these should add up to 100
$r = rand(0, 99);
for ($i=0; $i<count($weights); $i++) {
$r -= $weights[$i];
if ($r < 0)
return $i+1;
}
}
?>
This has the added benefit of supporting non-integer weights.
Put them all multiple times in array, e.g. the 1 15 times, the 3 12 times and so on.
Then pick a random number from that array.
$array = array_merge (array_fill (0, 15, 1), array_fill (0, 15, 2), array_fill (0, 12, 3), array_fill (0, 12, 4), array_fill (0, 10, 5), array_fill (0, 10, 6), array_fill (0, 8, 7), array_fill (0, 8, 8), array_fill (0, 5, 9), array_fill (0, 5, 10));
$random_number = array_rand ($array);

Generating a random number but with a twist

I need to generate a random number.
But the twist is that the % of lower numbers should be greater than the higher.
For example.
rand > 1 to 100
13,
15,
12,
16,
87,
15,
27,
12,
1,
12,
98,
12,
53,
12,
14....
The bold integers will be the ones return from the 1-100 range.
The math should be like so rand = a number lower than max/2
Hope you guys can help.
Ps, How would a matrix come into this ? im not superior at maths :(
The abs answer seems to be the one.
$up = $down = 0;
while(true)
{
if(abs((rand()%150)-50) < 50)
{
$up++;
}else
{
$down++;
}
if( ($up + $down) == 500){ break;}
}
echo $up . '/' . $down;
how about
n = abs((rand()%150)-50)
$x = rand(0,1) ? rand(1,100) : rand(1,50);
Simple method: the first rand(0,1) selects between the two cases. Either 1..50 or 1..100 as random range. Since 1,100 already encompases 1,50, the latter range is selected 100% of the time, the former case only in 1 of 2 runs.
If you want a distribution where the highest numer 99 gets selected almost never, but the lower numbers 1..20 pretty frequent, then a simple rand(1,rand(1,100)) would do.
$rand = (rand() * rand()) / (getrandmax() * getrandmax());
This will give you a random number between 0 and 1 with a high probability of falling into the lower end of the range and the probability of a larger number decreasing exponentially. You can then scale this result to any range that you want.

Categories