4

古典的な範囲ランダム関数は次のようになっています。

public static final int random(final int min, final int max) {
    Random rand = new Random();
    return min + rand.nextInt(max - min + 1);  // +1 for including the max
}

1..10の範囲でランダムに数値を生成するアルゴリズム関数を作成したいのですが、次のような不均一な可能性があります:
1)1,2,3-> 3/6(1/2)
2)4,5,6,7 -> 1/6
3)8,9,10-> 2/6(1/3)

上記は、関数が1から3までの数値を返す可能性が1/2、4から7までの数値を返す可能性が1/6、8から10までの数値を返す可能性が1/3であることを意味します。

誰もがアルゴリズムを知っていますか?

更新:
実際には、1..10の間の範囲は単なる例として提供されています。私が作成したい関数は、1..10000などの任意の範囲の数値に適用されますが、ルールは同じです。トップレンジ(30%の部分)の場合は3/6、ミドルレンジ(次の部分)の場合は1/6です。 40%の部分)、およびボトムレンジの2/6(最後の30%の部分)。

4

6 に答える 6

6

アルゴリズムを使用します。

int temp = random(0,5);
if (temp <= 2) {
  return random(1,3);
} else if (temp <= 3) {
 return random(4,7);
} else  {
 return random(8,10);
}

これでうまくいくはずです。

編集:あなたのコメントで要求されたように:

int first_lo = 1, first_hi = 3000; // 1/2 chance to choose a number in [first_lo, first_hi]
int second_lo = 3001, second_hi = 7000; // 1/6 chance to choose a number in [second_lo, second_hi] 
int third_lo = 7001, third_hi = 10000;// 1/3 chance to choose a number in [third_lo, third_hi] 
int second
int temp = random(0,5);
if (temp <= 2) {
  return random(first_lo,first_hi);
} else if (temp <= 3) {
 return random(second_lo,second_hi);
} else  {
 return random(third_lo,third_hi);
}
于 2012-04-26T09:20:33.307 に答える
3

目的の数値の配列を目的の密度で埋めてから、ランダムインデックスを生成し、対応する要素を取得できます。少し速いと思いますが、それほど重要ではないでしょう。そのようなもの、それは正しい解決策ではなく、単なる例です:

1,1,1,2,2,2,3,3,3,4,5,6 ...

または、最初にifステートメントを使用してドメインを定義してから、そのドメインから単純な番号を生成することもできます。

int x = random(1,6)
if (x < 4) return random(1, 3);
if (x < 5) return random(4, 7);
return random(8, 10);
于 2012-04-26T09:24:50.223 に答える
2

次の配列から選択するには、72面のサイコロを振ります。

// Each row represents 1/6 of the space
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7,
 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9,
 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10]
于 2012-04-26T09:27:55.573 に答える
0
final int lut[] = [
  1, 1, 1,
  2, 2, 2,
  3, 3, 3,
  4,
  5,
  6,
  7,
  8, 8,
  9, 9,
  10, 10
];

int uneven_random = lut[random.nextInt(lut.length)];

またはそれらの線に沿った何か...

于 2012-04-26T09:26:53.773 に答える
0

これは、整数を使用している場合に役立つ可能性があります。

次の関数を使用する必要があります。

f : A -> B

B = [b0、b1]は、乱数ジェネレーターから必要な値の範囲を表します

A = [b0、2 * b1]であるため、fの最後のブランチは実際にb1に到達します。

f(x) = step((x / 3) , 
    f(x) is part of interval [b0, length(B)/3]
f(x) = step(x)  + E,   
    f(x) is part of interval [length(B) / 3, 2 * length(B) / 3],
    E is a constant that makes sure the function is continuous
f(x) = step(x / 2) + F,   
    f(x) is part of interval [2 * length(B) / 3, length(B)]
    F is a constant that makes sure the function is continuous

説明:最初のブランチで同じ値を取得するには、2番目のブランチの3倍の数値が必要です。したがって、最初のブランチで数値を取得する確率は、2番目のブランチの3倍であり、値は乱数ジェネレーターから均等に分散されます。同じことが3番目のブランチにも当てはまります。

これがお役に立てば幸いです。

編集:間隔を変更しました。少し調整する必要がありますが、これは私の一般的な考え方です。

于 2012-04-26T11:51:57.100 に答える
0

要求に応じて、これが私の問題をうまく解決する私のコード(izomorphiusのコードに基づく)です:

private static Random rand = new Random();

public static int rangeRandom(final int min, final int max) {
    return min + rand.nextInt(max - min + 1);  // +1 for including the max
}

/**
 * 
 * @param min           The minimum range number
 * @param max           The maximum range number
 * @param weights       Array containing distributed weight values. The sum of values must be 1.0 
 * @param chances       Array containing distributed chance values. The array length must be same with weights and the sum of values must be 1.0 
 * @return              Random number
 * @throws Exception    Probably should create own exception, but I use default Exception for simplicity
 */
public static int weightedRangeRandom(final int min, final int max, final float[] weights, final float[] chances) throws Exception {
    // some validations
    if (weights.length != chances.length) {
        throw new Exception("Length of weight & chance must be equal");
    }

    int len = weights.length;

    float sumWeight = 0, sumChance = 0;
    for (int i=0; i<len; ++i) {
        sumWeight += weights[i];
        sumChance += chances[i];
    }
    if (sumWeight != 1.0 || sumChance != 1.0) {
        throw new Exception("Sum of weight/chance must be 1.0");
    }

    // find the random number
    int tMin = min, tMax;
    int rangeLen = max - min + 1;

    double n = Math.random();
    float c = 0;
    for (int i=0; i<len; ++i) {
        if (i != (len-1)) {
            tMax = tMin + Math.round(weights[i] * rangeLen) - 1;
        }
        else {
            tMax = max;
        }

        c += chances[i];
        if (n < c) {
            return rangeRandom(tMin, tMax);
        }
        tMin = tMax + 1;
    }

    throw new Exception("You shouldn't end up here, something got to be wrong!");
}

使用例:

int result = weightedRangeRandom(1, 10, new float[] {0.3f, 0.4f, 0.3f}, 
    new float[] {1f/2, 1f/6, 1f/3});

重みで除算すると10進値になるため、コードにはサブレンジ境界(tMinおよびtMax)の分散が依然として不正確である可能性があります。しかし、範囲番号は整数であるため、避けられないと思います。

いくつかの入力検証が必要になる場合がありますが、簡単にするために省略しました。

批評家、訂正、レビューは大歓迎です:)

于 2012-04-27T10:19:24.897 に答える