There is such a task: Generate an array of numbers, the sum of which will be 1. The number of numbers is entered from the keyboard. The solution can be any important to get the final amount 1 (It is not desirable a large number of zeros)

  • one
    Numbers can be any (positive / negative)? Or only from the interval [0; 1]? - Andrei NOP
  • one
    What should be the distribution of the numbers obtained? - Yaant
  • TC, if you need a uniform distribution, I recommend to consider the answer @AnT: ru.stackoverflow.com/a/820415/218063 - Andrey NOP

5 answers 5

We generate N any non-negative numbers.
We calculate their sum.
We divide each by this amount.

Example of implementation:

int count = 10; Random random = new Random(); int[] integers = new int[count]; long sum = 0; for (int i = 0; i < count; ++i) { integers[i] = random.Next(); sum += integers[i]; } double[] doubles = new double[count]; for (int i = 0; i < count; ++i) doubles[i] = (double)integers[i] / sum; Console.WriteLine(string.Join("\n", doubles)); Console.WriteLine(doubles.Sum()); 

random.Next() returns a non-negative random integer.
To accumulate the amount, take a long variable to avoid overflows.

  • By the way, this idea is already much more interesting :) by the way, on paper, it is well solved :) - JMNext
  • one
    @JMNext, the same method performs normalization of vectors to unit ones - test123
  • :) Bliiiin as everything just turned out ... And I am inventing complex stick tree algorithms)) - JMNext
  • 2
    Such an approach would give a “crooked” distribution of the result. That is, it is better than "many zeros", but in fact suffers from the same problem, only less clearly. - AnT
  • 2
    If you divided the obtained values ​​into the predefined constant , then the uniformity of distribution would be preserved, but since you divide by the sum of the random values ​​themselves , the uniformity is lost. The sum of several random variables is distributed not evenly , but normally . For example, the histogram of the sum N throws of the die has a well-known bell shape. It is precisely by such an unevenly distributed random variable that you perform the division in your variant. And precisely because of this you lose the uniform distribution of the result. - AnT

The option of dividing by the amount of pre-generated numbers does not give a uniform distribution of the result due to the fact that the sum of uniformly distributed values ​​is not itself uniformly distributed. A uniform distribution of the result in such tasks is usually implied.

From a distribution point of view, the following solution would be more suitable: generate N-1 non N-1 decreasing uniformly distributed random numbers in the range [0, 1]

r 1 ≤ r 2 ≤ r 3 ≤ ... ≤ r N-1

then put r 0 = 0 and r N = 1 and take the pairwise differences as neighbors as the required numbers

r 1 - r 0 , r 2 - r 1 , r 3 - r 2 , ..., r N - r N-1

In C ++

 #include <cstdlib> #include <vector> #include <algorithm> #include <iostream> int main() { unsigned N = 10; std::vector<unsigned> r(N + 1); r.front() = 0; std::generate(r.begin() + 1, r.end() - 1, std::rand); std::sort(r.begin() + 1, r.end() - 1); r.back() = RAND_MAX; for (unsigned i = 1; i <= N; ++i) std::cout << double(r[i] - r[i - 1]) / RAND_MAX << " "; std::cout << std::endl; } 
  • It seems that this is the only correct answer in terms of uniformity of distribution - Zergatul
  • @Zergatul, what do you mean by uniformity? I've generated in three ways a million times a packet of 10 numbers and got this picture: 1 , 2 . And here are packages of 100 numbers: 3 . As you can see, my algorithm gives a roughly equal number of numbers in the initial interval (from 0 to 0.15). The algorithm yolosora gives a lot of small numbers. The AnT algorithm gives the smaller numbers than they are, but not as many small numbers as the previous one. - Andrei NOP
  • @AndreyNOP Look, take the simplest version of the problem, generate 2 numbers, whose sum = 1. What is the most intuitively correct answer? Take and cut the interval [0, 1) in a random place. Which makes AnT. Your algorithm will generate numbers closer to 0.5 more often. And now what's wrong with yolosora. His algorithm does not depend on the number of numbers. Take 10 numbers. According to his algorithm, it turns out that the probability of the appearance of the number 0.9 at the first iteration is 0.1. Take the 1000 numbers. Again the same probability of occurrence of 0.9. - Zergatul
  • In general, it depends on the needs of the vehicle, if it generates 10 numbers and wants them to be close to 0.1, then my algorithm will go better with it. True, ideally, then he needs the default locale algorithm: D - Andrey NOP
  • one
    @VTT: I already gave the link: en.wikipedia.org/wiki/Irwin%E2%80%93Hall_distribution . The sum of evenly distributed is the Irwin-Hall distribution, very similar to the normal one. On the uniform does not seem at all. - AnT pm

rnd - Random

  static double[] Generate(int count) { var result = new double[count]; var max = 1.0; for (int i = 0; i < count - 1; i++) { result[i] = rnd.NextDouble() * max; max -= result[i]; } result[count-1] = max; return result; } 

Additionally, the array can be mixed if it is critical that with such generation, on average, the next value becomes less than the previous one. An example of simple mixing:

result.OrderBy(x => rnd.Next()).ToArray();

  • The last number will be deeply negative and very different from the rest. It is not clear just how much this is critical for the author. - Andrey NOP
  • one
    @AndrewNOP why will it be negative? There is probably another problem, the numbers with each iteration on average will become smaller. - yolosora
  • @AndreyNOP if the first is 0.7, then the second will not be greater than 0.3 - yolosora
  • Oh, no, that's right. You max every time you multiply. Understand your algorithm. But yes, even though the numbers will not be negative, they will still not be evenly distributed - distant numbers will be less - Andrey NOP
  • one
    @AndreyNOP Well, in principle, after this, the array can be mixed: D - yolosora

Well, since there are no restrictions, the most primitive solution: an array in which the first element is 1, and the rest is 0.

 int n = 5; var arr = new decimal[n]; arr[0] = 1; 

UPDATE: Added clarification that many zeros are undesirable. Because of this, the solution does not fit.

Option number 2: Fill the array with the values ​​1 / n:

 int n = 6; var value = 1.0m/n; var arr = Enumerable.Repeat(value, n).ToArray(); 

Here a problem arises: due to rounding errors when dividing, the amount may not converge. In order for the amount to converge we compensate the first element:

 arr[0] = 1-(value*(n-1)); 
  • 2
    If the solution does not seem to be sufficiently random, then it is possible to modify the algorithm and make 1 not the first element, but a random one. :) - Yaant pm
  • one
    a lot of zeros as it does not really look. And yes, I'll fix it. It is necessary rationally how to generate :) - JMNext
  • @JMNext Yes, perhaps we need to clarify the condition. And then in the title about random fractional numbers, and in the text they are not mentioned. - default locale
  • @Yaant Well, this will be chaos and confusion. - default locale
  • one
    Eh, I would not want to be your customer;) - Andrey NOP

One of the ideas is to create large integers and then divide them, for example, by 1000. This will form an array of fractional numbers =) Actions performed until the sum of all elements equals 1. Each generated number needs to be checked: is it suitable? condition (must be less than the difference of 1 and the sum of the remaining elements of the array).

  • and it will be equal to 1? - Alexcei Shmakov
  • one
    great solution, it remains to answer the question that is in the other - test123
  • four
    And what a good idea - to generate any numbers and divide each by the sum of all! Just the author unsuccessfully formulated the answer ... - Andrew NOP
  • No, read what Andrei wrote to you, what you propose does not fit again, according to the criterion "we need to specify the number of such numbers" - test123
  • Oh no, the author changed the answer and it has already suffered the wrong way ... Read my previous comment. - Andrei NOP