the shortest solution for your problem that i can think of would be:
$m = 110; // desired sum
$v = 8; // desired elements
$x = []; // result
for($i = 1; $i < $v; $i++)
$x[$i] = rand(1, $m - array_sum($x) - (($v - $i) * $v));
$x[0] = $m-array_sum($x);
// print results
print_r($x);
printf("Elements sum to: %d\n",array_sum($x));
which results in
Array
(
[1] => 16
[2] => 13
[3] => 15
[4] => 23
[5] => 5
[6] => 7
[7] => 1
[0] => 30
)
Elements sum to: 110
so hurray, just what you wanted, although it could be optimized for nicer spread. but let me explain line for line.
first i just initialized three variables. $m
is the desired sum you want to have for all of your elements. $v
is the number of elements (N's) you want to generate. and $x
holds an array with all N's that where calculated, so the result we are interested in:
$m = 110; // desired sum
$v = 8; // desired elements
$x = []; // result
now we start a loop through the elements we want to calculate. notice we start with 1, because we will be using 0 for calculating last value later on:
for($i = 1; $i < $v; $i++)
and here now comes the "brainwork" we are setting the current element $x[$i]
to a random value. in PHP we can pass min and max values to the random function, so i chose 1 as min to avoid 0's and the max i chose i shall explain a bit more detailed at the end, but obviously we want to avoid having 110 as first value and the rest zeros and this is how we do so:
$x[$i] = rand(1, $m - array_sum($x) - (($v - $i) * $v));
in the last step now we need to make sure that we will end up with the desired sum, so instead of going random, i simply set the element to the desired maximum sum minus the sum of all existing elements:
$x[0]=$m-array_sum($x);
the last rows of the code just print out the results, but as promised, let me explain the "complicated" max part of the random function that i chose.
$m - array_sum($x) - (($v - $i) * $v)
the one PHP function that comes really handy here is the array_sum
function, which adds up all elements of an array. if we would just call rand(1,110)
on every element, then we would could easily end up with a sum higher than 110, so we subtract the sum of all existing elements from the max value to avoid this on first hand: $m - array_sum($x)
. so if last three generated elements add up to 43 then next element can be no higher than 67 (110 - 43). we still could end up with a result like (12,7,24,5,62,0,0,0) and we don't wan't zeros, so we will have to subtract the number of elements left $v - $i
which will avoid the zeros.
again we still could end up with a result like (12,7,24,5,59,1,1,1) and that does not look nice, so last optimization i did was to multiply this by an arbitrary number to leave more space for higher values - in this case i just used the $v
(the number of elements) as arbitrary number, but you can play around with this value i.e. (($v - $i) * 12))
until you get desired result.