2017-01-11 12 views
0

私は、すでに選択された数字のセットから数字を "一番離れて"与えるように偏った乱数ジェネレータを探しています。例えば、私の範囲が[1、50]で、(1,20,40)のような数字のセットを渡すなら、私はジェネレータが1,20、したがって、50や30などの数字は、20や40よりも描画される可能性が高くなります。これは既に存在する可能性があります。誰もがJavaのために使用できるような実装を知っていますか?バイアスされた乱数ジェネレータ - Java

+0

私はRandomクラスの仕組みを正確にはわかりませんが、実際には貧弱なランダマイザです.JISの週末を見ることができます。それはあなたが探しているものかもしれません。実際のランダム性が必要な場合は、SecureRandomを使用します。 –

+1

これは、http://stackoverflow.com/questions/6737283/weighted-randomness-in-java – samlewis

+0

=/"バイアスされた乱数ジェネレータ"の可能な複製です。そうですね、私たちがここで助けている邪悪な金儲けの仕組みかもしれないと感じています。 :P(jk) –

答えて

1

これは手で行うことができる方法です。基本的には、私たちが生成したくないいくつかの数値を取ってから、乱数を生成し、その数値が数値のリストにあれば、再試行回数を最大にすることをやり直したくありません。

public static void main(String[] args) { 

     int times = 25; 
     int[] listOfNumbers = {1, 2, 3}; 
     int max = 5, min = 1; 

     while(times-- > 0) 
     { 
      System.out.print(GeneratePreferredNumbers(listOfNumbers, max, min) + " "); 
     } 


    }//main method 

    public static Integer GeneratePreferredNumbers(int[] listOfNotPreffered, int max, int min) 
    { 
     Random rand = new Random(); 
     int randomNum; 
     int retry = 1; //increasing this lessons the likely of our non-preferred numbers to show up 
     HashSet<Integer> notPrefer = new HashSet<>(); 

     //add all the numbers we don't want to generate into a HashSet for easy lookup 
     for(int index = 0; index < listOfNotPreffered.length; index++) 
      notPrefer.add(listOfNotPreffered[index]); 

     do { 
      randomNum = rand.nextInt((max - min) + 1) + min; 
      if(notPrefer.contains(randomNum)) 
      { 
       retry--; 
      } 
      //we found a good value, let's return it 
      else{ 
       retry = 0; 
      } 
     } while (retry > 0); 

     return randomNum; 
    } 

出力:

リトライ= 0(単にランダム)

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

リトライ= 1

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

リトライ= 2

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

再試行= 3

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

再試行= 4

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

再試行= 5

4 4 4 4 4 4 4 4 5 5 4 4 5 4 5 4 4 5 4 5 4 5 5 5 5 

注:より多くの回は、私たちは、アルゴリズムは、私たちの出力が構成されます可能性が高く、再試行することができます私たちが望む数のこれにより、これらの非優先番号がどのように表示されるかを制御することができます。再試行回数を無制限に増やすと、生成された数がリストの優先以外の数値に含まれていない場合に限り、これは停止します。

希望すると便利です。

1

あなたはweighted random distributionのように聞こえますが、いくつかの数字は他のものよりも多い可能性があります。

あなたがしなければならない決定は、ランダム分布曲線がどのように見えるか、すなわち選択された数字がいかに積極的に回避されるかです。

新しい番号を選択するときに、回避の持続時間も決める必要があります。例えば。特定のピック数に対して同じ数の避けられた前の数字ですか、または時間の経過とともに消えますか?分布曲線の

enter image description here
enter image description here
enter image description here

最後のものは、40三のピック前だったフェードアウトを示し、1は、2つのピック前であり、20の最終ここで、数字1822(を含む)は、次の選択の確率が0%です。

0

私は少し違う何かをやってしまったし、次のコードが有用であることが判明:

package util.math.random; 

import math.MersenneTwisterFast; 

public class SigmoidBiasedDistribution { 
    private MersenneTwisterFast mtf; 
    private int min; 
    private int max; 
    private double minsigmoidscalefactor; 
    private double maxsidmoidscalefactor; 
    private double maxoffsetfactor; 

public SigmoidBiasedDistribution(int min, int max, double minsigmoidscalefactor, double maxsidmoidscalefactor, double maxoffsetfactor) { 
    this.mtf = new MersenneTwisterFast(); 
    this.minsigmoidscalefactor = minsigmoidscalefactor; 
    this.maxsidmoidscalefactor = maxsidmoidscalefactor; 
    this.maxoffsetfactor = maxoffsetfactor; 
    this.min = min; 
    this.max = max; 
} 

public int[] getPoints(int points) { 
    int[] pts = new int[points]; 
    double lowoffset = mtf.nextDouble(true, true) * maxoffsetfactor; 
    double highoffset = mtf.nextDouble(true, true) * maxoffsetfactor; 
    double randomsigmoidscalefactor = mtf.nextDouble(true, true) * (maxsidmoidscalefactor - minsigmoidscalefactor) + minsigmoidscalefactor; 
    System.out.println(randomsigmoidscalefactor); 
    double pointsoffset = ((1 - highoffset) - lowoffset)/(points - 1); 
    for(int i = 0; i < points; i++) { 
     double offset = (i * pointsoffset) + lowoffset; 
     double scalefactor = getHalfSigmoid(offset, randomsigmoidscalefactor); 
     pts[i] = (int) (scalefactor * (max - min)) + min; 
    } 
    return pts; 
} 

//sigmoid scale factor can range from -1 to 1 (-1 represents most aggressive initial slope, 1 represents least aggressive initial slope, 0 is linear) 
//https://www.desmos.com/calculator/tswgrnoosy 
public double getHalfSigmoid(double value, double sigmoidscalefactor) { 
    return (value - value * sigmoidscalefactor)/(sigmoidscalefactor - 2 * Math.abs(value) * sigmoidscalefactor + 1); 
} 

public static void main(String[] args) { 
    SigmoidBiasedDistribution sbd = new SigmoidBiasedDistribution(5, 80, 5, 0, 0.5, 0.2); 
    int[] pts = sbd.getPoints(3); 
    for(int i = 0; i < pts.length; i++) { 
     System.out.println(pts[i]); 
    } 
} 
} 

基本的にコードがちょうど半分シグモイド曲線にN等距離の点にフィットします。代わりに、私はまた、以下の解決策を書いたが、私は私の目的のために上記の解決策を好む。

package util.math.random; 

import java.util.ArrayList; 
import java.util.List; 

import math.MersenneTwisterFast; 

public class WeightedRandomGenerator { 
    private double sigmoidscalefactor; 
    private MersenneTwisterFast mtf; 
    private List<Integer> points; 
    private int min; 
    private int max; 
    private int numcompletelyrandom; 

public WeightedRandomGenerator(int min, int max, int numcompletelyrandom, double sigmoidscalefactor) { 
    this.mtf = new MersenneTwisterFast(); 
    this.points = new ArrayList<Integer>(); 
    this.numcompletelyrandom = numcompletelyrandom; 
    this.sigmoidscalefactor = sigmoidscalefactor; 
    this.min = min; 
    this.max = max; 
    clear(); 
} 

public int nextInt() { 
    if(points.size() - 2 < numcompletelyrandom) { 
     int nextint = mtf.nextInt(max - min + 1) + min; 
     points.add(nextint); 
     return nextint; 
    } 
    else { 
     int maxsep = getMaxSeparation(); 
     while(true) { 
      int nextint = mtf.nextInt(max - min + 1) + min; 
      int nearestneighbor = getNearestNeighbor(nextint); 
      double sepfrac = (double) nearestneighbor/(double) maxsep; 
      if(mtf.nextBoolean(getHalfSigmoid(sepfrac))) { 
       points.add(nextint); 
       return nextint; 
      } 
     } 
    } 
} 

private int getNearestNeighbor(int nextint) { 
    int delta = Integer.MAX_VALUE; 
    for(int i = 0; i < points.size(); i++) { 
     delta = Math.min(delta, Math.abs(nextint - points.get(i))); 
    } 
    return delta; 
} 

private int getMaxSeparation() { 
    int maxsep = 0; 
    for(int i = 1; i < points.size(); i++) { 
     int delta = points.get(i) - points.get(i-1); 
     maxsep = Math.max(delta, maxsep); 
    } 
    return maxsep; 
} 

private void clear() { 
    points.clear(); 
    points.add(min); 
    points.add(max); 
} 

//sigmoid scale factor can range from -1 to 1 (-1 represents most aggressive initial slope, 1 represents least aggressive initial slope, 0 is linear) 
//https://www.desmos.com/calculator/tswgrnoosy 
public double getHalfSigmoid(double value) { 
    return (value - value * sigmoidscalefactor)/(sigmoidscalefactor - 2 * Math.abs(value) * sigmoidscalefactor + 1); 
} 

public static void main(String[] args) { 
    WeightedRandomGenerator wrg = new WeightedRandomGenerator(1, 80, 2, 0.95); 
    for(int i = 0; i < 5; i++) { 
     System.out.println(wrg.nextInt()); 
    } 
} 
} 
関連する問題