Bottom-Heavy Random Number

java

Solution

Use `Random.nextDouble()` to generate a number in [0,1), then you can use `Math.pow()` to give it a non-linear bias and scale it up to cover your range, e.g.:

 int randomBiased (int max, float bias) {
     float v = Math.pow(random.nextDouble(), bias); 
     return (int)(v * max);
 }

Or if you prefer a one-liner:

 int value = (int)(100 * Math.pow(random.nextDouble(), bias));

This is useful because you can adjust `bias` to tweak the "rareness" of rarer items. A bias > 1 will favor lower numbers, < 1 will favor higher numbers, 1 will be uniform.

For example, `randomBiased(100, 2.0)` will give the same result distribution as Tim B's answer.

Note also that you can use any function that maps [0,1) to [0,1) to modify the bias; for example, you could use a cubic to bias all results away from the center (see the graph):

int randomFavorEdges (int max) {
    float v = random.nextDouble();
    v = 3*v*v - 2*v*v*v;
    return (int)(v * max);
}

Another example is that you can get one half of a Gaussian distribution using `Math.abs(random.nextGaussian())` instead (see Christian's answer). The caveat is you have to keep trying that until you get a number less than 1 (it can go outside the range [-1,1]). However, you can take advantage of the large range by adding a scaling parameter that can be tweaked to taste:

int randomGaussian (int max, float scale) { 
    double v;
    do {
        v = Math.abs(random.nextGaussian() / scale);
    } while (v >= 1.0);
    return (int)(v * max);
}

Truth be told, after looking at the test results below, personally I like the Gaussian distributions with a higher scale value -- rare items become much rarer but without as intense a bias towards common items as the exponential distribution.

Update: I've created a project on ideone that demonstrates the methods listed above. Here is an example for 10000 samples of 30 values:

Name :  Uniform  Pow(0.5)  Pow(2.0) Pow(10.0)    G(1.0)    G(3.5)     Cubic 
0    :      337        11      1872      7118       365       946      1126 
1    :      359        33       744       511       406       939       517 
2    :      327        60       589       328       360       876       407 
3    :      330       101       458       224       370       846       307 
4    :      347       103       445       170       395       817       310 
5    :      344       131       366       141       374       727       257 
6    :      326       148       358       147       416       691       275 
7    :      326       180       309       106       373       645       254 
8    :      314       195       295       129       335       575       282 
9    :      331       227       311        79       356       506       219 
10   :      329       245       325        84       376       458       258 
11   :      340       241       230        75       370       366       228 
12   :      367       290       251        75       366       320       215 
13   :      343       294       264        70       345       243       237 
14   :      313       317       256        60       344       211       224 
15   :      346       331       240        66       358       186       210 
16   :      353       363       204        48       338       131       226 
17   :      329       373       213        55       344       157       193 
18   :      323       417       200        57       327        86       230 
19   :      323       446       219        56       354        75       208 
20   :      321       466       211        43       296        56       209 
21   :      339       496       205        40       297        34       267 
22   :      338       484       192        48       278        37       237 
23   :      335       523       168        46       290        19       306 
24   :      327       571       162        31       251        18       279 
25   :      322       573       216        49       263         7       302 
26   :      323       580       152        35       277        11       311 
27   :      333       596       209        41       268         9       354 
28   :      316       590       158        38       250         6       495 
29   :      339       615       178        30       258         2      1057 

Note that you can really make rare objects rare with high bias value for the `Math.pow()` method or a high scale value for the Gaussian method. This also shows the bias of the cubic S-curve away from the center.

Problem

Right now, I'm trying to make an Item drop table for a minigame. In this game, I would like for you to receive certain items more commonly than others, with some items having a very low chance of being picked. I have tried using something along the lines of: ``` Random rand = new Random(); int chance = rand.nextInt(100) + 1; if(chance > 2){ //give common item; } else if(chance == 1){ //give rare item } ``` However, when you do this over a scale of 50+ items, it becomes very tedious to create, modify, as well as the code takes a long time to execute. So, is there some kind of bottom-heavy random that will create a large amount of low numbers (1's, 2's, etc.) and very few high numbers (50's, 60's, etc.)?

Original source