Random number with Probabilities












36















I am wondering what would be the best way (e.g. in Java) to generate random numbers within a particular range where each number has a certain probability to occur or not?



e.g.



Generate random integers from within [1;3] with the following probabilities:



P(1) = 0.2

P(2) = 0.3

P(3) = 0.5





Right now I am considering the approach to generate a random integer within [0;100] and do the following:



If it is within [0;20] --> I got my random number 1.

If it is within [21;50] --> I got my random number 2.

If it is within [51;100] --> I got my random number 3.


What would you say?










share|improve this question




















  • 5





    I think it's a clever way to do it like that, but I don't know if there is anything "better". Just make sure you go from 0 to 99, as otherwise you will end up with 101 numbers and not exactly the percentage you want.

    – Blub
    Dec 2 '13 at 12:10








  • 3





    yes, this seems reasonable, otherwise you could use EnumeratedIntegerDistribution, example shown here

    – kiruwka
    Dec 2 '13 at 12:32








  • 1





    Granted, I could not find a relevant implementation for your problem in SSJ, but you should give it a more thorough look than I...

    – Yaneeve
    Dec 2 '13 at 12:40


















36















I am wondering what would be the best way (e.g. in Java) to generate random numbers within a particular range where each number has a certain probability to occur or not?



e.g.



Generate random integers from within [1;3] with the following probabilities:



P(1) = 0.2

P(2) = 0.3

P(3) = 0.5





Right now I am considering the approach to generate a random integer within [0;100] and do the following:



If it is within [0;20] --> I got my random number 1.

If it is within [21;50] --> I got my random number 2.

If it is within [51;100] --> I got my random number 3.


What would you say?










share|improve this question




















  • 5





    I think it's a clever way to do it like that, but I don't know if there is anything "better". Just make sure you go from 0 to 99, as otherwise you will end up with 101 numbers and not exactly the percentage you want.

    – Blub
    Dec 2 '13 at 12:10








  • 3





    yes, this seems reasonable, otherwise you could use EnumeratedIntegerDistribution, example shown here

    – kiruwka
    Dec 2 '13 at 12:32








  • 1





    Granted, I could not find a relevant implementation for your problem in SSJ, but you should give it a more thorough look than I...

    – Yaneeve
    Dec 2 '13 at 12:40
















36












36








36


10






I am wondering what would be the best way (e.g. in Java) to generate random numbers within a particular range where each number has a certain probability to occur or not?



e.g.



Generate random integers from within [1;3] with the following probabilities:



P(1) = 0.2

P(2) = 0.3

P(3) = 0.5





Right now I am considering the approach to generate a random integer within [0;100] and do the following:



If it is within [0;20] --> I got my random number 1.

If it is within [21;50] --> I got my random number 2.

If it is within [51;100] --> I got my random number 3.


What would you say?










share|improve this question
















I am wondering what would be the best way (e.g. in Java) to generate random numbers within a particular range where each number has a certain probability to occur or not?



e.g.



Generate random integers from within [1;3] with the following probabilities:



P(1) = 0.2

P(2) = 0.3

P(3) = 0.5





Right now I am considering the approach to generate a random integer within [0;100] and do the following:



If it is within [0;20] --> I got my random number 1.

If it is within [21;50] --> I got my random number 2.

If it is within [51;100] --> I got my random number 3.


What would you say?







java random probability






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 17 '15 at 23:11









Daniel Smith

6,85232953




6,85232953










asked Dec 2 '13 at 12:08









marc wellmanmarc wellman

3,25442447




3,25442447








  • 5





    I think it's a clever way to do it like that, but I don't know if there is anything "better". Just make sure you go from 0 to 99, as otherwise you will end up with 101 numbers and not exactly the percentage you want.

    – Blub
    Dec 2 '13 at 12:10








  • 3





    yes, this seems reasonable, otherwise you could use EnumeratedIntegerDistribution, example shown here

    – kiruwka
    Dec 2 '13 at 12:32








  • 1





    Granted, I could not find a relevant implementation for your problem in SSJ, but you should give it a more thorough look than I...

    – Yaneeve
    Dec 2 '13 at 12:40
















  • 5





    I think it's a clever way to do it like that, but I don't know if there is anything "better". Just make sure you go from 0 to 99, as otherwise you will end up with 101 numbers and not exactly the percentage you want.

    – Blub
    Dec 2 '13 at 12:10








  • 3





    yes, this seems reasonable, otherwise you could use EnumeratedIntegerDistribution, example shown here

    – kiruwka
    Dec 2 '13 at 12:32








  • 1





    Granted, I could not find a relevant implementation for your problem in SSJ, but you should give it a more thorough look than I...

    – Yaneeve
    Dec 2 '13 at 12:40










5




5





I think it's a clever way to do it like that, but I don't know if there is anything "better". Just make sure you go from 0 to 99, as otherwise you will end up with 101 numbers and not exactly the percentage you want.

– Blub
Dec 2 '13 at 12:10







I think it's a clever way to do it like that, but I don't know if there is anything "better". Just make sure you go from 0 to 99, as otherwise you will end up with 101 numbers and not exactly the percentage you want.

– Blub
Dec 2 '13 at 12:10






3




3





yes, this seems reasonable, otherwise you could use EnumeratedIntegerDistribution, example shown here

– kiruwka
Dec 2 '13 at 12:32







yes, this seems reasonable, otherwise you could use EnumeratedIntegerDistribution, example shown here

– kiruwka
Dec 2 '13 at 12:32






1




1





Granted, I could not find a relevant implementation for your problem in SSJ, but you should give it a more thorough look than I...

– Yaneeve
Dec 2 '13 at 12:40







Granted, I could not find a relevant implementation for your problem in SSJ, but you should give it a more thorough look than I...

– Yaneeve
Dec 2 '13 at 12:40














10 Answers
10






active

oldest

votes


















31














Yours is a pretty good way already and works well with any range.



Just thinking: another possibility is to get rid of the fractions by multiplying with a constant multiplier, and then build an array with the size of this multiplier. Multiplying by 10 you get



P(1) = 2
P(2) = 3
P(3) = 5


Then you create an array with the inverse values -- '1' goes into elements 1 and 2, '2' into 3 to 6, and so on:



P = (1,1, 2,2,2, 3,3,3,3,3);



and then you can pick a random element from this array instead.





(Add.) Using the probabilities from the example in kiruwka's comment:



int numsToGenerate           = new int    { 1,   2,    3,   4,    5   };
double discreteProbabilities = new double { 0.1, 0.25, 0.3, 0.25, 0.1 };


the smallest multiplier that leads to all-integers is 20, which gives you



2, 5, 6, 5, 2


and so the length of numsToGenerate would be 20, with the following values:



1 1
2 2 2 2 2
3 3 3 3 3 3
4 4 4 4 4
5 5


The distribution is exactly the same: the chance of '1', for example, is now 2 out of 20 -- still 0.1.



This is based on your original probabilities all adding up to 1. If they do not, multiply the total by this same factor (which is then going to be your array length as well).






share|improve this answer


























  • Thank you very much for your answer on that problem - your help is pretty much appreciated.

    – marc wellman
    Dec 2 '13 at 20:58



















24














Some time ago I wrote a helper class to solve this issue. The source code should show the concept clear enough:



public class DistributedRandomNumberGenerator {

private Map<Integer, Double> distribution;
private double distSum;

public DistributedRandomNumberGenerator() {
distribution = new HashMap<>();
}

public void addNumber(int value, double distribution) {
if (this.distribution.get(value) != null) {
distSum -= this.distribution.get(value);
}
this.distribution.put(value, distribution);
distSum += distribution;
}

public int getDistributedRandomNumber() {
double rand = Math.random();
double ratio = 1.0f / distSum;
double tempDist = 0;
for (Integer i : distribution.keySet()) {
tempDist += distribution.get(i);
if (rand / ratio <= tempDist) {
return i;
}
}
return 0;
}

}


The usage of the class is as follows:



DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
drng.addNumber(1, 0.3d); // Adds the numerical value 1 with a probability of 0.3 (30%)
// [...] Add more values

int random = drng.getDistributedRandomNumber(); // Generate a random number


Test driver to verify functionality:



    public static void main(String args) {
DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
drng.addNumber(1, 0.2d);
drng.addNumber(2, 0.3d);
drng.addNumber(3, 0.5d);

int testCount = 1000000;

HashMap<Integer, Double> test = new HashMap<>();

for (int i = 0; i < testCount; i++) {
int random = drng.getDistributedRandomNumber();
test.put(random, (test.get(random) == null) ? (1d / testCount) : test.get(random) + 1d / testCount);
}

System.out.println(test.toString());
}


Sample output for this test driver:



{1=0.20019100000017953, 2=0.2999349999988933, 3=0.4998739999935438}





share|improve this answer


























  • Nice piece of code. Thank you very much.

    – marc wellman
    Dec 2 '13 at 20:58











  • I like that! If you want to use it on a large scale tho the hashmap should use Float instead of Double to reduce unneccessary overhead

    – Xerus
    Oct 28 '17 at 13:36





















8














You already wrote the implementation in your question. ;)



final int ran = myRandom.nextInt(100);
if (ran > 50) { return 3; }
else if (ran > 20) { return 2; }
else { return 1; }


You can speed this up for more complex implementations by per-calculating the result on a switch table like this:



t[0] = 1; t[1] = 1; // ... one for each possible result
return t[ran];


But this should only be used if this is a performance bottleneck and called several hundred times per second.






share|improve this answer
























  • Your answer helped me a lot. Thank you very much.

    – marc wellman
    Dec 2 '13 at 20:59



















5














If you have performance issue instead of searching all the n values O(n)



you could perform binary search which costs O(log n)



Random r=new Random();      
double weights=new double{0.1,0.1+0.2,0.1+0.2+0.5};
// end of init
double random=r.nextDouble();
// next perform the binary search in weights array


you only need to access log2(weights.length) in average if you have a lot of weights elements.






share|improve this answer































    4














    Your approach is fine for the specific numbers you picked, although you could reduce storage by using an array of 10 instead of an array of 100. However, this approach doesn't generalize well to large numbers of outcomes or outcomes with probabilities such as 1/e or 1/PI.



    A potentially better solution is to use an alias table. The alias method takes O(n) work to set up the table for n outcomes, but then is constant time to generate regardless of how many outcomes there are.






    share|improve this answer


























    • Thank you very much :) You helped me a lot.

      – marc wellman
      Dec 2 '13 at 20:58



















    1














    Try this:
    In this example i use an array of chars, but you can substitute it with your integer array.



    Weight list contains for each char the associated probability.
    It represent the probability distribution of my charset.



    In weightsum list for each char i stored his actual probability plus the sum of any antecedent probability.



    For example in weightsum the third element corresponding to 'C', is 65:

    P('A') + P('B) + P('C') = P(X=>c)

    10 + 20 + 25 = 65



    So weightsum represent the cumulative distribution of my charset.
    weightsum contains the following values:



    It's easy to see that the 8th element correspondig to H, have a larger gap (80 of course like his probability) then is more like to happen!



            List<Character> charset =   Arrays.asList('A','B','C','D','E','F','G','H','I','J');
    List<Integer> weight = Arrays.asList(10,30,25,60,20,70,10,80,20,30);
    List<Integer> weightsum = new ArrayList<>();

    int i=0,j=0,k=0;
    Random Rnd = new Random();

    weightsum.add(weight.get(0));

    for (i = 1; i < 10; i++)
    weightsum.add(weightsum.get(i-1) + weight.get(i));


    Then i use a cycle to get 30 random char extractions from charset,each one drawned accordingly to the cumulative probability.



    In k i stored a random number from 0 to the max value allocated in weightsum.
    Then i look up in weightsum for a number grather than k, the position of the number in weightsum correspond to the same position of the char in charset.



       for (j = 0; j < 30; j++)
    {
    Random r = new Random();
    k = r.nextInt(weightsum.get(weightsum.size()-1));

    for (i = 0; k > weightsum.get(i); i++) ;
    System.out.print(charset.get(i));
    }


    The code give out that sequence of char:



    HHFAIIDFBDDDHFICJHACCDFJBGBHHB



    Let's do the math!



    A = 2

    B = 4

    C = 3

    D = 5

    E = 0

    F = 4

    G = 1

    H = 6

    I = 3

    J = 2



    Total.:30

    As we wish D and H are have more occurances (70% and 80% prob.)

    Otherwinse E didn't come out at all. (10% prob.)






    share|improve this answer































      0














      Written this class for interview after referencing the paper pointed by pjs in another post , the population of base64 table can be further optimized. The result is amazingly fast, initialization is slightly expensive, but if the probabilities are not changing often, this is a good approach.



      *For duplicate key, the last probability is taken instead of being combined (slightly different from EnumeratedIntegerDistribution behaviour)



      public class RandomGen5 extends BaseRandomGen {

      private int t_array = new int[4];
      private int sumOfNumerator;
      private final static int DENOM = (int) Math.pow(2, 24);
      private static final int bitCount = new int {18, 12, 6, 0};
      private static final int cumPow64 = new int {
      (int) ( Math.pow( 64, 3 ) + Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
      (int) ( Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
      (int) ( Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
      (int) ( Math.pow( 64, 0 ) )
      };


      ArrayList base64Table = {new ArrayList<Integer>()
      , new ArrayList<Integer>()
      , new ArrayList<Integer>()
      , new ArrayList<Integer>()};

      public int nextNum() {
      int rand = (int) (randGen.nextFloat() * sumOfNumerator);

      for ( int x = 0 ; x < 4 ; x ++ ) {
      if (rand < t_array[x])
      return x == 0 ? (int) base64Table[x].get(rand >> bitCount[x])
      : (int) base64Table[x].get( ( rand - t_array[x-1] ) >> bitCount[x]) ;
      }
      return 0;
      }

      public void setIntProbList( int intList, float probList ) {
      Map<Integer, Float> map = normalizeMap( intList, probList );
      populateBase64Table( map );
      }

      private void clearBase64Table() {
      for ( int x = 0 ; x < 4 ; x++ ) {
      base64Table[x].clear();
      }
      }

      private void populateBase64Table( Map<Integer, Float> intProbMap ) {
      int startPow, decodedFreq, table_index;
      float rem;

      clearBase64Table();

      for ( Map.Entry<Integer, Float> numObj : intProbMap.entrySet() ) {
      rem = numObj.getValue();
      table_index = 3;
      for ( int x = 0 ; x < 4 ; x++ ) {
      decodedFreq = (int) (rem % 64);
      rem /= 64;
      for ( int y = 0 ; y < decodedFreq ; y ++ ) {
      base64Table[table_index].add( numObj.getKey() );
      }
      table_index--;
      }
      }

      startPow = 3;
      for ( int x = 0 ; x < 4 ; x++ ) {
      t_array[x] = x == 0 ? (int) ( Math.pow( 64, startPow-- ) * base64Table[x].size() )
      : ( (int) ( ( Math.pow( 64, startPow-- ) * base64Table[x].size() ) + t_array[x-1] ) );
      }

      }

      private Map<Integer, Float> normalizeMap( int intList, float probList ) {
      Map<Integer, Float> tmpMap = new HashMap<>();
      Float mappedFloat;
      int numerator;
      float normalizedProb, distSum = 0;

      //Remove duplicates, and calculate the sum of non-repeated keys
      for ( int x = 0 ; x < probList.length ; x++ ) {
      mappedFloat = tmpMap.get( intList[x] );
      if ( mappedFloat != null ) {
      distSum -= mappedFloat;
      } else {
      distSum += probList[x];
      }
      tmpMap.put( intList[x], probList[x] );
      }

      //Normalise the map to key -> corresponding numerator by multiplying with 2^24
      sumOfNumerator = 0;
      for ( Map.Entry<Integer, Float> intProb : tmpMap.entrySet() ) {
      normalizedProb = intProb.getValue() / distSum;
      numerator = (int) ( normalizedProb * DENOM );
      intProb.setValue( (float) numerator );
      sumOfNumerator += numerator;
      }

      return tmpMap;
      }
      }





      share|improve this answer

































        0














        If you are not against adding a new library in your code, this feature is already implemented in MockNeat, check the probabilities() method.



        Some examples directly from the wiki:



        String s = mockNeat.probabilites(String.class)
        .add(0.1, "A") // 10% chance
        .add(0.2, "B") // 20% chance
        .add(0.5, "C") // 50% chance
        .add(0.2, "D") // 20% chance
        .val();


        Or if you want to generate numbers within given ranges with a given probability you can do something like:



        Integer x = m.probabilites(Integer.class)
        .add(0.2, m.ints().range(0, 100))
        .add(0.5, m.ints().range(100, 200))
        .add(0.3, m.ints().range(200, 300))
        .val();


        Disclaimer: I am the author of the library, so I might be biased when I am recommending it.






        share|improve this answer

































          0














          Here is the python code even though you ask for java, but it's very similar.



          # weighted probability

          theta = np.array([0.1,0.25,0.6,0.05])
          print(theta)

          sample_axis = np.hstack((np.zeros(1), np.cumsum(theta)))
          print(sample_axis)


          [0. 0.1 0.35 0.95 1. ]. This represent the cumulative distribution.



          you can use a uniform distribution to draw an index in this unit range.



          def binary_search(axis, q, s, e):
          if e-s <= 1:
          print(s)
          return s
          else:
          m = int( np.around( (s+e)/2 ) )
          if q < axis[m]:
          binary_search(axis, q, s, m)
          else:
          binary_search(axis, q, m, e)



          range_index = np.random.rand(1)
          print(range_index)
          q = range_index
          s = 0
          e = sample_axis.shape[0]-1
          binary_search(sample_axis, q, 0, e)





          share|improve this answer































            0














            Also responded here: find random country but probability of picking higher population country should be higher. Using TreeMap:



            TreeMap<Integer, Integer> map = new TreeMap<>();
            map.put(percent1, 1);
            map.put(percent1 + percent2, 2);
            // ...

            int random = (new Random()).nextInt(100);
            int result = map.ceilingEntry(random).getValue();





            share|improve this answer























              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f20327958%2frandom-number-with-probabilities%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              10 Answers
              10






              active

              oldest

              votes








              10 Answers
              10






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              31














              Yours is a pretty good way already and works well with any range.



              Just thinking: another possibility is to get rid of the fractions by multiplying with a constant multiplier, and then build an array with the size of this multiplier. Multiplying by 10 you get



              P(1) = 2
              P(2) = 3
              P(3) = 5


              Then you create an array with the inverse values -- '1' goes into elements 1 and 2, '2' into 3 to 6, and so on:



              P = (1,1, 2,2,2, 3,3,3,3,3);



              and then you can pick a random element from this array instead.





              (Add.) Using the probabilities from the example in kiruwka's comment:



              int numsToGenerate           = new int    { 1,   2,    3,   4,    5   };
              double discreteProbabilities = new double { 0.1, 0.25, 0.3, 0.25, 0.1 };


              the smallest multiplier that leads to all-integers is 20, which gives you



              2, 5, 6, 5, 2


              and so the length of numsToGenerate would be 20, with the following values:



              1 1
              2 2 2 2 2
              3 3 3 3 3 3
              4 4 4 4 4
              5 5


              The distribution is exactly the same: the chance of '1', for example, is now 2 out of 20 -- still 0.1.



              This is based on your original probabilities all adding up to 1. If they do not, multiply the total by this same factor (which is then going to be your array length as well).






              share|improve this answer


























              • Thank you very much for your answer on that problem - your help is pretty much appreciated.

                – marc wellman
                Dec 2 '13 at 20:58
















              31














              Yours is a pretty good way already and works well with any range.



              Just thinking: another possibility is to get rid of the fractions by multiplying with a constant multiplier, and then build an array with the size of this multiplier. Multiplying by 10 you get



              P(1) = 2
              P(2) = 3
              P(3) = 5


              Then you create an array with the inverse values -- '1' goes into elements 1 and 2, '2' into 3 to 6, and so on:



              P = (1,1, 2,2,2, 3,3,3,3,3);



              and then you can pick a random element from this array instead.





              (Add.) Using the probabilities from the example in kiruwka's comment:



              int numsToGenerate           = new int    { 1,   2,    3,   4,    5   };
              double discreteProbabilities = new double { 0.1, 0.25, 0.3, 0.25, 0.1 };


              the smallest multiplier that leads to all-integers is 20, which gives you



              2, 5, 6, 5, 2


              and so the length of numsToGenerate would be 20, with the following values:



              1 1
              2 2 2 2 2
              3 3 3 3 3 3
              4 4 4 4 4
              5 5


              The distribution is exactly the same: the chance of '1', for example, is now 2 out of 20 -- still 0.1.



              This is based on your original probabilities all adding up to 1. If they do not, multiply the total by this same factor (which is then going to be your array length as well).






              share|improve this answer


























              • Thank you very much for your answer on that problem - your help is pretty much appreciated.

                – marc wellman
                Dec 2 '13 at 20:58














              31












              31








              31







              Yours is a pretty good way already and works well with any range.



              Just thinking: another possibility is to get rid of the fractions by multiplying with a constant multiplier, and then build an array with the size of this multiplier. Multiplying by 10 you get



              P(1) = 2
              P(2) = 3
              P(3) = 5


              Then you create an array with the inverse values -- '1' goes into elements 1 and 2, '2' into 3 to 6, and so on:



              P = (1,1, 2,2,2, 3,3,3,3,3);



              and then you can pick a random element from this array instead.





              (Add.) Using the probabilities from the example in kiruwka's comment:



              int numsToGenerate           = new int    { 1,   2,    3,   4,    5   };
              double discreteProbabilities = new double { 0.1, 0.25, 0.3, 0.25, 0.1 };


              the smallest multiplier that leads to all-integers is 20, which gives you



              2, 5, 6, 5, 2


              and so the length of numsToGenerate would be 20, with the following values:



              1 1
              2 2 2 2 2
              3 3 3 3 3 3
              4 4 4 4 4
              5 5


              The distribution is exactly the same: the chance of '1', for example, is now 2 out of 20 -- still 0.1.



              This is based on your original probabilities all adding up to 1. If they do not, multiply the total by this same factor (which is then going to be your array length as well).






              share|improve this answer















              Yours is a pretty good way already and works well with any range.



              Just thinking: another possibility is to get rid of the fractions by multiplying with a constant multiplier, and then build an array with the size of this multiplier. Multiplying by 10 you get



              P(1) = 2
              P(2) = 3
              P(3) = 5


              Then you create an array with the inverse values -- '1' goes into elements 1 and 2, '2' into 3 to 6, and so on:



              P = (1,1, 2,2,2, 3,3,3,3,3);



              and then you can pick a random element from this array instead.





              (Add.) Using the probabilities from the example in kiruwka's comment:



              int numsToGenerate           = new int    { 1,   2,    3,   4,    5   };
              double discreteProbabilities = new double { 0.1, 0.25, 0.3, 0.25, 0.1 };


              the smallest multiplier that leads to all-integers is 20, which gives you



              2, 5, 6, 5, 2


              and so the length of numsToGenerate would be 20, with the following values:



              1 1
              2 2 2 2 2
              3 3 3 3 3 3
              4 4 4 4 4
              5 5


              The distribution is exactly the same: the chance of '1', for example, is now 2 out of 20 -- still 0.1.



              This is based on your original probabilities all adding up to 1. If they do not, multiply the total by this same factor (which is then going to be your array length as well).







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Feb 19 '16 at 11:11

























              answered Dec 2 '13 at 12:34









              usr2564301usr2564301

              17.8k73370




              17.8k73370













              • Thank you very much for your answer on that problem - your help is pretty much appreciated.

                – marc wellman
                Dec 2 '13 at 20:58



















              • Thank you very much for your answer on that problem - your help is pretty much appreciated.

                – marc wellman
                Dec 2 '13 at 20:58

















              Thank you very much for your answer on that problem - your help is pretty much appreciated.

              – marc wellman
              Dec 2 '13 at 20:58





              Thank you very much for your answer on that problem - your help is pretty much appreciated.

              – marc wellman
              Dec 2 '13 at 20:58













              24














              Some time ago I wrote a helper class to solve this issue. The source code should show the concept clear enough:



              public class DistributedRandomNumberGenerator {

              private Map<Integer, Double> distribution;
              private double distSum;

              public DistributedRandomNumberGenerator() {
              distribution = new HashMap<>();
              }

              public void addNumber(int value, double distribution) {
              if (this.distribution.get(value) != null) {
              distSum -= this.distribution.get(value);
              }
              this.distribution.put(value, distribution);
              distSum += distribution;
              }

              public int getDistributedRandomNumber() {
              double rand = Math.random();
              double ratio = 1.0f / distSum;
              double tempDist = 0;
              for (Integer i : distribution.keySet()) {
              tempDist += distribution.get(i);
              if (rand / ratio <= tempDist) {
              return i;
              }
              }
              return 0;
              }

              }


              The usage of the class is as follows:



              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.3d); // Adds the numerical value 1 with a probability of 0.3 (30%)
              // [...] Add more values

              int random = drng.getDistributedRandomNumber(); // Generate a random number


              Test driver to verify functionality:



                  public static void main(String args) {
              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.2d);
              drng.addNumber(2, 0.3d);
              drng.addNumber(3, 0.5d);

              int testCount = 1000000;

              HashMap<Integer, Double> test = new HashMap<>();

              for (int i = 0; i < testCount; i++) {
              int random = drng.getDistributedRandomNumber();
              test.put(random, (test.get(random) == null) ? (1d / testCount) : test.get(random) + 1d / testCount);
              }

              System.out.println(test.toString());
              }


              Sample output for this test driver:



              {1=0.20019100000017953, 2=0.2999349999988933, 3=0.4998739999935438}





              share|improve this answer


























              • Nice piece of code. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:58











              • I like that! If you want to use it on a large scale tho the hashmap should use Float instead of Double to reduce unneccessary overhead

                – Xerus
                Oct 28 '17 at 13:36


















              24














              Some time ago I wrote a helper class to solve this issue. The source code should show the concept clear enough:



              public class DistributedRandomNumberGenerator {

              private Map<Integer, Double> distribution;
              private double distSum;

              public DistributedRandomNumberGenerator() {
              distribution = new HashMap<>();
              }

              public void addNumber(int value, double distribution) {
              if (this.distribution.get(value) != null) {
              distSum -= this.distribution.get(value);
              }
              this.distribution.put(value, distribution);
              distSum += distribution;
              }

              public int getDistributedRandomNumber() {
              double rand = Math.random();
              double ratio = 1.0f / distSum;
              double tempDist = 0;
              for (Integer i : distribution.keySet()) {
              tempDist += distribution.get(i);
              if (rand / ratio <= tempDist) {
              return i;
              }
              }
              return 0;
              }

              }


              The usage of the class is as follows:



              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.3d); // Adds the numerical value 1 with a probability of 0.3 (30%)
              // [...] Add more values

              int random = drng.getDistributedRandomNumber(); // Generate a random number


              Test driver to verify functionality:



                  public static void main(String args) {
              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.2d);
              drng.addNumber(2, 0.3d);
              drng.addNumber(3, 0.5d);

              int testCount = 1000000;

              HashMap<Integer, Double> test = new HashMap<>();

              for (int i = 0; i < testCount; i++) {
              int random = drng.getDistributedRandomNumber();
              test.put(random, (test.get(random) == null) ? (1d / testCount) : test.get(random) + 1d / testCount);
              }

              System.out.println(test.toString());
              }


              Sample output for this test driver:



              {1=0.20019100000017953, 2=0.2999349999988933, 3=0.4998739999935438}





              share|improve this answer


























              • Nice piece of code. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:58











              • I like that! If you want to use it on a large scale tho the hashmap should use Float instead of Double to reduce unneccessary overhead

                – Xerus
                Oct 28 '17 at 13:36
















              24












              24








              24







              Some time ago I wrote a helper class to solve this issue. The source code should show the concept clear enough:



              public class DistributedRandomNumberGenerator {

              private Map<Integer, Double> distribution;
              private double distSum;

              public DistributedRandomNumberGenerator() {
              distribution = new HashMap<>();
              }

              public void addNumber(int value, double distribution) {
              if (this.distribution.get(value) != null) {
              distSum -= this.distribution.get(value);
              }
              this.distribution.put(value, distribution);
              distSum += distribution;
              }

              public int getDistributedRandomNumber() {
              double rand = Math.random();
              double ratio = 1.0f / distSum;
              double tempDist = 0;
              for (Integer i : distribution.keySet()) {
              tempDist += distribution.get(i);
              if (rand / ratio <= tempDist) {
              return i;
              }
              }
              return 0;
              }

              }


              The usage of the class is as follows:



              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.3d); // Adds the numerical value 1 with a probability of 0.3 (30%)
              // [...] Add more values

              int random = drng.getDistributedRandomNumber(); // Generate a random number


              Test driver to verify functionality:



                  public static void main(String args) {
              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.2d);
              drng.addNumber(2, 0.3d);
              drng.addNumber(3, 0.5d);

              int testCount = 1000000;

              HashMap<Integer, Double> test = new HashMap<>();

              for (int i = 0; i < testCount; i++) {
              int random = drng.getDistributedRandomNumber();
              test.put(random, (test.get(random) == null) ? (1d / testCount) : test.get(random) + 1d / testCount);
              }

              System.out.println(test.toString());
              }


              Sample output for this test driver:



              {1=0.20019100000017953, 2=0.2999349999988933, 3=0.4998739999935438}





              share|improve this answer















              Some time ago I wrote a helper class to solve this issue. The source code should show the concept clear enough:



              public class DistributedRandomNumberGenerator {

              private Map<Integer, Double> distribution;
              private double distSum;

              public DistributedRandomNumberGenerator() {
              distribution = new HashMap<>();
              }

              public void addNumber(int value, double distribution) {
              if (this.distribution.get(value) != null) {
              distSum -= this.distribution.get(value);
              }
              this.distribution.put(value, distribution);
              distSum += distribution;
              }

              public int getDistributedRandomNumber() {
              double rand = Math.random();
              double ratio = 1.0f / distSum;
              double tempDist = 0;
              for (Integer i : distribution.keySet()) {
              tempDist += distribution.get(i);
              if (rand / ratio <= tempDist) {
              return i;
              }
              }
              return 0;
              }

              }


              The usage of the class is as follows:



              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.3d); // Adds the numerical value 1 with a probability of 0.3 (30%)
              // [...] Add more values

              int random = drng.getDistributedRandomNumber(); // Generate a random number


              Test driver to verify functionality:



                  public static void main(String args) {
              DistributedRandomNumberGenerator drng = new DistributedRandomNumberGenerator();
              drng.addNumber(1, 0.2d);
              drng.addNumber(2, 0.3d);
              drng.addNumber(3, 0.5d);

              int testCount = 1000000;

              HashMap<Integer, Double> test = new HashMap<>();

              for (int i = 0; i < testCount; i++) {
              int random = drng.getDistributedRandomNumber();
              test.put(random, (test.get(random) == null) ? (1d / testCount) : test.get(random) + 1d / testCount);
              }

              System.out.println(test.toString());
              }


              Sample output for this test driver:



              {1=0.20019100000017953, 2=0.2999349999988933, 3=0.4998739999935438}






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jan 7 '18 at 17:23

























              answered Dec 2 '13 at 13:50









              trylimitstrylimits

              2,0541629




              2,0541629













              • Nice piece of code. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:58











              • I like that! If you want to use it on a large scale tho the hashmap should use Float instead of Double to reduce unneccessary overhead

                – Xerus
                Oct 28 '17 at 13:36





















              • Nice piece of code. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:58











              • I like that! If you want to use it on a large scale tho the hashmap should use Float instead of Double to reduce unneccessary overhead

                – Xerus
                Oct 28 '17 at 13:36



















              Nice piece of code. Thank you very much.

              – marc wellman
              Dec 2 '13 at 20:58





              Nice piece of code. Thank you very much.

              – marc wellman
              Dec 2 '13 at 20:58













              I like that! If you want to use it on a large scale tho the hashmap should use Float instead of Double to reduce unneccessary overhead

              – Xerus
              Oct 28 '17 at 13:36







              I like that! If you want to use it on a large scale tho the hashmap should use Float instead of Double to reduce unneccessary overhead

              – Xerus
              Oct 28 '17 at 13:36













              8














              You already wrote the implementation in your question. ;)



              final int ran = myRandom.nextInt(100);
              if (ran > 50) { return 3; }
              else if (ran > 20) { return 2; }
              else { return 1; }


              You can speed this up for more complex implementations by per-calculating the result on a switch table like this:



              t[0] = 1; t[1] = 1; // ... one for each possible result
              return t[ran];


              But this should only be used if this is a performance bottleneck and called several hundred times per second.






              share|improve this answer
























              • Your answer helped me a lot. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:59
















              8














              You already wrote the implementation in your question. ;)



              final int ran = myRandom.nextInt(100);
              if (ran > 50) { return 3; }
              else if (ran > 20) { return 2; }
              else { return 1; }


              You can speed this up for more complex implementations by per-calculating the result on a switch table like this:



              t[0] = 1; t[1] = 1; // ... one for each possible result
              return t[ran];


              But this should only be used if this is a performance bottleneck and called several hundred times per second.






              share|improve this answer
























              • Your answer helped me a lot. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:59














              8












              8








              8







              You already wrote the implementation in your question. ;)



              final int ran = myRandom.nextInt(100);
              if (ran > 50) { return 3; }
              else if (ran > 20) { return 2; }
              else { return 1; }


              You can speed this up for more complex implementations by per-calculating the result on a switch table like this:



              t[0] = 1; t[1] = 1; // ... one for each possible result
              return t[ran];


              But this should only be used if this is a performance bottleneck and called several hundred times per second.






              share|improve this answer













              You already wrote the implementation in your question. ;)



              final int ran = myRandom.nextInt(100);
              if (ran > 50) { return 3; }
              else if (ran > 20) { return 2; }
              else { return 1; }


              You can speed this up for more complex implementations by per-calculating the result on a switch table like this:



              t[0] = 1; t[1] = 1; // ... one for each possible result
              return t[ran];


              But this should only be used if this is a performance bottleneck and called several hundred times per second.







              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Dec 2 '13 at 12:30









              TwoTheTwoThe

              10.2k12040




              10.2k12040













              • Your answer helped me a lot. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:59



















              • Your answer helped me a lot. Thank you very much.

                – marc wellman
                Dec 2 '13 at 20:59

















              Your answer helped me a lot. Thank you very much.

              – marc wellman
              Dec 2 '13 at 20:59





              Your answer helped me a lot. Thank you very much.

              – marc wellman
              Dec 2 '13 at 20:59











              5














              If you have performance issue instead of searching all the n values O(n)



              you could perform binary search which costs O(log n)



              Random r=new Random();      
              double weights=new double{0.1,0.1+0.2,0.1+0.2+0.5};
              // end of init
              double random=r.nextDouble();
              // next perform the binary search in weights array


              you only need to access log2(weights.length) in average if you have a lot of weights elements.






              share|improve this answer




























                5














                If you have performance issue instead of searching all the n values O(n)



                you could perform binary search which costs O(log n)



                Random r=new Random();      
                double weights=new double{0.1,0.1+0.2,0.1+0.2+0.5};
                // end of init
                double random=r.nextDouble();
                // next perform the binary search in weights array


                you only need to access log2(weights.length) in average if you have a lot of weights elements.






                share|improve this answer


























                  5












                  5








                  5







                  If you have performance issue instead of searching all the n values O(n)



                  you could perform binary search which costs O(log n)



                  Random r=new Random();      
                  double weights=new double{0.1,0.1+0.2,0.1+0.2+0.5};
                  // end of init
                  double random=r.nextDouble();
                  // next perform the binary search in weights array


                  you only need to access log2(weights.length) in average if you have a lot of weights elements.






                  share|improve this answer













                  If you have performance issue instead of searching all the n values O(n)



                  you could perform binary search which costs O(log n)



                  Random r=new Random();      
                  double weights=new double{0.1,0.1+0.2,0.1+0.2+0.5};
                  // end of init
                  double random=r.nextDouble();
                  // next perform the binary search in weights array


                  you only need to access log2(weights.length) in average if you have a lot of weights elements.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 2 '13 at 12:54









                  chrochro

                  1,5691422




                  1,5691422























                      4














                      Your approach is fine for the specific numbers you picked, although you could reduce storage by using an array of 10 instead of an array of 100. However, this approach doesn't generalize well to large numbers of outcomes or outcomes with probabilities such as 1/e or 1/PI.



                      A potentially better solution is to use an alias table. The alias method takes O(n) work to set up the table for n outcomes, but then is constant time to generate regardless of how many outcomes there are.






                      share|improve this answer


























                      • Thank you very much :) You helped me a lot.

                        – marc wellman
                        Dec 2 '13 at 20:58
















                      4














                      Your approach is fine for the specific numbers you picked, although you could reduce storage by using an array of 10 instead of an array of 100. However, this approach doesn't generalize well to large numbers of outcomes or outcomes with probabilities such as 1/e or 1/PI.



                      A potentially better solution is to use an alias table. The alias method takes O(n) work to set up the table for n outcomes, but then is constant time to generate regardless of how many outcomes there are.






                      share|improve this answer


























                      • Thank you very much :) You helped me a lot.

                        – marc wellman
                        Dec 2 '13 at 20:58














                      4












                      4








                      4







                      Your approach is fine for the specific numbers you picked, although you could reduce storage by using an array of 10 instead of an array of 100. However, this approach doesn't generalize well to large numbers of outcomes or outcomes with probabilities such as 1/e or 1/PI.



                      A potentially better solution is to use an alias table. The alias method takes O(n) work to set up the table for n outcomes, but then is constant time to generate regardless of how many outcomes there are.






                      share|improve this answer















                      Your approach is fine for the specific numbers you picked, although you could reduce storage by using an array of 10 instead of an array of 100. However, this approach doesn't generalize well to large numbers of outcomes or outcomes with probabilities such as 1/e or 1/PI.



                      A potentially better solution is to use an alias table. The alias method takes O(n) work to set up the table for n outcomes, but then is constant time to generate regardless of how many outcomes there are.







                      share|improve this answer














                      share|improve this answer



                      share|improve this answer








                      edited May 23 '17 at 12:34









                      Community

                      11




                      11










                      answered Dec 2 '13 at 19:41









                      pjspjs

                      13.2k41540




                      13.2k41540













                      • Thank you very much :) You helped me a lot.

                        – marc wellman
                        Dec 2 '13 at 20:58



















                      • Thank you very much :) You helped me a lot.

                        – marc wellman
                        Dec 2 '13 at 20:58

















                      Thank you very much :) You helped me a lot.

                      – marc wellman
                      Dec 2 '13 at 20:58





                      Thank you very much :) You helped me a lot.

                      – marc wellman
                      Dec 2 '13 at 20:58











                      1














                      Try this:
                      In this example i use an array of chars, but you can substitute it with your integer array.



                      Weight list contains for each char the associated probability.
                      It represent the probability distribution of my charset.



                      In weightsum list for each char i stored his actual probability plus the sum of any antecedent probability.



                      For example in weightsum the third element corresponding to 'C', is 65:

                      P('A') + P('B) + P('C') = P(X=>c)

                      10 + 20 + 25 = 65



                      So weightsum represent the cumulative distribution of my charset.
                      weightsum contains the following values:



                      It's easy to see that the 8th element correspondig to H, have a larger gap (80 of course like his probability) then is more like to happen!



                              List<Character> charset =   Arrays.asList('A','B','C','D','E','F','G','H','I','J');
                      List<Integer> weight = Arrays.asList(10,30,25,60,20,70,10,80,20,30);
                      List<Integer> weightsum = new ArrayList<>();

                      int i=0,j=0,k=0;
                      Random Rnd = new Random();

                      weightsum.add(weight.get(0));

                      for (i = 1; i < 10; i++)
                      weightsum.add(weightsum.get(i-1) + weight.get(i));


                      Then i use a cycle to get 30 random char extractions from charset,each one drawned accordingly to the cumulative probability.



                      In k i stored a random number from 0 to the max value allocated in weightsum.
                      Then i look up in weightsum for a number grather than k, the position of the number in weightsum correspond to the same position of the char in charset.



                         for (j = 0; j < 30; j++)
                      {
                      Random r = new Random();
                      k = r.nextInt(weightsum.get(weightsum.size()-1));

                      for (i = 0; k > weightsum.get(i); i++) ;
                      System.out.print(charset.get(i));
                      }


                      The code give out that sequence of char:



                      HHFAIIDFBDDDHFICJHACCDFJBGBHHB



                      Let's do the math!



                      A = 2

                      B = 4

                      C = 3

                      D = 5

                      E = 0

                      F = 4

                      G = 1

                      H = 6

                      I = 3

                      J = 2



                      Total.:30

                      As we wish D and H are have more occurances (70% and 80% prob.)

                      Otherwinse E didn't come out at all. (10% prob.)






                      share|improve this answer




























                        1














                        Try this:
                        In this example i use an array of chars, but you can substitute it with your integer array.



                        Weight list contains for each char the associated probability.
                        It represent the probability distribution of my charset.



                        In weightsum list for each char i stored his actual probability plus the sum of any antecedent probability.



                        For example in weightsum the third element corresponding to 'C', is 65:

                        P('A') + P('B) + P('C') = P(X=>c)

                        10 + 20 + 25 = 65



                        So weightsum represent the cumulative distribution of my charset.
                        weightsum contains the following values:



                        It's easy to see that the 8th element correspondig to H, have a larger gap (80 of course like his probability) then is more like to happen!



                                List<Character> charset =   Arrays.asList('A','B','C','D','E','F','G','H','I','J');
                        List<Integer> weight = Arrays.asList(10,30,25,60,20,70,10,80,20,30);
                        List<Integer> weightsum = new ArrayList<>();

                        int i=0,j=0,k=0;
                        Random Rnd = new Random();

                        weightsum.add(weight.get(0));

                        for (i = 1; i < 10; i++)
                        weightsum.add(weightsum.get(i-1) + weight.get(i));


                        Then i use a cycle to get 30 random char extractions from charset,each one drawned accordingly to the cumulative probability.



                        In k i stored a random number from 0 to the max value allocated in weightsum.
                        Then i look up in weightsum for a number grather than k, the position of the number in weightsum correspond to the same position of the char in charset.



                           for (j = 0; j < 30; j++)
                        {
                        Random r = new Random();
                        k = r.nextInt(weightsum.get(weightsum.size()-1));

                        for (i = 0; k > weightsum.get(i); i++) ;
                        System.out.print(charset.get(i));
                        }


                        The code give out that sequence of char:



                        HHFAIIDFBDDDHFICJHACCDFJBGBHHB



                        Let's do the math!



                        A = 2

                        B = 4

                        C = 3

                        D = 5

                        E = 0

                        F = 4

                        G = 1

                        H = 6

                        I = 3

                        J = 2



                        Total.:30

                        As we wish D and H are have more occurances (70% and 80% prob.)

                        Otherwinse E didn't come out at all. (10% prob.)






                        share|improve this answer


























                          1












                          1








                          1







                          Try this:
                          In this example i use an array of chars, but you can substitute it with your integer array.



                          Weight list contains for each char the associated probability.
                          It represent the probability distribution of my charset.



                          In weightsum list for each char i stored his actual probability plus the sum of any antecedent probability.



                          For example in weightsum the third element corresponding to 'C', is 65:

                          P('A') + P('B) + P('C') = P(X=>c)

                          10 + 20 + 25 = 65



                          So weightsum represent the cumulative distribution of my charset.
                          weightsum contains the following values:



                          It's easy to see that the 8th element correspondig to H, have a larger gap (80 of course like his probability) then is more like to happen!



                                  List<Character> charset =   Arrays.asList('A','B','C','D','E','F','G','H','I','J');
                          List<Integer> weight = Arrays.asList(10,30,25,60,20,70,10,80,20,30);
                          List<Integer> weightsum = new ArrayList<>();

                          int i=0,j=0,k=0;
                          Random Rnd = new Random();

                          weightsum.add(weight.get(0));

                          for (i = 1; i < 10; i++)
                          weightsum.add(weightsum.get(i-1) + weight.get(i));


                          Then i use a cycle to get 30 random char extractions from charset,each one drawned accordingly to the cumulative probability.



                          In k i stored a random number from 0 to the max value allocated in weightsum.
                          Then i look up in weightsum for a number grather than k, the position of the number in weightsum correspond to the same position of the char in charset.



                             for (j = 0; j < 30; j++)
                          {
                          Random r = new Random();
                          k = r.nextInt(weightsum.get(weightsum.size()-1));

                          for (i = 0; k > weightsum.get(i); i++) ;
                          System.out.print(charset.get(i));
                          }


                          The code give out that sequence of char:



                          HHFAIIDFBDDDHFICJHACCDFJBGBHHB



                          Let's do the math!



                          A = 2

                          B = 4

                          C = 3

                          D = 5

                          E = 0

                          F = 4

                          G = 1

                          H = 6

                          I = 3

                          J = 2



                          Total.:30

                          As we wish D and H are have more occurances (70% and 80% prob.)

                          Otherwinse E didn't come out at all. (10% prob.)






                          share|improve this answer













                          Try this:
                          In this example i use an array of chars, but you can substitute it with your integer array.



                          Weight list contains for each char the associated probability.
                          It represent the probability distribution of my charset.



                          In weightsum list for each char i stored his actual probability plus the sum of any antecedent probability.



                          For example in weightsum the third element corresponding to 'C', is 65:

                          P('A') + P('B) + P('C') = P(X=>c)

                          10 + 20 + 25 = 65



                          So weightsum represent the cumulative distribution of my charset.
                          weightsum contains the following values:



                          It's easy to see that the 8th element correspondig to H, have a larger gap (80 of course like his probability) then is more like to happen!



                                  List<Character> charset =   Arrays.asList('A','B','C','D','E','F','G','H','I','J');
                          List<Integer> weight = Arrays.asList(10,30,25,60,20,70,10,80,20,30);
                          List<Integer> weightsum = new ArrayList<>();

                          int i=0,j=0,k=0;
                          Random Rnd = new Random();

                          weightsum.add(weight.get(0));

                          for (i = 1; i < 10; i++)
                          weightsum.add(weightsum.get(i-1) + weight.get(i));


                          Then i use a cycle to get 30 random char extractions from charset,each one drawned accordingly to the cumulative probability.



                          In k i stored a random number from 0 to the max value allocated in weightsum.
                          Then i look up in weightsum for a number grather than k, the position of the number in weightsum correspond to the same position of the char in charset.



                             for (j = 0; j < 30; j++)
                          {
                          Random r = new Random();
                          k = r.nextInt(weightsum.get(weightsum.size()-1));

                          for (i = 0; k > weightsum.get(i); i++) ;
                          System.out.print(charset.get(i));
                          }


                          The code give out that sequence of char:



                          HHFAIIDFBDDDHFICJHACCDFJBGBHHB



                          Let's do the math!



                          A = 2

                          B = 4

                          C = 3

                          D = 5

                          E = 0

                          F = 4

                          G = 1

                          H = 6

                          I = 3

                          J = 2



                          Total.:30

                          As we wish D and H are have more occurances (70% and 80% prob.)

                          Otherwinse E didn't come out at all. (10% prob.)







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Apr 26 '18 at 16:01









                          Giulio PilottoGiulio Pilotto

                          111




                          111























                              0














                              Written this class for interview after referencing the paper pointed by pjs in another post , the population of base64 table can be further optimized. The result is amazingly fast, initialization is slightly expensive, but if the probabilities are not changing often, this is a good approach.



                              *For duplicate key, the last probability is taken instead of being combined (slightly different from EnumeratedIntegerDistribution behaviour)



                              public class RandomGen5 extends BaseRandomGen {

                              private int t_array = new int[4];
                              private int sumOfNumerator;
                              private final static int DENOM = (int) Math.pow(2, 24);
                              private static final int bitCount = new int {18, 12, 6, 0};
                              private static final int cumPow64 = new int {
                              (int) ( Math.pow( 64, 3 ) + Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                              (int) ( Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                              (int) ( Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                              (int) ( Math.pow( 64, 0 ) )
                              };


                              ArrayList base64Table = {new ArrayList<Integer>()
                              , new ArrayList<Integer>()
                              , new ArrayList<Integer>()
                              , new ArrayList<Integer>()};

                              public int nextNum() {
                              int rand = (int) (randGen.nextFloat() * sumOfNumerator);

                              for ( int x = 0 ; x < 4 ; x ++ ) {
                              if (rand < t_array[x])
                              return x == 0 ? (int) base64Table[x].get(rand >> bitCount[x])
                              : (int) base64Table[x].get( ( rand - t_array[x-1] ) >> bitCount[x]) ;
                              }
                              return 0;
                              }

                              public void setIntProbList( int intList, float probList ) {
                              Map<Integer, Float> map = normalizeMap( intList, probList );
                              populateBase64Table( map );
                              }

                              private void clearBase64Table() {
                              for ( int x = 0 ; x < 4 ; x++ ) {
                              base64Table[x].clear();
                              }
                              }

                              private void populateBase64Table( Map<Integer, Float> intProbMap ) {
                              int startPow, decodedFreq, table_index;
                              float rem;

                              clearBase64Table();

                              for ( Map.Entry<Integer, Float> numObj : intProbMap.entrySet() ) {
                              rem = numObj.getValue();
                              table_index = 3;
                              for ( int x = 0 ; x < 4 ; x++ ) {
                              decodedFreq = (int) (rem % 64);
                              rem /= 64;
                              for ( int y = 0 ; y < decodedFreq ; y ++ ) {
                              base64Table[table_index].add( numObj.getKey() );
                              }
                              table_index--;
                              }
                              }

                              startPow = 3;
                              for ( int x = 0 ; x < 4 ; x++ ) {
                              t_array[x] = x == 0 ? (int) ( Math.pow( 64, startPow-- ) * base64Table[x].size() )
                              : ( (int) ( ( Math.pow( 64, startPow-- ) * base64Table[x].size() ) + t_array[x-1] ) );
                              }

                              }

                              private Map<Integer, Float> normalizeMap( int intList, float probList ) {
                              Map<Integer, Float> tmpMap = new HashMap<>();
                              Float mappedFloat;
                              int numerator;
                              float normalizedProb, distSum = 0;

                              //Remove duplicates, and calculate the sum of non-repeated keys
                              for ( int x = 0 ; x < probList.length ; x++ ) {
                              mappedFloat = tmpMap.get( intList[x] );
                              if ( mappedFloat != null ) {
                              distSum -= mappedFloat;
                              } else {
                              distSum += probList[x];
                              }
                              tmpMap.put( intList[x], probList[x] );
                              }

                              //Normalise the map to key -> corresponding numerator by multiplying with 2^24
                              sumOfNumerator = 0;
                              for ( Map.Entry<Integer, Float> intProb : tmpMap.entrySet() ) {
                              normalizedProb = intProb.getValue() / distSum;
                              numerator = (int) ( normalizedProb * DENOM );
                              intProb.setValue( (float) numerator );
                              sumOfNumerator += numerator;
                              }

                              return tmpMap;
                              }
                              }





                              share|improve this answer






























                                0














                                Written this class for interview after referencing the paper pointed by pjs in another post , the population of base64 table can be further optimized. The result is amazingly fast, initialization is slightly expensive, but if the probabilities are not changing often, this is a good approach.



                                *For duplicate key, the last probability is taken instead of being combined (slightly different from EnumeratedIntegerDistribution behaviour)



                                public class RandomGen5 extends BaseRandomGen {

                                private int t_array = new int[4];
                                private int sumOfNumerator;
                                private final static int DENOM = (int) Math.pow(2, 24);
                                private static final int bitCount = new int {18, 12, 6, 0};
                                private static final int cumPow64 = new int {
                                (int) ( Math.pow( 64, 3 ) + Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                (int) ( Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                (int) ( Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                (int) ( Math.pow( 64, 0 ) )
                                };


                                ArrayList base64Table = {new ArrayList<Integer>()
                                , new ArrayList<Integer>()
                                , new ArrayList<Integer>()
                                , new ArrayList<Integer>()};

                                public int nextNum() {
                                int rand = (int) (randGen.nextFloat() * sumOfNumerator);

                                for ( int x = 0 ; x < 4 ; x ++ ) {
                                if (rand < t_array[x])
                                return x == 0 ? (int) base64Table[x].get(rand >> bitCount[x])
                                : (int) base64Table[x].get( ( rand - t_array[x-1] ) >> bitCount[x]) ;
                                }
                                return 0;
                                }

                                public void setIntProbList( int intList, float probList ) {
                                Map<Integer, Float> map = normalizeMap( intList, probList );
                                populateBase64Table( map );
                                }

                                private void clearBase64Table() {
                                for ( int x = 0 ; x < 4 ; x++ ) {
                                base64Table[x].clear();
                                }
                                }

                                private void populateBase64Table( Map<Integer, Float> intProbMap ) {
                                int startPow, decodedFreq, table_index;
                                float rem;

                                clearBase64Table();

                                for ( Map.Entry<Integer, Float> numObj : intProbMap.entrySet() ) {
                                rem = numObj.getValue();
                                table_index = 3;
                                for ( int x = 0 ; x < 4 ; x++ ) {
                                decodedFreq = (int) (rem % 64);
                                rem /= 64;
                                for ( int y = 0 ; y < decodedFreq ; y ++ ) {
                                base64Table[table_index].add( numObj.getKey() );
                                }
                                table_index--;
                                }
                                }

                                startPow = 3;
                                for ( int x = 0 ; x < 4 ; x++ ) {
                                t_array[x] = x == 0 ? (int) ( Math.pow( 64, startPow-- ) * base64Table[x].size() )
                                : ( (int) ( ( Math.pow( 64, startPow-- ) * base64Table[x].size() ) + t_array[x-1] ) );
                                }

                                }

                                private Map<Integer, Float> normalizeMap( int intList, float probList ) {
                                Map<Integer, Float> tmpMap = new HashMap<>();
                                Float mappedFloat;
                                int numerator;
                                float normalizedProb, distSum = 0;

                                //Remove duplicates, and calculate the sum of non-repeated keys
                                for ( int x = 0 ; x < probList.length ; x++ ) {
                                mappedFloat = tmpMap.get( intList[x] );
                                if ( mappedFloat != null ) {
                                distSum -= mappedFloat;
                                } else {
                                distSum += probList[x];
                                }
                                tmpMap.put( intList[x], probList[x] );
                                }

                                //Normalise the map to key -> corresponding numerator by multiplying with 2^24
                                sumOfNumerator = 0;
                                for ( Map.Entry<Integer, Float> intProb : tmpMap.entrySet() ) {
                                normalizedProb = intProb.getValue() / distSum;
                                numerator = (int) ( normalizedProb * DENOM );
                                intProb.setValue( (float) numerator );
                                sumOfNumerator += numerator;
                                }

                                return tmpMap;
                                }
                                }





                                share|improve this answer




























                                  0












                                  0








                                  0







                                  Written this class for interview after referencing the paper pointed by pjs in another post , the population of base64 table can be further optimized. The result is amazingly fast, initialization is slightly expensive, but if the probabilities are not changing often, this is a good approach.



                                  *For duplicate key, the last probability is taken instead of being combined (slightly different from EnumeratedIntegerDistribution behaviour)



                                  public class RandomGen5 extends BaseRandomGen {

                                  private int t_array = new int[4];
                                  private int sumOfNumerator;
                                  private final static int DENOM = (int) Math.pow(2, 24);
                                  private static final int bitCount = new int {18, 12, 6, 0};
                                  private static final int cumPow64 = new int {
                                  (int) ( Math.pow( 64, 3 ) + Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                  (int) ( Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                  (int) ( Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                  (int) ( Math.pow( 64, 0 ) )
                                  };


                                  ArrayList base64Table = {new ArrayList<Integer>()
                                  , new ArrayList<Integer>()
                                  , new ArrayList<Integer>()
                                  , new ArrayList<Integer>()};

                                  public int nextNum() {
                                  int rand = (int) (randGen.nextFloat() * sumOfNumerator);

                                  for ( int x = 0 ; x < 4 ; x ++ ) {
                                  if (rand < t_array[x])
                                  return x == 0 ? (int) base64Table[x].get(rand >> bitCount[x])
                                  : (int) base64Table[x].get( ( rand - t_array[x-1] ) >> bitCount[x]) ;
                                  }
                                  return 0;
                                  }

                                  public void setIntProbList( int intList, float probList ) {
                                  Map<Integer, Float> map = normalizeMap( intList, probList );
                                  populateBase64Table( map );
                                  }

                                  private void clearBase64Table() {
                                  for ( int x = 0 ; x < 4 ; x++ ) {
                                  base64Table[x].clear();
                                  }
                                  }

                                  private void populateBase64Table( Map<Integer, Float> intProbMap ) {
                                  int startPow, decodedFreq, table_index;
                                  float rem;

                                  clearBase64Table();

                                  for ( Map.Entry<Integer, Float> numObj : intProbMap.entrySet() ) {
                                  rem = numObj.getValue();
                                  table_index = 3;
                                  for ( int x = 0 ; x < 4 ; x++ ) {
                                  decodedFreq = (int) (rem % 64);
                                  rem /= 64;
                                  for ( int y = 0 ; y < decodedFreq ; y ++ ) {
                                  base64Table[table_index].add( numObj.getKey() );
                                  }
                                  table_index--;
                                  }
                                  }

                                  startPow = 3;
                                  for ( int x = 0 ; x < 4 ; x++ ) {
                                  t_array[x] = x == 0 ? (int) ( Math.pow( 64, startPow-- ) * base64Table[x].size() )
                                  : ( (int) ( ( Math.pow( 64, startPow-- ) * base64Table[x].size() ) + t_array[x-1] ) );
                                  }

                                  }

                                  private Map<Integer, Float> normalizeMap( int intList, float probList ) {
                                  Map<Integer, Float> tmpMap = new HashMap<>();
                                  Float mappedFloat;
                                  int numerator;
                                  float normalizedProb, distSum = 0;

                                  //Remove duplicates, and calculate the sum of non-repeated keys
                                  for ( int x = 0 ; x < probList.length ; x++ ) {
                                  mappedFloat = tmpMap.get( intList[x] );
                                  if ( mappedFloat != null ) {
                                  distSum -= mappedFloat;
                                  } else {
                                  distSum += probList[x];
                                  }
                                  tmpMap.put( intList[x], probList[x] );
                                  }

                                  //Normalise the map to key -> corresponding numerator by multiplying with 2^24
                                  sumOfNumerator = 0;
                                  for ( Map.Entry<Integer, Float> intProb : tmpMap.entrySet() ) {
                                  normalizedProb = intProb.getValue() / distSum;
                                  numerator = (int) ( normalizedProb * DENOM );
                                  intProb.setValue( (float) numerator );
                                  sumOfNumerator += numerator;
                                  }

                                  return tmpMap;
                                  }
                                  }





                                  share|improve this answer















                                  Written this class for interview after referencing the paper pointed by pjs in another post , the population of base64 table can be further optimized. The result is amazingly fast, initialization is slightly expensive, but if the probabilities are not changing often, this is a good approach.



                                  *For duplicate key, the last probability is taken instead of being combined (slightly different from EnumeratedIntegerDistribution behaviour)



                                  public class RandomGen5 extends BaseRandomGen {

                                  private int t_array = new int[4];
                                  private int sumOfNumerator;
                                  private final static int DENOM = (int) Math.pow(2, 24);
                                  private static final int bitCount = new int {18, 12, 6, 0};
                                  private static final int cumPow64 = new int {
                                  (int) ( Math.pow( 64, 3 ) + Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                  (int) ( Math.pow( 64, 2 ) + Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                  (int) ( Math.pow( 64, 1 ) + Math.pow( 64, 0 ) ),
                                  (int) ( Math.pow( 64, 0 ) )
                                  };


                                  ArrayList base64Table = {new ArrayList<Integer>()
                                  , new ArrayList<Integer>()
                                  , new ArrayList<Integer>()
                                  , new ArrayList<Integer>()};

                                  public int nextNum() {
                                  int rand = (int) (randGen.nextFloat() * sumOfNumerator);

                                  for ( int x = 0 ; x < 4 ; x ++ ) {
                                  if (rand < t_array[x])
                                  return x == 0 ? (int) base64Table[x].get(rand >> bitCount[x])
                                  : (int) base64Table[x].get( ( rand - t_array[x-1] ) >> bitCount[x]) ;
                                  }
                                  return 0;
                                  }

                                  public void setIntProbList( int intList, float probList ) {
                                  Map<Integer, Float> map = normalizeMap( intList, probList );
                                  populateBase64Table( map );
                                  }

                                  private void clearBase64Table() {
                                  for ( int x = 0 ; x < 4 ; x++ ) {
                                  base64Table[x].clear();
                                  }
                                  }

                                  private void populateBase64Table( Map<Integer, Float> intProbMap ) {
                                  int startPow, decodedFreq, table_index;
                                  float rem;

                                  clearBase64Table();

                                  for ( Map.Entry<Integer, Float> numObj : intProbMap.entrySet() ) {
                                  rem = numObj.getValue();
                                  table_index = 3;
                                  for ( int x = 0 ; x < 4 ; x++ ) {
                                  decodedFreq = (int) (rem % 64);
                                  rem /= 64;
                                  for ( int y = 0 ; y < decodedFreq ; y ++ ) {
                                  base64Table[table_index].add( numObj.getKey() );
                                  }
                                  table_index--;
                                  }
                                  }

                                  startPow = 3;
                                  for ( int x = 0 ; x < 4 ; x++ ) {
                                  t_array[x] = x == 0 ? (int) ( Math.pow( 64, startPow-- ) * base64Table[x].size() )
                                  : ( (int) ( ( Math.pow( 64, startPow-- ) * base64Table[x].size() ) + t_array[x-1] ) );
                                  }

                                  }

                                  private Map<Integer, Float> normalizeMap( int intList, float probList ) {
                                  Map<Integer, Float> tmpMap = new HashMap<>();
                                  Float mappedFloat;
                                  int numerator;
                                  float normalizedProb, distSum = 0;

                                  //Remove duplicates, and calculate the sum of non-repeated keys
                                  for ( int x = 0 ; x < probList.length ; x++ ) {
                                  mappedFloat = tmpMap.get( intList[x] );
                                  if ( mappedFloat != null ) {
                                  distSum -= mappedFloat;
                                  } else {
                                  distSum += probList[x];
                                  }
                                  tmpMap.put( intList[x], probList[x] );
                                  }

                                  //Normalise the map to key -> corresponding numerator by multiplying with 2^24
                                  sumOfNumerator = 0;
                                  for ( Map.Entry<Integer, Float> intProb : tmpMap.entrySet() ) {
                                  normalizedProb = intProb.getValue() / distSum;
                                  numerator = (int) ( normalizedProb * DENOM );
                                  intProb.setValue( (float) numerator );
                                  sumOfNumerator += numerator;
                                  }

                                  return tmpMap;
                                  }
                                  }






                                  share|improve this answer














                                  share|improve this answer



                                  share|improve this answer








                                  edited May 13 '18 at 23:03

























                                  answered Mar 28 '18 at 23:05









                                  E.R.TanE.R.Tan

                                  11




                                  11























                                      0














                                      If you are not against adding a new library in your code, this feature is already implemented in MockNeat, check the probabilities() method.



                                      Some examples directly from the wiki:



                                      String s = mockNeat.probabilites(String.class)
                                      .add(0.1, "A") // 10% chance
                                      .add(0.2, "B") // 20% chance
                                      .add(0.5, "C") // 50% chance
                                      .add(0.2, "D") // 20% chance
                                      .val();


                                      Or if you want to generate numbers within given ranges with a given probability you can do something like:



                                      Integer x = m.probabilites(Integer.class)
                                      .add(0.2, m.ints().range(0, 100))
                                      .add(0.5, m.ints().range(100, 200))
                                      .add(0.3, m.ints().range(200, 300))
                                      .val();


                                      Disclaimer: I am the author of the library, so I might be biased when I am recommending it.






                                      share|improve this answer






























                                        0














                                        If you are not against adding a new library in your code, this feature is already implemented in MockNeat, check the probabilities() method.



                                        Some examples directly from the wiki:



                                        String s = mockNeat.probabilites(String.class)
                                        .add(0.1, "A") // 10% chance
                                        .add(0.2, "B") // 20% chance
                                        .add(0.5, "C") // 50% chance
                                        .add(0.2, "D") // 20% chance
                                        .val();


                                        Or if you want to generate numbers within given ranges with a given probability you can do something like:



                                        Integer x = m.probabilites(Integer.class)
                                        .add(0.2, m.ints().range(0, 100))
                                        .add(0.5, m.ints().range(100, 200))
                                        .add(0.3, m.ints().range(200, 300))
                                        .val();


                                        Disclaimer: I am the author of the library, so I might be biased when I am recommending it.






                                        share|improve this answer




























                                          0












                                          0








                                          0







                                          If you are not against adding a new library in your code, this feature is already implemented in MockNeat, check the probabilities() method.



                                          Some examples directly from the wiki:



                                          String s = mockNeat.probabilites(String.class)
                                          .add(0.1, "A") // 10% chance
                                          .add(0.2, "B") // 20% chance
                                          .add(0.5, "C") // 50% chance
                                          .add(0.2, "D") // 20% chance
                                          .val();


                                          Or if you want to generate numbers within given ranges with a given probability you can do something like:



                                          Integer x = m.probabilites(Integer.class)
                                          .add(0.2, m.ints().range(0, 100))
                                          .add(0.5, m.ints().range(100, 200))
                                          .add(0.3, m.ints().range(200, 300))
                                          .val();


                                          Disclaimer: I am the author of the library, so I might be biased when I am recommending it.






                                          share|improve this answer















                                          If you are not against adding a new library in your code, this feature is already implemented in MockNeat, check the probabilities() method.



                                          Some examples directly from the wiki:



                                          String s = mockNeat.probabilites(String.class)
                                          .add(0.1, "A") // 10% chance
                                          .add(0.2, "B") // 20% chance
                                          .add(0.5, "C") // 50% chance
                                          .add(0.2, "D") // 20% chance
                                          .val();


                                          Or if you want to generate numbers within given ranges with a given probability you can do something like:



                                          Integer x = m.probabilites(Integer.class)
                                          .add(0.2, m.ints().range(0, 100))
                                          .add(0.5, m.ints().range(100, 200))
                                          .add(0.3, m.ints().range(200, 300))
                                          .val();


                                          Disclaimer: I am the author of the library, so I might be biased when I am recommending it.







                                          share|improve this answer














                                          share|improve this answer



                                          share|improve this answer








                                          edited Sep 12 '18 at 12:35

























                                          answered Sep 12 '18 at 12:19









                                          Andrei CiobanuAndrei Ciobanu

                                          5,7741862110




                                          5,7741862110























                                              0














                                              Here is the python code even though you ask for java, but it's very similar.



                                              # weighted probability

                                              theta = np.array([0.1,0.25,0.6,0.05])
                                              print(theta)

                                              sample_axis = np.hstack((np.zeros(1), np.cumsum(theta)))
                                              print(sample_axis)


                                              [0. 0.1 0.35 0.95 1. ]. This represent the cumulative distribution.



                                              you can use a uniform distribution to draw an index in this unit range.



                                              def binary_search(axis, q, s, e):
                                              if e-s <= 1:
                                              print(s)
                                              return s
                                              else:
                                              m = int( np.around( (s+e)/2 ) )
                                              if q < axis[m]:
                                              binary_search(axis, q, s, m)
                                              else:
                                              binary_search(axis, q, m, e)



                                              range_index = np.random.rand(1)
                                              print(range_index)
                                              q = range_index
                                              s = 0
                                              e = sample_axis.shape[0]-1
                                              binary_search(sample_axis, q, 0, e)





                                              share|improve this answer




























                                                0














                                                Here is the python code even though you ask for java, but it's very similar.



                                                # weighted probability

                                                theta = np.array([0.1,0.25,0.6,0.05])
                                                print(theta)

                                                sample_axis = np.hstack((np.zeros(1), np.cumsum(theta)))
                                                print(sample_axis)


                                                [0. 0.1 0.35 0.95 1. ]. This represent the cumulative distribution.



                                                you can use a uniform distribution to draw an index in this unit range.



                                                def binary_search(axis, q, s, e):
                                                if e-s <= 1:
                                                print(s)
                                                return s
                                                else:
                                                m = int( np.around( (s+e)/2 ) )
                                                if q < axis[m]:
                                                binary_search(axis, q, s, m)
                                                else:
                                                binary_search(axis, q, m, e)



                                                range_index = np.random.rand(1)
                                                print(range_index)
                                                q = range_index
                                                s = 0
                                                e = sample_axis.shape[0]-1
                                                binary_search(sample_axis, q, 0, e)





                                                share|improve this answer


























                                                  0












                                                  0








                                                  0







                                                  Here is the python code even though you ask for java, but it's very similar.



                                                  # weighted probability

                                                  theta = np.array([0.1,0.25,0.6,0.05])
                                                  print(theta)

                                                  sample_axis = np.hstack((np.zeros(1), np.cumsum(theta)))
                                                  print(sample_axis)


                                                  [0. 0.1 0.35 0.95 1. ]. This represent the cumulative distribution.



                                                  you can use a uniform distribution to draw an index in this unit range.



                                                  def binary_search(axis, q, s, e):
                                                  if e-s <= 1:
                                                  print(s)
                                                  return s
                                                  else:
                                                  m = int( np.around( (s+e)/2 ) )
                                                  if q < axis[m]:
                                                  binary_search(axis, q, s, m)
                                                  else:
                                                  binary_search(axis, q, m, e)



                                                  range_index = np.random.rand(1)
                                                  print(range_index)
                                                  q = range_index
                                                  s = 0
                                                  e = sample_axis.shape[0]-1
                                                  binary_search(sample_axis, q, 0, e)





                                                  share|improve this answer













                                                  Here is the python code even though you ask for java, but it's very similar.



                                                  # weighted probability

                                                  theta = np.array([0.1,0.25,0.6,0.05])
                                                  print(theta)

                                                  sample_axis = np.hstack((np.zeros(1), np.cumsum(theta)))
                                                  print(sample_axis)


                                                  [0. 0.1 0.35 0.95 1. ]. This represent the cumulative distribution.



                                                  you can use a uniform distribution to draw an index in this unit range.



                                                  def binary_search(axis, q, s, e):
                                                  if e-s <= 1:
                                                  print(s)
                                                  return s
                                                  else:
                                                  m = int( np.around( (s+e)/2 ) )
                                                  if q < axis[m]:
                                                  binary_search(axis, q, s, m)
                                                  else:
                                                  binary_search(axis, q, m, e)



                                                  range_index = np.random.rand(1)
                                                  print(range_index)
                                                  q = range_index
                                                  s = 0
                                                  e = sample_axis.shape[0]-1
                                                  binary_search(sample_axis, q, 0, e)






                                                  share|improve this answer












                                                  share|improve this answer



                                                  share|improve this answer










                                                  answered Nov 4 '18 at 16:23









                                                  Albert ChenAlbert Chen

                                                  703611




                                                  703611























                                                      0














                                                      Also responded here: find random country but probability of picking higher population country should be higher. Using TreeMap:



                                                      TreeMap<Integer, Integer> map = new TreeMap<>();
                                                      map.put(percent1, 1);
                                                      map.put(percent1 + percent2, 2);
                                                      // ...

                                                      int random = (new Random()).nextInt(100);
                                                      int result = map.ceilingEntry(random).getValue();





                                                      share|improve this answer




























                                                        0














                                                        Also responded here: find random country but probability of picking higher population country should be higher. Using TreeMap:



                                                        TreeMap<Integer, Integer> map = new TreeMap<>();
                                                        map.put(percent1, 1);
                                                        map.put(percent1 + percent2, 2);
                                                        // ...

                                                        int random = (new Random()).nextInt(100);
                                                        int result = map.ceilingEntry(random).getValue();





                                                        share|improve this answer


























                                                          0












                                                          0








                                                          0







                                                          Also responded here: find random country but probability of picking higher population country should be higher. Using TreeMap:



                                                          TreeMap<Integer, Integer> map = new TreeMap<>();
                                                          map.put(percent1, 1);
                                                          map.put(percent1 + percent2, 2);
                                                          // ...

                                                          int random = (new Random()).nextInt(100);
                                                          int result = map.ceilingEntry(random).getValue();





                                                          share|improve this answer













                                                          Also responded here: find random country but probability of picking higher population country should be higher. Using TreeMap:



                                                          TreeMap<Integer, Integer> map = new TreeMap<>();
                                                          map.put(percent1, 1);
                                                          map.put(percent1 + percent2, 2);
                                                          // ...

                                                          int random = (new Random()).nextInt(100);
                                                          int result = map.ceilingEntry(random).getValue();






                                                          share|improve this answer












                                                          share|improve this answer



                                                          share|improve this answer










                                                          answered Nov 20 '18 at 8:30









                                                          RoberMPRoberMP

                                                          776615




                                                          776615






























                                                              draft saved

                                                              draft discarded




















































                                                              Thanks for contributing an answer to Stack Overflow!


                                                              • Please be sure to answer the question. Provide details and share your research!

                                                              But avoid



                                                              • Asking for help, clarification, or responding to other answers.

                                                              • Making statements based on opinion; back them up with references or personal experience.


                                                              To learn more, see our tips on writing great answers.




                                                              draft saved


                                                              draft discarded














                                                              StackExchange.ready(
                                                              function () {
                                                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f20327958%2frandom-number-with-probabilities%23new-answer', 'question_page');
                                                              }
                                                              );

                                                              Post as a guest















                                                              Required, but never shown





















































                                                              Required, but never shown














                                                              Required, but never shown












                                                              Required, but never shown







                                                              Required, but never shown

































                                                              Required, but never shown














                                                              Required, but never shown












                                                              Required, but never shown







                                                              Required, but never shown







                                                              這個網誌中的熱門文章

                                                              Hercules Kyvelos

                                                              Tangent Lines Diagram Along Smooth Curve

                                                              Yusuf al-Mu'taman ibn Hud