我需要在n
和a
之间生成b
个随机数,但任何两个数字的差异都不能小于c
。除n
之外的所有变量都是浮点数(n
是一个int)。
在java中首选解决方案,但C / C ++也可以。
这是我到目前为止的代码。:
static float getRandomNumberInRange(float min, float max) {
return (float) (min + (Math.random() * (max - min)));
}
static float[] randomNums(float a, float b, float c, int n) {
float minDistance = c;
float maxDistance = (b - a) - (n - 1) * c;
float[] randomNumArray = new float[n];
float random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[0] = a + random;
for (int x = 1; x < n; x++) {
maxDistance = (b - a) - (randomNumArray[x - 1]) - (n - x - 1) * c;
random = getRandomNumberInRange(minDistance, maxDistance);
randomNumArray[x] = randomNumArray[x - 1] + random;
}
return randomNumArray;
}
如果我这样运行这个功能(10次),我得到以下输出:
输入:randomNums(-1f, 1f, 0.1f, 10)
[-0.88, 0.85, 1.23, 1.3784, 1.49, 1.59, 1.69, 1.79, 1.89, 1.99]
[-0.73, -0.40, 0.17, 0.98, 1.47, 1.58, 1.69, 1.79, 1.89, 1.99]
[-0.49, 0.29, 0.54, 0.77, 1.09, 1.56, 1.69, 1.79, 1.89, 1.99]
答案 0 :(得分:8)
我认为合理的方法如下:
(b - a)
(n-1)*c
以获取剩余空间(n-1)
个随机数并对其进行缩放,以便总和就是这个“可选空间”。它们中的每一个都将是一个“切片”的空间。a
c
和下一个“切片”添加到上一个号码。最后一个号码为b
。如果您不希望第一个和最后一个完全匹配a
和b
,那么只需创建n+1
个切片而不是n-1
,然后从a+slice[0]
开始而不是a
。
主要思想是,一旦删除了点之间所需的间距(总计(n-1)*c
),问题就在于找到n-1
值,以便总和是规定的“可选空间”。要使用均匀分布执行此操作,只需拍摄n-1
个数字,计算总和并均匀地缩放这些数字,以便通过将每个数乘以常数因子k = wanted_sum / current_sum
来得到总和。
要获得最终结果,您只需将值与前一个结果用作必需部分c
和其中一个随机采样变量部分的总和。
Python中用于计算所需代码的示例如下
space = b - a
slack = space - (n - 1)*c
slice = [random.random() for i in xrange(n-1)] # Pick (n-1) random numbers 0..1
k = slack / sum(slice) # Compute needed scaling
slice = [x*k for x in slice] # Scale to get slice sizes
result = [a]
for i in xrange(n-1):
result.append(result[-1] + slice[i] + c)
答案 1 :(得分:2)
如果您有随机数X并且您想要另一个随机数Y,其中X的最小值为A,最大值为X,那么为什么不在代码中写出?
float nextRandom(float base, float minDist, float maxDist) {
return base + minDist + (((float)Math.random()) * (maxDist - minDist));
}
通过尝试将基数保留在下一个数字例程之外,会给算法增加很多复杂性。
答案 2 :(得分:1)
虽然这并不能完全按照您的需要进行操作,并且没有包含此线程中描述的技术,但我相信这段代码将证明是有用的,因为它会像您想要的那样。
static float getRandomNumberInRange(float min, float max)
{
return (float) (min + (Math.random() * ((max - min))));
}
static float[] randomNums(float a, float b, float c, int n)
{
float averageDifference=(b-a)/n;
float[] randomNumArray = new float[n];
int random;
randomNumArray[0]=a+averageDifference/2;
for (int x = 1; x < n; x++)
randomNumArray[x]=randomNumArray[x-1]+averageDifference;
for (int x = 0; x < n; x++)
{
random = getRandomNumberInRange(-averageDifference/2, averageDifference/2);
randomNumArray[x]+=random;
}
return randomNumArray;
}
答案 3 :(得分:1)
我需要在a和b之间生成n个随机数,但任何两个数字的差值都不能小于c。除n之外的所有变量都是浮点数(n是int)。
在java中首选解决方案,但C / C ++也可以。
首先,分发?我将假设一个统一的分布,但有一点需要注意“任何两个数字不能有小于c 的差异”。你想要什么被称为“拒绝抽样”。有关于这个主题的维基百科文章,以及关于'网络和书籍(例如http://www.columbia.edu/~ks20/4703-Sigman/4703-07-Notes-ARM.pdf)的大量其他参考文献。伪代码,使用一些函数random_uniform()
返回从U [0,1]中提取的随机数,并假设一个基于1的数组(许多语言使用基于0的数组):
function generate_numbers (a, b, c, n, result)
result[1] = a + (b-a)*random_uniform()
for index from 2 to n
rejected = true
while (rejected)
result[index] = a + (b-a)*random_uniform()
rejected = abs (result[index] < result[index-1]) < c
end
end
答案 4 :(得分:0)
我会通过在a和b之间生成n个随机数来实现这一点。然后我会对它们进行排序并得到第一个顺序差异,踢出任何产生差异小于c的数字,留下m个数字。如果m < n,我会再次这样做,这次是n-m数字,将这些数字添加到我的原始结果中,再次排序,生成差异......依此类推,直到我有n个数字。
注意,一阶差分意味着x [1] - x [0],x [2] - x [1],依此类推。
我没有时间用C写出来,但在R中,这很容易:
getRands<-function(n,a,b,c){ r<-c() while(length(r) < n){ r<-sort(c(r,runif(n,a,b))) r<-r[-(which(diff(r) <= c) + 1 )] } r
}
注意,如果你对c相对于a和b过于强烈,那么这种解决方案可能需要很长时间才能收敛,或者如果n * C&gt;那么根本不收敛。 b -a
另请注意,我并不是说这个R代码是完全形成的,生产准备好的代码片段,只是算法的例证(对于那些可以跟随R的人)。
答案 5 :(得分:0)
你的解决方案几乎是正确的,这是修复:
maxDistance = b - (randomNumArray[x - 1]) - (n - x - 1) * c;
答案 6 :(得分:0)
在生成数字时如何使用移位范围以确保它们看起来不太近?
static float[] randomNums(float min, float max, float separation, int n) {
float rangePerNumber = (max - min) / n;
// Check separation and range are consistent.
assert (rangePerNumber >= separation) : "You have a problem.";
float[] randomNumArray = new float[n];
// Set range for first random number
float lo = min;
float hi = lo + rangePerNumber;
for (int i = 0; i < n; ++i) {
float random = getRandomNumberInRange(lo, hi);
// Shift range for next random number.
lo = random + separation;
hi = lo + rangePerNumber;
randomNumArray[i] = random;
}
return randomNumArray;
}
答案 7 :(得分:0)
我知道你已经接受了答案,但我喜欢这个问题。我希望它是独一无二的,我还没有详细介绍每个人的答案,我需要运行,所以我会发布这个并希望它有所帮助。
按照这种方式思考:一旦你选择了第一个号码,就会有一个你不能再选择的大块+/- c。
所以你的第一个号码是
range1=b-a
x=Random()*range1+a
此时,x介于a和b之间(假设Random()
在0到1之间返回)。现在,我们标出了我们无法再选择的空间
excludedMin=x-c
excludedMax=x+c
如果x接近任何一端,那么很容易,我们只需选择剩余的空间
if (excludedMin<=a)
{
range2=b-excludedMax
y=Random()*range2+excludedMax
}
这里,x非常靠近a,你不会在a和x之间得到y,所以你只需要在x + c和b之间选择。同样地:
else if (excludedMax>=b)
{
range2=excludedMin-a
y=Random()*range2+a
}
现在如果x在中间的某个地方,我们必须做一点魔术
else
{
range2=b-a-2*c
y=Random()*range2+a
if (y>excludedMin) y+=2*c
}
这里发生了什么?好吧,我们知道范围y可以位于,比整个空间小2 * c,所以我们在那个较小的空间中选择一个数字。现在,如果y小于excludedMin,我们知道x“在左边”是x-c,我们都没问题。但是,如果y&gt;排除min,我们会向它添加2 * c(总排除空间),以确保它大于x + c,但它仍然小于b,因为我们的范围减小了。
现在,很容易扩展n个数字,每次你只是通过任何其他点之间的排除空间缩小范围。继续,直到排除的空间等于原始范围(b-a)。
答案 8 :(得分:0)
我知道做第二个答案是不好的形式,但我只想到一个......使用递归搜索空间:
假设全球点数列表:points
FillRandom(a,b,c)
{
range=b-a;
if (range>0)
{
x=Random()*range+a
points.Append(x)
FillRandom(a,x-c,c)
FillRandom(x+c,b,c)
}
}
我会让你跟踪递归,但最后,你会在points
中找到一个用密度1 / c填充空间的列表