开发者

Create numbers within an array that add up to a set amount

开发者 https://www.devze.com 2022-12-29 09:04 出处:网络
I\'m fairly new to PHP - programming in general. So basically what I need to accomplish is, create an array of x amount o开发者_运维问答f numbers (created randomly) whose value add up to n:

I'm fairly new to PHP - programming in general. So basically what I need to accomplish is, create an array of x amount o开发者_运维问答f numbers (created randomly) whose value add up to n:

Let's say, I have to create 4 numbers that add up to 30. I just need the first random dataset. The 4 and 30 here are variables which will be set by the user.

Essentially something like

x = amount of numbers;
n = sum of all x's combined;

// create x random numbers which all add up to n;

$row = array(5, 7, 10, 8) // these add up to 30

Also, no duplicates are allowed and all numbers have to be positive integers.

I need the values within an array. I have been messing around with it sometime, however, my knowledge is fairly limited. Any help will be greatly appreciated.


First off, this is a really cool problem. I'm almost sure that my approach doesn't even distribute the numbers perfectly, but it should be better than some of the other approaches here.

I decided to build the array from the lowest number up (and shuffle them at the end). This allows me to always choose a random range that will allows yield valid results. Since the numbers must always be increasing, I solved for the highest possible number that ensures that a valid solution still exists (ie, if n=4 and max=31, if the first number was picked to be 7, then it wouldn't be possible to pick numbers greater than 7 such that the sum of 4 numbers would be equal to 31).

$n = 4;
$max = 31;
$array = array();

$current_min = 1;
while( $n > 1 ) {
    //solve for the highest possible number that would allow for $n many random numbers
    $current_max = floor( ($max/$n) - (($n-1)/2) );
    if( $current_max < $current_min ) throw new Exception( "Can't use combination" );
    $new_rand = rand( $current_min, $current_max ); //get a new rand
    $max -= $new_rand; //drop the max
    $current_min = $new_rand + 1; //bump up the new min
    $n--; //drop the n
    $array[] = $new_rand; //add rand to array
}
$array[] = $max; //we know what the last element must be
shuffle( $array );

EDIT: For large values of $n you'll end up with a lot of grouped values towards the end of the array, since there is a good chance you will get a random value near the max value forcing the rest to be very close together. A possible fix is to have a weighted rand, but that's beyond me.


I'm not sure whether I understood you correctly, but try this:

$n = 4;
$max = 30;
$array = array();

do {
    $random = mt_rand(0, $max);

    if (!in_array($random, $array)) {
        $array[] = $random;
        $n--;
    }
} while (n > 0);


sorry i missed 'no duplicates' too
-so need to tack on a 'deduplicator' ...i put it in the other question

To generate a series of random numbers with a fixed sum:

  • make a series of random numbers (of largest practical magnitude to hide granularity...)
  • calculate their sum
  • multiply each in series by desiredsum/sum

(basicaly to scale a random series to its new size)

Then there is rounding error to adjust for:

  • recalculate sum and its difference from desired sum
  • add the sumdiff to a random element in series if it doesnt result in a negative, if it does loop to another random element until fine.
  • to be ultratight instead add or subtract 1 bit to random elements until sumdiff=0

Some non-randomness resulting from doing it like this is if the magnitude of the source randoms is too small causing granularity in the result.

I dont have php, but here's a shot -

$n = ;              //size of array
$targsum = ;        //target sum
$ceiling = 0x3fff;  //biggish number for rands
$sizedrands = array();

$firstsum=0;
$finsum=0;

//make rands, sum size
for( $count=$n; $count>0; $count--)
{ $arand=rand( 0, $ceiling );
  $sizedrands($count)=$arand;
  $firstsum+=$arand; }

//resize, sum resize
for( $count=$n; $count>0; $count--)
{ $sizedrands($count)=($sizedrands($count)*$targsum)/$firstsum;
  $finsum+=$sizedrands($count);
  }

//redistribute parts of rounding error randomly until done
$roundup=$targsum-$finsum;

$rounder=1; if($roundup<0){ $rounder=-1; }

while( $roundup!=0 )
{ $arand=rand( 0, $n );
  if( ($rounder+$sizedrands($arand) ) > 0 )
  { $sizedrands($arand)+=$rounder; 
    $roundup-=$rounder; }
  }


Hope this will help you more....

Approch-1

$aRandomarray = array();
for($i=0;$i<100;$i++)
{
    $iRandomValue = mt_rand(1000, 999);
    if (!in_array($iRandomValue , $aRandomarray)) {
        $aRandomarray[$i] = $iRandomValue;
    }
} 

Approch-2

$aRandomarray = array();
for($i=0;$i<100;$i++)
{
    $iRandomValue = mt_rand(100, 999);
    $sRandom .= $iRandomValue;
}
array_push($aRandomarray, $sRandom);
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号