1

I am working on a report in C# in which I am given a total number of prints a department printed and I have to distribute them according to the month date that on 1st March 10 papers are printed out and so on to 31st March.

I have a form which takes the total print outs count. I have a Month Selector.

From Month I get the total days which is total numbers to be generated eg: 30 or 31 or 28

Scenario :

In the month of March 2000 Prints outs Total Sum of Month : 2000 Numbers to be generated : 31

this is my code

        int sum = 2345;
        int nums = 23;
        Random rand = new Random();
        int newNum = 0;
        int[] ar = new int[23];
        for (int i = 0; i < nums; i++)
        {
            newNum = rand.Next(0, sum);
            ar[i] = newNum;
            sum = sum - newNum;
        }
        for (int i = 0; i < 23 ; i++)
        {
            Console.WriteLine(ar[i]);

        }
        Console.ReadLine();

what happens is in the ending numbers it goes to zero . I want Normally distributed like on one index it stores the maximum value at first and in the end it decreases.

We have a thrid party Ricoh Print/PhotoCopier Machine installed and third party bills us with certain amount which they have calculate that our department has printed 3000 printouts so we have to distribute them in the days randomly, print out the report and get payment invoice from our department head.

The department people are doing it on excel I offered them to give them a solution. Windows form application is built and I just have to put this logic thats all.. Thank you for your feedbacks

3 Answers3

4

You can do this easily with partitions. For a 4 day month that produced 10 things: generate 3 random numbers between 0 and 10 (inclusive). Sort them and append 10 to the list of numbers. So we have perhaps:

3 6 6 10

Which partitions our prints:

p p p | p p p | | p p p p
U2EF1
  • 12,907
  • 3
  • 35
  • 37
  • 1
    Yes, this is the right way to do it. Code [here](http://stackoverflow.com/a/16884017/2192494). – Lee Daniel Crocker Jun 12 '13 at 04:04
  • I'm not so sure this is uniform. I haven't thought about it much theoretically, but just empirically doing it in R and looking at histograms, it looks to be heavily biased to small numbers e.g. hist(diff(sort(c(0,sample(10000,200,replace=T),10000)))). On the other hand, I don't see how it can ever be uniform and add up. I need to think about it more theoretically. – frankc Jun 12 '13 at 14:32
1

If you want to have 23 random numbers with sum of 2345, you can use this code:

        int sum = 2345;
        int nums = 23;
        int max = sum / nums;
        Random rand = new Random();
        int newNum = 0;
        int[] ar = new int[23];
        for (int i = 0; i < nums-1; i++) {
            newNum = rand.Next(max);
            ar[i] = newNum;
            sum-= newNum;
            max = sum / (nums-i-1);
        }
        ar[nums - 1] = sum;

It will give you:

enter image description here

Majid
  • 13,853
  • 15
  • 77
  • 113
  • Mathematically, this isn't evenly distributed. – SimpleVar Jun 12 '13 at 03:48
  • You didn't really change what it does. The algorithm itself is flawed. Or maybe the specifications are. I'm not sure. You'll either get many zero's, or results shorter than 30. Not sure if valid according to OP. – SimpleVar Jun 12 '13 at 03:53
  • int sum = 2345; int nums = 23; Random rand = new Random(); int newNum = 0; int[] ar = new int[23]; for (int i = 0; i < nums; i++) { newNum = rand.Next(0, sum); ar[i] = newNum; sum = sum - newNum; } for (int i = 0; i < 23 ; i++) { Console.WriteLine(ar[i]); } Console.ReadLine(); – Rehmat Alam Jun 12 '13 at 03:54
  • int sum = 2345; int nums = 23; Random rand = new Random(); int newNum = 0; int[] ar = new int[23]; for (int i = 0; i < nums; i++) { newNum = rand.Next(0, sum); ar[i] = newNum; sum = sum - newNum; } for (int i = 0; i < 23 ; i++) { Console.WriteLine(ar[i]); } Console.ReadLine(); This is what I have done in the ending numbers the value goes to zero. Majid your program doesnt create what i wa – Rehmat Alam Jun 12 '13 at 03:55
  • @RehmatAlam There is an edit option to comments. Avoid spamming. – SimpleVar Jun 12 '13 at 03:55
  • @YoryeNathan what about my new answer? – Majid Jun 12 '13 at 04:03
  • @majidgeek Still. The whole approach of generating a random and subtracting from max is flawed, since it means that each random is dependent on previous randoms. And `2345/23` is about `102`, which means that the sum of your result isn't even `2345`, since all numbers are lower than `102`. – SimpleVar Jun 12 '13 at 04:07
  • @YoryeNathan depending to previous random is not problem because it is more random!!!! – Majid Jun 12 '13 at 04:09
  • 1
    What he means by "depending to previous random" is "correlated to previous results", which is very NOT random. Read some basics [here](http://stackoverflow.com/questions/3956478/understanding-randomness/3956538#3956538). – Lee Daniel Crocker Jun 12 '13 at 04:16
  • Run your code 10000 times, each time counting the numbers higher and lower than `102`. In total, there shouldn't be a big difference between your "higher" counter and your "lower" counter. In your case, there is. @LeeDanielCrocker Thank you for helping me explain myself; I'm not strong with professional terms and such. – SimpleVar Jun 12 '13 at 04:22
  • I am not good at maths lol. Thank you all for sharing your professional experiences. I hope I will learn from you guys – Rehmat Alam Jun 12 '13 at 04:30
0

Here is my idea for generating 30 random numbers with a specific sum:

int sum = 3000;
int size = 30; // assumes that (sum % size == 0)
int[] result = new int[size];
Random rand = new Random();
int x = sum / size;

for (int i = 0; i < size; i++)
{
    result[i] = x;
}

for (int i = 0; i < x; i++)
{
    var a = rand.Next(size - 1); // not sure if parameter is inclusive?
    var b = rand.Next(size - 1); // should return number between 0 and size-1 inclusively

    result[a]++;
    result[b]--;
}

int testSum = result.Sum(); // will equal "sum" (3000)

Lee Daniel Crocker linked to this, though, which I think is a better solution. Very neat and intuitive.

Community
  • 1
  • 1
SimpleVar
  • 14,044
  • 4
  • 38
  • 60
  • That'll work, but won't be uniform. Correct algorithm is [here](http://stackoverflow.com/a/16884017/2192494). – Lee Daniel Crocker Jun 12 '13 at 04:04
  • @LeeDanielCrocker I agree. It's a beautiful solution. But I'm not sure that mine is not uniform... Could you explain why it is the case? – SimpleVar Jun 12 '13 at 04:05
  • The obvious is that your method never produces any values outside the range [70, 130]. – Lee Daniel Crocker Jun 12 '13 at 04:08
  • @LeeDanielCrocker Wrong. I initialize all numbers as `100` and run the loop for `100` times. A single value can go be `0` or `200`, but I do see your point. You said it right. I'll leave the answer just so not to throw the code away ;) – SimpleVar Jun 12 '13 at 04:12
  • I think maybe you meant to use `x` as the rand limit, not `size`. – Lee Daniel Crocker Jun 12 '13 at 04:17
  • @LeeDanielCrocker The rand in my case isn't to generate numbers, but to select two indices which I increase/decrease in the array (maintaining the sum while altering the values). – SimpleVar Jun 12 '13 at 04:20
  • Yorye Nathan your solution is far much better to adopt but it is also repeating the values – Rehmat Alam Jun 12 '13 at 04:25
  • Ah. missed that, thanks. This is like starting from a flat line and generating random noise. I suspect this distribution is more like a bell curve, but I'd have to do the math. Might be more like what OP wants. – Lee Daniel Crocker Jun 12 '13 at 04:26
  • @RehmatAlam Yes, I would suggest increasing the times we loop the 2nd `for`, also adding a check to make sure we don't get any negative values. – SimpleVar Jun 12 '13 at 04:26
  • @LeeDanielCrocker That makes sense. If we increase the amount of times we go over the 2nd `for` (maybe to something like `x*size/2` or some other magic formula?) and add a check to avoid negative numbers, I think we would have something more uniform, but still not truly uniform. Your solution is undoubtedly perfect - and as a bonus it is very easy to understand the logic behind it ;) – SimpleVar Jun 12 '13 at 04:28