Dividing a integer equally in X parts - php

I'm looking for a efficient way in PHP to divide a number in equal part. Number will always be integer (no float).
Let's say that I have an array $hours with values from "1" to "24" ($hours['1'], etc) and a variable $int containing an integer. What I want to acheive is spreading the value of $int equally in 24 parts so I can assing the value to each corresponding array entries. (Should the number be odd, the remaining would be added to the last or first values in the 24).
Regards,

Here's the algorithm you're looking for; it evenly spreads an integer N over K cells:
for i = 0 to K
array[i] = N / K # integer division
# divide up the remainder
for i = 0 to N mod K
array[i] += 1

Try this code
<?php
$num = 400;
$val = floor($num/24);
for($i=0;$i<24;$i++) {
$arr[$i] = $val;
}
$arr[0] += $num - array_sum($arr);
?>

function split($x, $n)
{
// If we cannot split the
// number into exactly 'N' parts
if($x < $n)
echo (-1);
// If x % n == 0 then the minimum
// difference is 0 and all
// numbers are x / n
else if ($x % $n == 0)
{
for($i = 0; $i < $n; $i++)
{
echo ($x / $n);
echo (" ");
}
}
else
{
// upto n-(x % n) the values
// will be x / n
// after that the values
// will be x / n + 1
$zp = $n - ($x % $n);
$pp = $x / $n;
for ($i = 0; $i < $n; $i++)
{
if($i >= $zp)
{
echo (int)$pp + 1;
echo (" ");
}
else
{
echo (int)$pp;
echo (" ");
}
}
}
}
// Driver code
$x = 5;
$n = 3;
split( $x, $n);

Related

Logic php condition sum of the divisors

I have an array of numbers 1 until 100 and I need to find a list of numbers applying two conditions, first sum of divisors is greater than itself and second condition no subset of divisors can not sums the number itself
for that I have the php code
$arrayNumbers = [];
//array numbers 1 - 100
$a = 1;
$b = 100;
for ($n = $a; $n <= $b; $n++) {
$conditionOne = false; // Condition one: sum of the divisors greater than ifself
$conditionTwo = false; // Condition two: No subset of those divisors sums itself
$multiples = [];
$subset = [];
// Get sum of multiples divisors
for ($i = 1; $i < $n; $i++) {
if ($n % $i == 0)
$multiples[]= $i;
}
//Condition one sum of the divisors greater than itself
if (array_sum( $multiples ) > $n)
$conditionOne = true;
foreach ($multiples as $number) {
if ($number % 2 == 0) $subset[]= $number;
}
// Condition tow sum of the divisors greater than itself
if (array_sum($subset) > $n)
$conditionTwo = true;
// If first ondition one match with second condition two
if ($conditionOne && $conditionTwo)
$arrayNumbers[] = $n;
}
echo implode('</br>$arrayNumbers );
Is this php logic correct? thanks in advance.

Find the highest product in 4 directions in a matrix

I got this challenge to find the highest product of 4 consecutive numbers on a 20x20 matrix of integers.
The numbers are read line by line from a file separated by a space.
The products can be in horizontal, vertical and diagonal in both directions
My "solution" gives the wrong answer.
EDIT: I've updated the code to work without file input and added sample data; also fixed one of my mistakes that were pointed out in the comments
$data = [
[89,32,92,64,81,2,20,33,44,1,70,75,39,62,76,35,16,77,22,27],
[53,11,6,95,41,51,31,59,8,23,19,13,61,91,48,69,84,52,66,24],
[93,72,85,97,21,79,56,5,45,3,65,30,83,87,43,7,34,0,4,14],
[29,17,49,9,82,90,55,67,15,63,54,94,12,28,96,37,58,98,86,78],
[74,40,50,60,26,99,80,18,10,46,36,68,25,57,47,71,42,73,88,38],
[50,22,6,26,18,53,52,5,46,2,89,77,83,48,4,58,45,28,84,81],
[49,82,31,14,69,17,91,54,34,40,0,33,30,95,60,44,29,24,85,16],
[27,11,76,39,15,86,92,74,99,59,94,12,55,57,38,96,47,32,78,75],
[51,20,87,42,62,41,7,35,23,21,71,25,67,97,80,90,88,64,13,70],
[19,9,56,43,68,93,65,98,36,3,61,63,10,72,8,73,1,66,79,37],
[22,58,52,12,3,41,28,72,42,74,76,64,59,35,85,78,14,27,53,88],
[46,80,5,96,7,68,61,69,67,34,36,40,82,26,75,50,29,91,10,2],
[30,39,19,48,33,93,1,45,66,98,0,23,62,25,51,71,56,77,24,21],
[79,87,94,60,8,32,13,65,4,92,73,9,31,37,17,84,15,90,86,20],
[95,6,81,70,47,16,44,83,49,43,55,54,18,63,38,11,97,89,99,57],
[95,78,64,58,7,17,53,28,74,86,6,12,54,85,21,94,16,69,25,68],
[13,20,41,97,1,2,80,30,0,84,67,45,93,96,82,92,62,33,18,44],
[60,77,31,70,76,36,59,38,15,3,91,46,65,73,49,11,8,35,5,52],
[61,66,79,40,26,72,89,71,75,99,22,9,43,32,14,81,98,88,87,83],
[10,4,23,19,56,57,51,47,50,27,90,63,42,29,24,55,48,37,39,34]
];
$matrix = [];
//maximums in possible directions
$maxes = [0, 0, 0, 0];
//while ($line = trim(fgets(STDIN))) {
while ($line = current($data)) {
//the horizontal maxes can be calculated while loading
//$array = explode(" ", $line);
$array = $line;
$hMax = array_product(array_slice($array, 0, 4));
for ($i = 1; $i < (count($array)-4); $i++) {
$max = array_product(array_slice($array, $i, 4));
if($max > $hMax) {
$hMax = $max;
}
}
if ( $hMax > $maxes[0] ) {
$maxes[0] = $hMax;
}
$matrix[] = $array;
next($data);
}
// the last 3 rows can be skipped
for($i = 0; $i < (count($matrix)-4); $i++) {
for ($j = 0; $j < (count($matrix[$i])-1); $j++) {
$vMax = 1; // vertical
$dlMax = 1; // diagonal left
$drMax = 1; // diagonal rigth
for ($k = 0; $k < 5; $k++) {
$vMax *= $matrix[$i + $k][$j];
if ( $j < (count($matrix[$i]) - 4) ) {
$drMax *= $matrix[$i + $k][$j + $k];
}
if ( $j > 3 ) {
$dlMax *= $matrix[$i + $k][$j - $k];
}
}
if ( $maxes[1] < $vMax ) $maxes[1] = $vMax; // the index used to be 1 - my first mistake
if ( $maxes[2] < $dlMax ) $maxes[2] = $dlMax; // the index used to be 1 - my first mistake
if ( $maxes[3] < $drMax ) $maxes[3] = $drMax; // the index used to be 1 - my first mistake
}
}
sort($maxes);
echo end($maxes).PHP_EOL;
Where did my approach go wrong, and how can it be sped up?
Are there any math tricks that can be applied here (besides checking for zeros)?
EDIT: the solution that the code gives for the current data is 4912231320 is it correct?
I've found 2 major errors, and now the result is a plausible 67352832
I'm considering it solved for that reason, but if anyone comes up with some math trick that simplifies or makes it faster I'll give up the accepted answer.
The first mistake was
for ($k = 0; $k < 5; $k++) {
It should've been
for ($k = 0; $k < 4; $k++) {
since we are only counting 4 numbers at once, thats why the result was so large compared to 10^8
The second was
if ( $j > 3 ) {
which should've been
if ( $j > 2 ) {
which will now include one more diagonal possibility
We can consider the four directions a bottom- or right-most cell can be the last of in a sequence. If m[i][j][k][d] is the highest total for a sequence of length k coming from direction d, then:
m[i][j][1][d] = data[i][j] for all d
m[i][j][k]['E'] = data[i][j] * m[i][j - 1][k - 1]['E']
m[i][j][k]['NE'] = data[i][j] * m[i - 1][j - 1][k - 1]['NE']
m[i][j][k]['N'] = data[i][j] * m[i - 1][j][k - 1]['N']
m[i][j][k]['NW'] = data[i][j] * m[i - 1][j + 1][k - 1]['NW']
If we traverse north to south, east to west, the needed cells should have already been calculated, and, clearly, we're looking for
max(m[i][j][4][d])
for all i, j, d

How to print correct multiplication of big number in PHP

I was trying to print multiplication of big numbers and they are resulting in float type scientific number.
var_dump((double)('290287121823'*'290287121823'));
I tried the function number_format and preg_replace to remove all ','. But after number_format the result is not correct.
Used following code:
preg_replace("/,/", "", (number_format(('290287121823'*'290287121823'))));
Output received: 84266613096281242861568
Expected correct output: 84266613096281243382112
The large numbers are computed digits by digits. Like we learn at school (see Long multiplication).
ex:
// 17
// x 27
// ----
// 119
// + 34
// -----
// = 459
Here is a function (which should be optimized) but shows you the principle.
echo bn_mul('17', '27'), PHP_EOL; // 459
echo bn_mul('157', '27'), PHP_EOL; // 4239
echo bn_mul('1234', '6627'), PHP_EOL; // 8177718
echo bn_mul('23958233', '5830'), PHP_EOL; // 139676498390
echo bn_mul('290287121823', '290287121823'), PHP_EOL; // 84266613096281242843329
Implementation:
function bn_mul($n2, $n1) {
$l1 = strlen($n1);
$l2 = strlen($n2);
$rows = [];
for ($idx1 = $l1 - 1 ; $idx1 >= 0 ; $idx1--) {
// get digit
$d1 = substr($n1, $idx1, 1) ;
$carry = 0; // reset carry
$row = []; // store digit of $d1 x each digits of $n2
// prepend 0 (10 * num rows)
for ($x=0 ; $x<count($rows) ; $x++) $row[] = 0;
for ($idx2 = $l2 - 1 ; $idx2 >= 0 ; $idx2--) {
// get digit
$d2 = substr($n2, $idx2, 1) ;
// multiplication of digit 1 x digit 2 + current carry
$r = $d1 * $d2 + $carry;
$carry = 0;
// compute carry
if ($r >= 10) {
$carry = substr($r, 0, -1);
$r = substr($r, -1);
}
$row[] = $r ;
}
if ($carry) $row[] = $carry;
$rows[] = $row ;
}
// Sum digits of rows
$total = [] ;
$carry = 0 ;
for ($x=0;$x < count(end($rows)) ; $x++){
$tot = $carry;
$carry = 0;
foreach ($rows as $row){
if (isset($row[$x])) $tot += $row[$x] ;
}
while ($tot >= 10) {
$tot -= 10;
$carry++;
}
$total[$x] = $tot;
}
return strrev(implode($total));
}
You should keep in mind that even if PHP is NOT typesafe, there are types in the background.
When you look up the documentation you'll find out, that floating points only have a precision up to 14 digits. Therefore, all trailing numbers are "cut off". The magnitude remains and it will print in scientific format but you can't really know what's "below" that 14 digits. Therefore, your try to convert the result is doomed to fail in the first place.
Example:
12345678910111213
^^^ get's cut off

Round down to nearest multiple of 10000 using PHP

If I have the following code which grabs an array of values and adds them all together, how can I then round them down to the nearest 10000 using PHP?
Here's the code I currently have
$rows = $db->get("sales");
$sales = 0;
foreach($rows as $row) {
$stock = $sales + $row['sales'];
}
return $sales;
An example result would be
146740
How could I then make that returned as
140000
Although if I had a number greater than 1 million, how could I have that returned as just 1 million?
Divide by 10000, use floor to round down to an integer, then multiply by 10000:
$x = 146740;
$x = 10000 * floor($x/10000);
Or subtract the remainer:
$x = 146740;
$x = $x - ($x % 10000);
To extend this to 1 million, you can do:
if ($x > 1000000) {
$divisor = 1000000;
} elseif ($x > 10000) {
$divisor = 10000;
} else {
$divisor = 1;
}
$x = $x - ($x % divisor);
you could divide the value by 1000. If it is integer 146740/1000 = 146. And after that multiply by 1000 will give 146000

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