有偏随机数生成器-Java
我正在寻找一个随机数生成器,它倾向于从一组已经选择的数字中给出“最远”的数字。例如,如果我的范围是[1,50],并且我传入一组数字,例如(1,20,40),那么我希望生成器“更喜欢”生成远离1,20和40的数字。因此,像50或30这样的数字比20或40更可能被抽取。我怀疑这可能已经存在。有人知道这样一个我可以用于Java的实现吗?听起来你想要一个,其中一些数字比其他数字更可能 你必须做出的决定是,随机分布曲线应该是什么样子的,也就是说,选择的数字避免的力度有多大 当你选择新号码时,你还需要决定这种回避会持续多久。例如,对于特定数量的拣选,先前的数字是否被同等地避免,还是会随着时间的推移逐渐消失 分布曲线示例有偏随机数生成器-Java,java,random,Java,Random,我正在寻找一个随机数生成器,它倾向于从一组已经选择的数字中给出“最远”的数字。例如,如果我的范围是[1,50],并且我传入一组数字,例如(1,20,40),那么我希望生成器“更喜欢”生成远离1,20和40的数字。因此,像50或30这样的数字比20或40更可能被抽取。我怀疑这可能已经存在。有人知道这样一个我可以用于Java的实现吗?听起来你想要一个,其中一些数字比其他数字更可能 你必须做出的决定是,随机分布曲线应该是什么样子的,也就是说,选择的数字避免的力度有多大 当你选择新号码时,你还需要决定这
最后一个显示淡出,其中
40
是三个选择之前,1
是两个选择之前,20
是最后一个选择,其中数字18
到22
(含)下一个选择的概率为0%。听起来像是你想要一个选择,其中一些数字比其他数字更可能
你必须做出的决定是,随机分布曲线应该是什么样子的,也就是说,选择的数字避免的力度有多大
当你选择新号码时,你还需要决定这种回避会持续多久。例如,对于特定数量的拣选,先前的数字是否被同等地避免,还是会随着时间的推移逐渐消失
分布曲线示例
最后一个显示淡出,其中
40
是三个选择之前,1
是两个选择之前,20
是最后一个选择,其中数字18
到22
(含)下一个选择的概率为0%。以下是一种手动操作的方法。基本上,我们的想法是,我们接收一些我们不想生成的数字,然后我们生成一个随机数,如果这个数字在我们不想生成的数字列表中,我们将重试一次,最多重试一次
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;
}
重试=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
注意:我们允许算法重试的次数越多,我们的输出就越可能包含我们想要的数字。这允许您控制希望这些非首选号码出现的可能性。这是有意义的,因为如果我们将重试次数增加到无穷大,那么只有当生成的号码不包含在非首选号码列表中时,重试才会停止
希望这有帮助 这里有一种方法可以手工完成。基本上,我们的想法是,我们接收一些我们不想生成的数字,然后我们生成一个随机数,如果这个数字在我们不想生成的数字列表中,我们将重试一次,最多重试一次
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;
}
重试=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
注意:我们允许算法重试的次数越多,我们的输出就越可能包含我们想要的数字。这允许您控制希望这些非首选号码出现的可能性。这是有意义的,因为如果我们将重试次数增加到无穷大,那么只有当生成的号码不包含在非首选号码列表中时,重试才会停止
希望这有帮助 我最终做了一些不同的事情,发现以下代码很有用:
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]);
}
}
}
package util.math.random;
导入math.MersenneTwisterFast;
公共类SigmoidBiasedDistribution{
私人梅森快速mtf;
私用int min;
私人int max;
私有双指数指数因子;
专用双maxsidmoidscalefactor;
私人双maxoffsetfactor;
公共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;
}
公共整数[]获取点数(整数点数){
int[]pts=新的int[点];
双低偏移=mtf.nextDouble(真,真)*最大偏移系数;
double highoffset=mtf.nextDouble(真,真)*maxoffsetfactor;
双随机SigmoidScaleFactor=mtf.nextDouble(真,真)*(maxsidmoidscalefactor-minsigmoidscalefactor)+minsigmoidscalefactor;
System.out.println(随机SigmoidScaleFactor);
双点OFSET=((1-高偏移)-低偏移)/(点-1);
对于(int i=0;i
基本上,代码只是将N个等距点拟合到半S形曲线上。或者,我也写了下面的解决方案,但出于我的目的,我更喜欢上面的解决方案
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());
}
}
}
package util.math.random;
导入java.util.ArrayList;
导入java.util.List;
导入math.MersenneTwisterFast;
公共类围板