Adding and subtracting within a range of numbers and looping round - php

I'm wondering how I would go about the addition and subtraction of numbers in a set range and which would loop back on themselves, example below;
Range: 1 - 10
So if I now had the number 7 and added 5 to it, I would want the number go to 2
8, 9, 10, loop around to 1, 2.
And the same if I subtracted, so I have the number 3 and I subtract 4 so I should be left with 9.
2, 1, loop around to 10, 9
I hope this makes sense.
Thanks.

You can use % operator.
It calculates remainder after division.
For example:
$d = 10;
$x = 7;
$y = 5;
echo ($x + $y) % $d;
gives 2;
With negative values you can just remove MINUS

Use the modulus operator.
result = (a + b) % 10;

You can use modulo function like (7+5)%10 = 2

Try this:
$range = range(1,10);
$min = min($range);
$max = max($range);
function operate( $a, $b, $operation ) {
global $max, $min;
switch( $operation ) {
case '+':
$a += $b;
break;
case '-':
$a -= $b;
break;
}
if( $a < $min ) {
return $max + $a;
} else if( $a > $max ) {
return $a - $max;
}
}
Hope it helps.

You can do this with code like
$range = array('from' => 3, 'to' => 13);
$dist = $range['to'] - $range['from'];
$a = 7;
$b = 14;
echo ($dist + ($a % $range['to'] - $b % $range['to'])) % $dist; // $a - $b
echo ($dist + ($a % $range['to'] + $b % $range['to'])) % $dist; // $a + $b

Modulo will do the trick as others have shown, but you must also account for the lower end of the range.
E.g. looping an arbitrary value within an hour range will work since it's zero-based. But if you want to loop a value within a month range you will get into trouble with the last day, because:
31 % 31 = 0
So you will loop to zero when you should remain on 31.
To deal with any range, you need to do this:
$min = 5;
$max = 15;
$value = 25; // The range is 11, so we want this turned into 14
$range = $max - $min + 1;
$value = (($value-$min) % $range) + $min;
To deal with values below minimum:
$range = $max - $min + 1;
$value = ($min - $value) % $range;
$value = $max - ($value - 1);

Related

List of numbers until n divisible by A or B but not divisible by C

I have three integers: A, B, C
I want to print all integers from 1 to range which are divisible by A or B but not by C.
My code
for($n=0; $n < $range; $n++){
if(($n < $a && $n < $b) || ($n % $c == 0)){
return [];
}
if(($n % $a == 0 || $n % $b == 0) && ($n % $c > 0)){
$outputArr[] = $n;
}
}
Is there any more efficient way to do this?
You can speed this up but it is more complicated, especially if you must print these out in order. Here is a method that doesn't print them out in order.
First write a greatest common divisor (gcd) function in PHP, and then write a least common multiple (lcm) function that uses the gcd function. Compute m = lcm(a, b). Iterate over multiples of a and print them out if they are not divisible by c. Next, iterate over multiples of b and print them out if they are not divisible by m or c.
Other optimizations along these lines are possible. For example, you can precompute the multiples of a or b that are not multiples of m and store them in an array. This works if m is not too large, division is more expensive than array access in PHP, and range is significantly larger than m.
PHP version 7 or higher is so fast when only integer operations are used that micro-optimizations are no longer needed.
$res = [];
$a = 9;
$b = 13;
$c = 26;
$range = 10000;
for($n=$a; $n <= $range; $n += $a){
if($n%$c != 0) $res[] = $n;
}
for($n=$b; $n <= $range; $n += $b){
if($n%$c != 0) $res[] = $n;
}
$res = array_unique($res);
sort($res);
This example takes about 1 millisecond to calculate the 1411 values on my 8-year-old system. This time for the presentation of the result is several times greater.
I would use range() and array_filter().
$range = 20;
$A = 2;
$B = 3;
$C = 9;
$nums = array_filter(range(1, $range), function ($x) use ($A, $B, $C) {
return (!($x % $A) || !($x % $B)) && $x % $C;
});
var_dump($nums);
Here is a more optimized solution, that also works efficient when a and b are large. You can simply run through the multiples of a and b:
for($na=$a, $nb=$b; $na <= $range || $nb <= $range; ){
if ($na <= $nb) {
if ($na % $c != 0)
$outputArr[] = $na;
if ($na == $nb)
$nb += $b;
$na += $a;
} else {
if ($nb % $c != 0)
$outputArr[] = $nb;
$nb += $b;
}
}
Each output number is only generated once, and already in the desired order.
If you are afraid the modulo test is slow, you could also have a next multiple of c running along, but that looks like too much overhead.

add zero after single number if needed

i want to add zero after number if number is single
e.g $a = 2 then 20
if $a = 20 then 20
if $a = 12 then '12'
like this. I some things but it didn't work for me.
How to do it ?
Use if-statements:
if ($a < 10) $a *= 10;
That shouldn't be too hard.
$number = intval($number)
if ($number > 0 && $number < 10) {
$number *= 10;
}
Use str_pad to pad with zeros.
http://php.net/manual/en/function.str-pad.php
Echo str_pad($a, 2, "0", STR_PAD_RIGHT);

Array range with exceptions

In the PHP function range there are a start point, a end point and a step point.
is it possible to create an array with numbers, in which some values should not exist?
$hundred_tens = range(120, 190, 10);
I need the numbers 220,230,...290 ... 920,930..990, but not 200,210 ...900,910.
My solution:
$hundreds = range(100, 800, 100);
foreach ($hundred_tens as $value) {
$add_numbers[] = $value + $hundreds[0];
$add_numbers[] = $value + $hundreds[1];
$add_numbers[] = $value + $hundreds[2];
$add_numbers[] = $value + $hundreds[3];
$add_numbers[] = $value + $hundreds[4];
$add_numbers[] = $value + $hundreds[5];
$add_numbers[] = $value + $hundreds[6];
$add_numbers[] = $value + $hundreds[7];
}
$all_hundred_tens = array_merge($hundred_tens, $add_numbers);
I have add in a foreach every array value $hundreds to in a new array and merge this array with $hundred_tens.
You can either loop through your entire range and exclude the unnecessary numbers
$hundred_tens = array();
foreach (range(100, 800, 10) as $number) {
if ($number % 100 !== 0 && $number % 100 !== 10) {
$hundred_tens[] = $number;
}
}
or you can merge smaller ranges:
$hundred_tens = array_merge(range(120, 190, 10), range(220, 890, 10), range(920, 990, 10));
Which one is better depends on how many exclusions you have, and if they are together in the list.
Ref my comment below about for ( being faster, here's an example (only one line is different)
$hundred_tens = array();
for ($number = 100; $number <= 1000; $number += 10) {
if ($number % 100 !== 0 && $number % 100 !== 10) {
$hundred_tens[] = $number;
}
}
Basically, you create a for-loop starting from 220 till 910 in steps of 10. In the loop you check whether the number is a hundred or a hundred plus ten. If it is not, then add the number to the array.
To check whether a number is divisable by 100, you could use the module operator %.
So, a % 100 == 0 will result in true, if a is divisable by 100 and false otherwise. For hundreds plus ten, you could do: (a - 10) % 100 == 0.

Dividing a integer equally in X parts

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);

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