PHP make combination with exponents - php

I've been looking in to a math problem: to find the factors of a large number.
I've come to the method of "prime factorization", that all went well to code in php.
But then, say i want to know the factors of the number 196 (being: 1, 2, 4, 7, 14, 28, 49, 98, 196), i've found that the prime factorization of this number is: (2^2)(7^2).
To find the factors, you'll have to make all the possible combinations between the two and muttiply them:
(2^0)(7^0) = 1
(2^1)(7^0) = 2
(2^2)(7^0) = 4
(2^0)(7^1) = 7
(2^1)(7^1) = 14
(2^2)(7^1) = 28
(2^0)(7^2) = 49
(2^1)(7^2) = 98
(2^2)(7^2) = 196
This is where i'm stuck.
I need to find a function that will make a combination of these items (the exponent may not be higher then the one is the prime factorization of that number). This function will have to work on N factors (N is a number > 0 and smaller than 100).
I hope you understand my problem and have some ideas on how to solve it!

The following will print the prime factor of $N = '196' along with the number of exponents.
<?php
function is_prime($N) {
if($N == 2) return true;
for($i = 3 ; $i * $i <= $N; $i++ ) {
if($N % $i == 0) return false;
}
return true;
}
$a = array();
$N = '196';
for($i = 2; $i <= $N; $i++) {
while($N % $i == 0 && is_prime($i)) {
if(!isset($a[$i])) {
$a[$i] = 0;
}
$a[$i]++;
$N = $N / $i;
}
}
print_r($a);
?>

Related

PHP random numbers frequency of occurrence

In PHP I want to generate random numbers from 1 to 10 in a loop.
So for example:
$factor="1"; // this will be changed in another area
for ($i=0;$i<10;$i++) {
if ($factor=="1") {$output = rand(1,10);}
else if ($factor=="2") {$output = rand(1,10);}
else {$output = rand(1,10);}
}
Now to explain this - In result I want to receive 10 random numbers, but when $factor = "2", in that case I want to receive numbers from 6 to 10 more frequently as lower numbers.
It means, from 10 numbers I need to have 80% higher random numbers (it means larger than 5) and in 20% lower numbers (5 or lower).
E.g. 1,2,6,7,8,9,7,9,8,6 (1,2 are the only lower numbers = 20%, the rest are higher = 80)
If the $factor will change, then I want to change the percentage, in that case for example 40% lower numbers, 60% higher numbers.
The idea I have is to put each output in the loop to an array, then check each result and somehow calculate, if there is no 80% of larger numbers, then get random numbers again for those, but this seems to be an overkill.
Is there a simplier solution?
Let's go with the percentages you mention and first generate a random number between 1 and 100. Then the lower number, 1 to 20, have to represent outputs 1 to 5 and the higher numbers, 21 to 100, have to represent output 6 to 10. In PHP that would look like this:
function HighMoreOften()
{
$percentage = rand(1, 100);
if ($percentage <= 20) {
return rand(1, 5);
} else {
return rand(6, 10);
}
}
That should do the trick. You can also convert the percentage you got into the output, this would probably be slightly faster:
function HighMoreOften()
{
$percentage = rand(1, 100);
if ($percentage <= 20) {
return ceil($percentage / 5);
} else {
return 6 + ceil(($percentage - 20) / 20);
}
}
but personally I think the first version is easier to understand and change.
To change frequency you gonna need an array of numbers. And a sum to this direction. frequency is the relation of something between an array of things.
$t = 0;
// $factor = 1; // let's say that this means 20%
$factor = 2; // let's say that this means 40%
if ($factor === 1) {
for ($i = 1; $i <= 80; $i++) {
$t += rand(1,10);
}
for ($i = 1; $i <= 20; $i++) {
$t += rand(6,10);
}
} else if ($factor === 2) {
for ($i = 1; $i <= 60; $i++) {
$t += rand(1,10);
}
for ($i = 1; $i <= 40; $i++) {
$t += rand(6,10);
}
} else {
for ($i = 1; $i <= 100; $i++) {
$t += rand(1,10);
}
}
echo round(($t/100), 0);
Something like that! :)
I came with a very simple (maybe creepy) solution, but this works as I wanted:
echo print_r(generate("2"));
function generate($factor) {
$nums=array();
for ($i=0;$i<10;$i++) {
if ($i<$factor) {$rnd = rand(1,5);}
else {$rnd = rand(6,10);}
array_push($nums,$rnd);
}
return $nums;
}
I can also shuffle the final array results, as the lower numbers will be on the beginning always, but in my case it doesn't matter.

Possible combinations of binary

The problem statement is as following:
A particular kind of coding which we will refer to as "MysteryCode" is a binary system of encoding in which two successive values, differ at exactly one bit, i.e. the Hamming Distance between successive entities is 1. This kind of encoding is popularly used in Digital Communication systems for the purpose of error correction.
LetMysteryCodes(N)represent the MysteryCode list for N-bits.
MysteryCodes(1) = 0, 1 (list for 1-bitcodes,in this order)
MysteryCodes(2) = 00, 01, 11, 10 (list for 2-bitcodes,in this order)
MysteryCodes(3) =000, 001, 011, 010,110, 111, 101, 100 (list for 3-bitcodes,in this order)
There is a technique by which the list of (N+1) bitcodescan be generated from (N)-bitcodes.
Take the list of N bitcodesin the given order and call itList-N
Reverse the above list (List-N), and name the new reflected list: Reflected-List-N
Prefix each member of the original list (List-N) with 0 and call this new list 'A'
Prefix each member of the new list (Reflected-List-N) with 1 and call this new list 'B'
The list ofcodeswith N+1 bits is the concatenation of Lists A and B.
A Demonstration of the above steps: Generating the list of 3-bitMysteryCodesfrom 2-BitMysteryCodes
2-bit list ofcodes:00, 01, 11, 10
Reverse/Reflect the above list:10, 11, 01, 00
Prefix Old Entries with 0:000, 001, 011, 010
Prefix Reflected List with 1:110, 111, 101, 100
Concatenate the lists obtained in the last two steps:000, 001, 011, 010, 110, 111, 101, 100
Your Task
Your task is to display the last N "MysteryCodes" from the list of MysteryCodes for N-bits. If possible, try to identify a way in which this list can be generated in a more efficient way, than iterating through all the generation steps mentioned above.
More efficient or optimized solutions will receive higher credit.
Input Format
A single integer N.
Output Format
N lines, each of them with a binary number of N-bits. These are the last N elements in the list ofMysteryCodesfor N-bits.
Input Constraints 1 = N = 65
Sample Input 1
1
Sample Output 1
1
Explanation for Sample 1
Since N = 1, this is the (one) last element in the list ofMysteryCodesof 1-bit length.
Sample Input 2
2
Sample Output 2
11
10
Explanation for Sample 2 Since N = 2, these are the two last elements in the list ofMysteryCodesof 2-bit length.
Sample Input 3
3
Sample Output 3
111
101
100
$listN = 25;
$bits = array('0','1');
//check if input is valid or not
if(!is_int($listN))
{
echo "Input must be numeric!";
}
if($listN >= 1 && $listN <=65){
if($listN == 1){
echo '1'; exit;
}
ini_set('memory_limit', -1);
for($i=1; $i<=($listN - 1); $i++){
$reverseBits = array_reverse($bits);
$prefixBit = preg_filter('/^/', '0', $bits);
$prefixReverseBits = preg_filter('/^/', '1', $reverseBits);
$bits = array_merge($prefixBit, $prefixReverseBits);
unset($prefixBit, $prefixReverseBits, $reverseBits);
}
$finalBits = array_slice($bits, -$listN);
foreach($finalBits as $k=>$v){
echo $v."\n";
}
}
else{
echo "Invalid input!";
}
I have tried above solution, but didnt worked for input greater than 20.
for eg. If the input is 21, I got "Couldnt allocate memory" error.
It will be great if somebody figure out the optimized solutions...
The numbers follow a pattern which I transformed to below code.
Say given number is N
then create a N x N matrix and fill it's first column with 1's
and all other cells with 0's
Start from rightmost column uptil 2nd column.
For any column X start from bottom-most row and fill values like below:
Fill 2^(N - X + 1)/2 rows with 0's.
Fill 2^(N - X + 1) rows with 1's and then 0's alternatively.
Repeat step 2 till we reach topmost row.
Print the N x N matrix by joining the values in each row.
<?php
$listN = 3;
$output = [];
for ($i = 0; $i < $listN; $i++) {
$output[$i] = [];
for ($j = 0; $j < $listN; $j++) {
$output[$i][$j] = 0;
}
}
$output[$listN - 1][0] = 1;
for ($column = 1; $column < $listN; $column++) {
$zeroFlag = false;
for ($row = $listN - 1; $row >= 0;) {
$oneZero = 1;
if (!$zeroFlag) {
for ($k = 1; $k <= pow(2, $column) / 2 && $row >= 0; $k++) {
$output[$row][$listN - $column] = 0;
$row--;
$zeroFlag = true;
}
}
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
$oneZero = 0;
for ($k = 1; $k <= pow(2, $column) && $row >= 0; $k++) {
$output[$row][$listN - $column] = $oneZero;
$row--;
}
}
}
for ($i = 0; $i < $listN; $i++) {
$output[$i][0] = 1;
}
for ($i = 0; $i < $listN; $i++) {
print(join('', $output[$i]));
print("\n");
}

PHP for loop displaying strange results

I have this code:
for($i = 1; $i <= $max; $i+=0.1) {
echo "$i<br>";
}
if the variable $max = 6; the results are: 1, 1.1, 1.2, 1.3 .... 5.8, 5.9, 6 , but when the variable $max = 4 the results are: 1, 1.1 ... 3.8, 3.9, but the number 4 is missing.
Please explain this behavior, and a possible solution to this.
the results are the same when i use the condition $i <= $max; or $i < $max;
The bug occurs when $max is 2, 3 or 4
From http://php.net/manual/en/language.types.float.php
Additionally, rational numbers that are exactly representable as floating point numbers in base 10, like 0.1 or 0.7, do not have an exact representation as floating point numbers in base 2, which is used internally, no matter the size of the mantissa. Hence, they cannot be converted into their internal binary counterparts without a small loss of precision.
So to overcome this you could multiply your numbers by 10.
So $max is 40 or 60.
for($i = 10; $i <= $max; $i+=1) {
echo ($i/10).'<br>';
}
$err = .000001//allowable error
for($i = 1; $i <= $max+$err; $i+=0.1) {
echo "$i<br>";
}
You can use of number_format()
<?php
$max=6;
for($i = 1; number_format($i,2) < number_format($max,2); $i+=0.1) {
echo $i."<br>";
}
?>
You should set the precision when using integers,
like this:
$e = 0.0001;
while($i > 0) {
echo($i);
$i--;
}

Project Euler #23: Non-abundant sums

I'm struggling with Project Euler problem 23: Non-abundant sums.
I have a script, that calculates abundant numbers:
function getSummOfDivisors( $number )
{
$divisors = array ();
for( $i = 1; $i < $number; $i ++ ) {
if ( $number % $i == 0 ) {
$divisors[] = $i;
}
}
return array_sum( $divisors );
}
$limit = 28123;
//$limit = 1000;
$matches = array();
$k = 0;
while( $k <= ( $limit/2 ) ) {
if ( $k < getSummOfDivisors( $k ) ) {
$matches[] = $k;
}
$k++;
}
echo '<pre>'; print_r( $matches );
I checked those numbers with the available on the internet already, and they are correct. I can multiply those by 2 and get the number that is the sum of two abundant numbers.
But since I need to find all numbers that cannot be written like that, I just reverse the if statement like this:
if ( $k >= getSummOfDivisors( $k ) )
This should now store all, that cannot be created as the sum of to abundant numbers, but something is not quit right here. When I sum them up I get a number that is not even close to the right answer.
I don't want to see an answer, but I need some guidelines / tips on what am I doing wrong ( or what am I missing or miss-understanding ).
EDIT: I also tried in the reverse order, meaning, starting from top, dividing by 2 and checking if those are abundant. Still comes out wrong.
An error in your logic lies in the line:
"I can multiply those by 2 and get the number that is the sum of two abundant numbers"
You first determine all the abundant numbers [n1, n2, n3....] below the analytically proven limit. It is then true to state that all integers [2*n1, 2*n2,....] are the sum of two abundant numbers but n1+n2, and n2+n3 are also the sum of two abundant numbers. Therein lies your error. You have to calculate all possible integers that are the sum of any two numbers from [n1, n2, n3....] and then take the inverse to find the integers that are not.
I checked those numbers with the available on the internet already, and they are correct. I can multiply those by 2 and get the number that is the sum of two abundant numbers.
No, that's not right. There is only one abundant number <= 16, but the numbers <= 32 that can be written as the sum of abundant numbers are 24 (= 12 + 12), 30 (= 12 + 18), 32 (= 12 + 20).
If you have k numbers, there are k*(k+1)/2 ways to choose two (not necessarily different) of them. Often, a lot of these pairs will have the same sum, so in general there are much fewer than k*(k+1)/2 numbers that can be written as the sum of two of the given k numbers, but usually, there are more than 2*k.
Also, there are many numbers <= 28123 that can be written as the sum of abundant numbers only with one of the two abundant numbers larger than 28123/2.
This should now store all, that cannot be created as the sum of to abundant numbers,
No, that would store the non-abundant numbers, those may or may not be the sum of abundant numbers, e.g. 32 is a deficient number (sum of all divisors except 32 is 31), but can be written as the sum of two abundant numbers (see above).
You need to find the abundant numbers, but not only to half the given limit, and you need to check which numbers can be written as the sum of two abundant numbers. You can do that by taking all pairs of two abundant numbers (<= $limit) and mark the sum, or by checking $number - $abundant until you either find a pair of abundant numbers or determine that none sums to $number.
There are a few number theoretic properties that can speed it up greatly.
Below is php code takes 320 seconds
<?php
set_time_limit(0);
ini_set('memory_limit', '2G');
$time_start = microtime(true);
$abundantNumbers = array();
$sumOfTwoAbundantNumbers = array();
$totalNumbers = array();
$limit = 28123;
for ($i = 12; $i <= $limit; $i++) {
if ($i >= 24) {
$totalNumbers[] = $i;
}
if (isAbundant($i)) {
$abundantNumbers[] = $i;
}
}
$countOfAbundantNumbers = count($abundantNumbers);
for ($j = 0; $j < $countOfAbundantNumbers; $j++) {
if (($j * 2) > $limit)
break; //if sum of two abundant exceeds limit ignore that
for ($k = $j; $k < $countOfAbundantNumbers; $k++) { //set $k = $j to avoid duble addtion like 1+2, 2+1
$l = $abundantNumbers[$j] + $abundantNumbers[$k];
$sumOfTwoAbundantNumbers[] = $l;
}
}
$numbers = array_diff($totalNumbers, $sumOfTwoAbundantNumbers);
echo '<pre>';print_r(array_sum($numbers));
$time_end = microtime(true);
$execution_time = ($time_end - $time_start);
//execution time of the script
echo '<br /><b>Total Execution Time:</b> ' . $execution_time . 'seconds';
exit;
function isAbundant($n) {
if ($n % 12 == 0 || $n % 945 == 0) { //first even and odd abundant number. a multiple of abundant number is also abundant
return true;
}
$k = round(sqrt($n));
$sum = 1;
if ($n >= 1 && $n <= 28123) {
for ($i = 2; $i <= $k; $i++) {
if ($n % $i == 0)
$sum+= $i + ( $n / $i);
if ($n / $i == $i) {
$sum = $sum - $i;
}
}
}
return $sum > $n;
}

how to find the sum of all the multiples of 3 or 5 below 1000 in php, issue?

i have an small issue with the way this problem is resolved.
some would say: println((0 /: ((0 until 1000).filter(x => x % 3 == 0 || x % 5 == 0))) (_+_)) is the solution witch adds to 233168
my way was to do:
$maxnumber = 1000;
for ($i = 3; $i < $maxnumber; $i += 3)
{
$t += $i;
echo $i.',';
}
echo '<br>';
for ($j = 5; $j < $maxnumber; $j += 5)
{
$d += $j;
echo $j.',';
}
echo '<br>';
echo $t;
echo '<br>';
echo $d;
echo '<br>';
echo $t+$d;
this will give me :
3,6,9,12,15,18,21,24,27,30,33,36,39,42,45,48,51,54,57,60,63,66,69,72,75,78,81,84,87,90,93,96,99,102,105,108,111,114,117,120,123,126,129,132,135,138,141,144,147,150,153,156,159,162,165,168,171,174,177,180,183,186,189,192,195,198,201,204,207,210,213,216,219,222,225,228,231,234,237,240,243,246,249,252,255,258,261,264,267,270,273,276,279,282,285,288,291,294,297,300,303,306,309,312,315,318,321,324,327,330,333,336,339,342,345,348,351,354,357,360,363,366,369,372,375,378,381,384,387,390,393,396,399,402,405,408,411,414,417,420,423,426,429,432,435,438,441,444,447,450,453,456,459,462,465,468,471,474,477,480,483,486,489,492,495,498,501,504,507,510,513,516,519,522,525,528,531,534,537,540,543,546,549,552,555,558,561,564,567,570,573,576,579,582,585,588,591,594,597,600,603,606,609,612,615,618,621,624,627,630,633,636,639,642,645,648,651,654,657,660,663,666,669,672,675,678,681,684,687,690,693,696,699,702,705,708,711,714,717,720,723,726,729,732,735,738,741,744,747,750,753,756,759,762,765,768,771,774,777,780,783,786,789,792,795,798,801,804,807,810,813,816,819,822,825,828,831,834,837,840,843,846,849,852,855,858,861,864,867,870,873,876,879,882,885,888,891,894,897,900,903,906,909,912,915,918,921,924,927,930,933,936,939,942,945,948,951,954,957,960,963,966,969,972,975,978,981,984,987,990,993,996,999
5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,255,260,265,270,275,280,285,290,295,300,305,310,315,320,325,330,335,340,345,350,355,360,365,370,375,380,385,390,395,400,405,410,415,420,425,430,435,440,445,450,455,460,465,470,475,480,485,490,495,500,505,510,515,520,525,530,535,540,545,550,555,560,565,570,575,580,585,590,595,600,605,610,615,620,625,630,635,640,645,650,655,660,665,670,675,680,685,690,695,700,705,710,715,720,725,730,735,740,745,750,755,760,765,770,775,780,785,790,795,800,805,810,815,820,825,830,835,840,845,850,855,860,865,870,875,880,885,890,895,900,905,910,915,920,925,930,935,940,945,950,955,960,965,970,975,980,985,990,995
$t - 166833
$d - 99500
and total:
266333
why am i wrong?
Some numbers are multiples of both 3 and 5. (Your algorithm adds these numbers to the total twice.)
Because 6 * 5 == 30 and 10 * 3 == 30, you're adding the some numbers up twice.
$sum = 0;
$i = 0;
foreach(range(0, 999) as $i) {
if($i % 3 == 0 || $i % 5 == 0) $sum += $i;
}
Because you double-count numbers that are multiple of both 3 and 5, i.e. multiples of 15.
You can account for this naively by subtracting all multiples of 15.
for ($j = 15; $j < $maxnumber; $j += 15)
{
$e += $j;
echo $j.',';
}
$total = $total - $d;
In your case, if it is 15, you will add the number twice.
Try this:
$t = 0;
$d = 0;
for ($i = 0; $i <= $maxnumber; $i++){
if ($i % 3 == 0)
$t+= $i;
else if ($i % 5 == 0)
$d += $i;
}
echo $t.'<br>'.$d;
I think that in your code, if a number is a multiple of 3 and 5, it is added twice. Take 15 for example. It's in your list of multiples of 3 and in the list of multiples of 5. Is this the behaviour you want?
One of the best approach to this solution (to achieve optimum time complexity), run an Arithmetic Progression series and find the number of terms in all series by using AP formula: T=a+(n-1)d, then find sum by : S=n/2[2*a+(n-1)d]
where : a=first term ,n=no. of term , d=common deference, T=nth term
The code solution below has been implemented to suit the question above - so the values 3 and 5 are hard-coded. However, the function can modified such that values are passed in as variable parameters.
function solution($number){
$val1 = 3;
$val2 = 5;
$common_term = $val1 * $val2;
$sum_of_terms1 = calculateSumofMulitples($val1,$number);
$sum_of_terms2 = calculateSumofMulitples($val2,$number);
$sum_of_cterms = calculateSumofMulitples($common_term,$number);
$final_result = $sum_of_terms1 + $sum_of_terms2 - $sum_of_cterms;
return $final_result;
}
function calculateSumofMulitples($val, $number)
{
//first, we begin by running an aithmetic prograssion for $val up to $number say N to get the no of terms [using T=a +(n-1)d]
$no_of_terms = (int) ($number / $val);
if($number % $val == 0) $no_of_terms = (int) ( ($number-1)/$val ); //since we are computing for a no of terms below N and not up to/exactly/up to N. if N divides val with no remainder, use no of terms = (N-1)/val
//second, we compute the sum of terms [using Sn = n/2[2a + (n-1)d]
$sum_of_terms = ($no_of_terms * 0.5) * ( (2*$val) + ($no_of_terms - 1) * $val );
// sum of multiples
return $sum_of_terms;
}
You can run a single loop checking whether the number is multiple of 3 OR 5:
for ($i = 0; $i < $maxnumber; $i++)
{
if($i%3 || $i%5){
$t += $i;
echo $i.',';}
}
I think the original code is not including numbers which are multiples of both 3 and 5 in the total: if the test for multiple of 3 matches, it takes that and goes on.
If you total the multiples of 15 up to 1000, you get 33165, which is exactly the difference between your total, 266333, and the original total, 233168.
Here's my solution to the question:
<?php
$sum = 0;
$arr = [];
for($i = 1; $i < 1000; $i++){
if((int)$i % 3 === 0 || (int)$i % 5 === 0)
{
$sum += $i;
array_push($arr,$i);
}
}
echo $sum;
echo '<br>';
print_r($arr);//Displays the values meeting the criteria as an array of values

Categories