9

For example, say I enter '10' for the amount of values, and '10000' as a total amount.

The script would need to randomize 10 different numbers that all equal up to 10000. No more, no less.

But it needs to be dynamic, as well. As in, sometimes I might enter '5' or '6' or even '99' for the amount of values, and any number (up to a billion or even higher) as the total amount.

How would I go about doing this?

EDIT: I should also mention that all numbers need to be a positive integer

Rob
  • 7,980
  • 30
  • 75
  • 115
  • What's the distribution you want? For instance, one answer that would satisfy your priblem would be to have the first 8 values of 1000, and then either 999, 1001 or 1001, 999 with equal probability. So... You want what? A sum of normal distributions? What would be the standard deviation?... You see it's impossible to answer your question as it stands. – Artefacto Sep 12 '10 at 21:38
  • @Artefacto well, as it stands, he doesn't require a specific distribution and deviation - which makes the question answerable. Isn't it? – Pekka Sep 12 '10 at 21:41
  • @Pekka Yes, it makes it "answerable". In fact, I gave one possible answer. However, it probably isn't what the OP wants. The point is: "random" doesn't mean anything unless you also specify the underlying distribution. – Artefacto Sep 12 '10 at 21:45
  • @Artefacto I see! I can see this goes *way* beyond my math knowledge (which is close to zero anyway :) – Pekka Sep 12 '10 at 22:01
  • @Pekka I gave an answer in case he wants uniformly distribution numbers inside a range. The other answers will yield numbers that are more likely to be near (sum total)/(number of parcels). – Artefacto Sep 12 '10 at 22:03

6 Answers6

11

The correct answer here is unbelievably simple.

Just imagine a white line, let's say 1000 units long.

You want to divide the line in to ten parts, using red marks.

VERY SIMPLY, CHOOSE NINE RANDOM NUMBERS and put a red paint mark at each of those points.

It's just that simple. You're done!

Thus, the algorithm is:

(1) pick nine random numbers between 0 and 1000 (2) put the nine numbers, a zero, and a 1000, in an array (3) sort the array (4) using "subtraction" get the ten "distances" between array values

You're done.

(Obviously if you want to have no zeros in your final set, in part (1) simply rechoose another random number if you get a collision.)

Ideally as programmers, we can "see" visual algorithms like this in our heads -- try to think visually whatever we do!


Footnote - for any non-programmers reading this, pls note that this is like "the first thing you learn when studying computer science!" i.e. I do not get any credit for this, I just typed in the trivial answer.

FTR another common algorithm everyone knows assuming you're dealing with fractions. Get 10 random numbers. Add them. multiply or divide them all by some number, so that, the total is the desired total! It's that easy if dealing with fractions.

Fattie
  • 27,874
  • 70
  • 431
  • 719
  • 2
    +1 for having the undoubtedly best and simplest answer; -0.9 for boasting :P still +1. – Pekka Sep 12 '10 at 21:33
  • 2
    It may be simple but it does **not** generate uniformly distributed numbers... It is biased in favor of numbers of size 1000/10 (for a sum of 1000 and 10 numbers). – Artefacto Sep 12 '10 at 21:58
  • 3
    Artefacto - it absolutely, definitely, generates uniform numbers. It could be you are making a unity error in your head thinking about the algorithm. Try some tests if you don't believe! – Fattie Sep 17 '10 at 21:17
  • I believe that under this method, the numbers presented in each element have a uniform chance at being a particular value *compared with any other element's position*, but I don't agree that this is an inherent property of *randomness*. See my answer below for another take. – Grade 'Eh' Bacon Jan 27 '16 at 21:03
3

maybe something like this:

set max amount remaining to the target number

loop for 1 to the number of values you want - 1

get a random number from 0 to the max amount remaining

set new max amount remaining to old max amount remaining minus the current random number

repeat loop

you will end up with a 'remainder' so the last number is determined by whatever is left over to make up the original total.

Randy
  • 16,480
  • 1
  • 37
  • 55
  • Nice idea! Better than mine. Mine is better only if you want "chunks" of approximately the same size. +1 – Pekka Sep 12 '10 at 21:16
  • I'm really not sure what you mean. Can you perhaps give me a small example? Doesn't need to be exact, pseudocode works – Rob Sep 12 '10 at 21:19
  • 2
    This DOES NOT WORK. it is completely, totally, absolutely, fully, 100% wrong. (Sorry!) You DO NOT get random numbers from this. Specifically, you get a list of numbers that run from large to small. Utterly not-random. It's a shame to see completely wrong guesses on stackoverflow .... if someone uses this in production they are buggered! – Fattie Sep 30 '10 at 08:58
  • No, this would work, as long as you made sure your numbers generated lied in the range of 0..(max / num_required) – Thomas O Oct 19 '10 at 19:43
  • I see now that the algorithm here is the same as what I have in my answer - apologies for that. In short @JoeBlow, I agree with Randy that this is a perfectly valid approach to creating the numberset. In terms of ensuring the items do not on average decrease over time, the elements can be randomized in order after they are created. Apart from that, *randomness* is not a concrete concept without further information regarding distribution. – Grade 'Eh' Bacon Jan 27 '16 at 21:16
  • Hi G.E.H. When you say *"the elements can be randomized in order after they are created"*, that process is a well explored problem: note **you are wrong**, I'm afraid. If you think about it, that creates: a set of decreasingly sized values, which are shuffled. That's not the same as a random set of values. – Fattie Jan 27 '16 at 21:24
  • "Give me a random number between 2-12": Is the correct answer (a) Roll 2 6-sided die; (b) Roll 1 4-sided die, and 1 8-sided die; OR (c) Roll 1 12-sided die? Answer: it depends on what distribution pattern you want. – Grade 'Eh' Bacon Jan 27 '16 at 21:55
  • @JoeBlow remember that what we're talking about in this question is inherently NOT a 'pure random number'. By forcing a max limit on the total of all N elements, the size of each element explicitly impacts the size of each subsequent element in some way. Therefore we are using a qualified approach to randomness. Take your 'legal' approach - would it be legal for a lottery to 'pick 10 random numbers' where they made all numbers add up to 100 every time without telling anyone? No - because they have expressly created a set of only pseudo random numbers. After that, any distribution may be right. – Grade 'Eh' Bacon Jan 28 '16 at 13:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/101899/discussion-between-grade-eh-bacon-and-joe-blow). – Grade 'Eh' Bacon Jan 28 '16 at 13:56
  • Couldn't be simpler, you questioned the nature of the distribution of the 10 achieved numbers. Of course, they should be have an even distribution (since "random" means "even distribution random" in English.) Note too that to a non expert (i.e. NOT yourself) "random" **absolutely** means "even distribution random". If you start telling an ordinary person you're giving them "random" numbers - but then explain what a "distribution" is and explain you're NOT giving them "random" numbers - they'll whack you :) You're viewing it **as an expert**, not as asked. Anyway let's leave this – Fattie Jan 28 '16 at 13:58
2

I believe the answer provided by @JoeBlow is largely correct, but only if the 'randomness' desired requires uniform distribution. In a comment on that answer, @Artefacto said this:

It may be simple but it does not generate uniformly distributed numbers... 
Itis biased in favor of numbers of size 1000/10 (for a sum of 1000 and 10 numbers).

This begs the question which was mentioned previously regarding the desired distribution of these numbers. JoeBlow's method does ensure a that element 1 has the same chance at being number x as element 2, which means that it must be biased towards numbers of size Max/n. Whether the OP wanted a more likely shot at a single element approaching Max or wanted a uniform distribution was not made clear in the question. [Apologies - I am not sure from a terminology perspective whether that makes a 'uniform distribution', so I refer to it in layman's terms only]

In all, it is incorrect to say that a 'random' list of elements is necessarily uniformly distributed. The missing element, as stated in other comments above, is the desired distribution.

To demonstrate this, I propose the following solution, which contains sequential random numbers of a random distribution pattern. Such a solution would be useful if the first element should have an equal chance at any number between 0-N, with each subsequent number having an equal chance at any number between 0-[Remaining Total]:

[Pseudo code]:
Create Array of size N
Create Integer of size Max
Loop through each element of N Except the last one
    N(i) = RandomBetween (0, Max)
    Max = Max - N(i)
End Loop
N(N) = Max

It may be necessary to take these elements and randomize their order after they have been created, depending on how they will be used [otherwise, the average size of each element decreases with each iteration].

Grade 'Eh' Bacon
  • 3,773
  • 4
  • 24
  • 46
  • 1
    As explained at length in comments, sure, for questions like this asked by absolutely beginners who are not mathematicians, it's wise to have a side not explaining "distribution". Note that artefecto already did this, and indeed included a link to the relevant matlab function. – Fattie Jan 28 '16 at 14:02
1

Generate 10 random numbers till 10000 . Sort them from big to small : g0 to g9

g0 = 10000 - r0
g1 = r0 - r1
...
g8 = r8 - r9
g9 = r9

This will yield 10 random numbers over the full range which add up to 10000.

Peter Tillemans
  • 34,983
  • 11
  • 83
  • 114
0

Update: @Joe Blow has the perfect answer. My answer has the special feature of generating chunks of approximately the same size (or at least a difference no bigger than (10000 / 10)), leaving it in place for that reason.

The easiest and fastest approach that comes to my mind is:

  • Divide 10000 by 10 and store the values in an array. (10 times the value 10000)

  • Walk through every one of the 10 elements in a for loop.

  • From each element, subtract a random number between (10000 / 10).

  • Add that number to the following element.

This will give you a number of random values that, when added, will result in the end value (ignoring floating point issues).

Should be half-way easy to implement.

You'll reach PHP's maximum integer limit at some point, though. Not sure how far this can be used for values towards a billion and beyond.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
  • I think I know what you mean, but I'm not sure. I'll try a few things based on this and report back. In the meantime, any additional help would be greatly appreciated. – Rob Sep 12 '10 at 21:10
  • @Joe Blow well, that's more or less what these steps do - they give you chunks that never deviate from each other in size more than (10000 / 10). By reducing the limits when calling the randomizer, it's possible to make chunks more and more similar in size. It's not what the OP asked for though, so fine-tuning this is a question for another day – Pekka Sep 12 '10 at 21:44
  • @Joe Blow I'm no mathematician and I have no problem with being corrected, but I can't see a fundamental error in my idea. If I have 10 chunks sized 100, and I subtract a random number between 0 and 100 from the first chunk (say, 30) I need to add that random number to the second chunk. I will end up with one chunk sized 70, and one sized 130, equalling 200. Continue the same operation until I reach the tenth chunk, which will always be larger than 100 (just as the first chunk will always be smaller than 100). I don't see the problem? – Pekka Sep 17 '10 at 21:43
  • @Pekka - it's unfortunate, someone as experienced on these sites as you. You say **"I'm no mathematician"** then you go on to give an answer that is totally wrong! And you won't simply delete it. Did you need the points? :) Very surprising for you dude. This QA came up again recently! – Fattie Sep 10 '14 at 14:56
  • 2
    @JoeBlow The yellow warning at the top of this answer clearly explains that this is not the best solution so I would not worry about the case of "someone using it" in a wrong way and being surprised. Your remark "you need the points" is hilarious when addressed towards a user with 200k+ rep, when the answer is giving +8 :) Perhaps you could calm down a bit :) – BartoszKP Jan 27 '16 at 18:15
  • hi @BartoszKP the yellow warning **is wrong**. (Note too there is often vast confusion about exactly this topic, randomness in software engineering.) The only possible reason P can want the answer here, is for the points: just as I said, that is ridiculous for a user with huge points. If I made some random incorrect guess about something in a field of which I knew nothing, people on that question would ask me to delete it. The "yellow warning" indeed is triply confusing because it suggests there's a "special" reason for the answer: the yellow warning ***itself is totally wrong***. – Fattie Jan 27 '16 at 18:19
  • 2
    Luckily for me, the number of casualties from plane crashes caused by my answer providing a first chunk that is always smaller than 100 has remained at acceptable levels. – Pekka Jan 27 '16 at 18:43
  • 1
    @JoeBlow Software engineers do "calm down", unless they are not professionals. Which part of the yellow warning in particular is wrong? Surely not the one stating that your answer is the best. Perhaps you could be more constructive. Even if Pekka's solution does not match the problem in question exactly, it is somehow related - and by custom such answers are often preserved - you can't foresee what exactly will be helpful for a future reader. – BartoszKP Jan 27 '16 at 20:00
0

Related: http://www.mathworks.cn/matlabcentral/newsreader/view_thread/141395

See this MATLAB package. It is accompanied with a file with the theory behind the implementation.

This function generates random, uniformly distributed vectors, x = [x1,x2,x3,...,xn]', which have a specified sum s, and for which we have a <= xi <= b, for specified values a and b. It is helpful to regard such vectors as points belonging to n-dimensional Euclidean space and lying in an n-1 dimensional hyperplane constrained to the sum s. Since, for all a and b, the problem can easily be rescaled to the case where a = 0 and b = 1, we will henceforth assume in this description that this is the case, and that we are operating within the unit n-dimensional "cube".

This is the implementation (© Roger Stafford):

function [x,v] = randfixedsum(n,m,s,a,b)

% Rescale to a unit cube: 0 <= x(i) <= 1
s = (s-n*a)/(b-a);

% Construct the transition probability table, t.
% t(i,j) will be utilized only in the region where j <= i + 1.
k = max(min(floor(s),n-1),0); % Must have 0 <= k <= n-1
s = max(min(s,k+1),k); % Must have k <= s <= k+1
s1 = s - [k:-1:k-n+1]; % s1 & s2 will never be negative
s2 = [k+n:-1:k+1] - s;
w = zeros(n,n+1); w(1,2) = realmax; % Scale for full 'double' range
t = zeros(n-1,n);
tiny = 2^(-1074); % The smallest positive matlab 'double' no.
for i = 2:n
 tmp1 = w(i-1,2:i+1).*s1(1:i)/i;
 tmp2 = w(i-1,1:i).*s2(n-i+1:n)/i;
 w(i,2:i+1) = tmp1 + tmp2;
 tmp3 = w(i,2:i+1) + tiny; % In case tmp1 & tmp2 are both 0,
 tmp4 = (s2(n-i+1:n) > s1(1:i)); % then t is 0 on left & 1 on right
 t(i-1,1:i) = (tmp2./tmp3).*tmp4 + (1-tmp1./tmp3).*(~tmp4);
end

% Derive the polytope volume v from the appropriate
% element in the bottom row of w.
v = n^(3/2)*(w(n,k+2)/realmax)*(b-a)^(n-1);

% Now compute the matrix x.
x = zeros(n,m);
if m == 0, return, end % If m is zero, quit with x = []
rt = rand(n-1,m); % For random selection of simplex type
rs = rand(n-1,m); % For random location within a simplex
s = repmat(s,1,m);
j = repmat(k+1,1,m); % For indexing in the t table
sm = zeros(1,m); pr = ones(1,m); % Start with sum zero & product 1
for i = n-1:-1:1  % Work backwards in the t table
 e = (rt(n-i,:)<=t(i,j)); % Use rt to choose a transition
 sx = rs(n-i,:).^(1/i); % Use rs to compute next simplex coord.
 sm = sm + (1-sx).*pr.*s/(i+1); % Update sum
 pr = sx.*pr; % Update product
 x(n-i,:) = sm + pr.*e; % Calculate x using simplex coords.
 s = s - e; j = j - e; % Transition adjustment
end
x(n,:) = sm + pr.*s; % Compute the last x

% Randomly permute the order in the columns of x and rescale.
rp = rand(n,m); % Use rp to carry out a matrix 'randperm'
[ig,p] = sort(rp); % The values placed in ig are ignored
x = (b-a)*x(p+repmat([0:n:n*(m-1)],n,1))+a; % Permute & rescale x

return
Artefacto
  • 96,375
  • 17
  • 202
  • 225