我能够在0到25的范围内生成三个随机整数。但是我必须确定这三个整数应该总是具有不同的值,即i != j
,j != k
,k != i
。我已经制作了以下代码,但我担心它不会满足条件,也可能导致无限循环条件。
int i = ts_rint (25); int j = ts_rint (25); int k = ts_rint (25);
while ( k == i)
{
k = ts_rint (25);
while ( i == j )
{
i = ts_rint (25);
while ( j == k )
{
j = ts_rint (25);
}
}
}
我正在使用TScope
这是一个C库来创建认知实验。您可以查看here以查看ts_rint(int nMax)
。
我的代码在此条件下失败了:
原文:i = 9 j = 9 k = 11
While While循环i:9 j:9 k:11
所以,这个while循环系统非常容易失败。
答案 0 :(得分:3)
这称为拒绝抽样。对于以下情况,这是一个很好的解决方案:
这个循环在理论上确实是无界限的,但是,在大多数情况下实际上,这不会是一个问题。
没有必要重新取样所有三个数字。你可以用这个:
int i = ts_rint(25), j, k;
do j = ts_rint(25); while (i == j);
do k = ts_rint(25); while (k ==i || k == j);
在这种情况下,我们只拒绝部分样本。 (样本是数字的三重组合。我们一次只拒绝一个。)在这种情况下有效。然而,随着更复杂的概率分布,有必要确保算法的结构产生所需的分布。
编辑:正如其他答案所指出的那样,有一些方法可以生成所需的三元组而不会出现循环。 (因此,违反了上述第三个标准;拒绝采样通常不应用于此问题。)但是,正如其他答案和众多编辑所证明的那样,它们似乎容易出错。所以仔细检查一下代码。
现在其他答案已经有所缓和,我决定玩得开心。让我们直接按升序生成三个数字(不带任何分支)。我们可以使用以下代码执行此操作:
int p = ts_rint(25*24*23/6);
complex double t =
cpow(372600 - 324*p + 3*csqrt(11664.*p*p-26827200.*p-80590467), 1/3.);
int j = (50 - t/3 - 1729/t - csqrt(-3)*(t/3-1729/t))/4 + 0x1p-20;
int r = p - (69*j - 79 - 2*j*j) * j / 6;
int i = r%j;
int k = r/j;
不幸的是,我现在没时间了,所以详细解释将等待另一天。简而言之,我们将样本编号从0到2299(2300个样本,25•24•23/6)。我们知道 j •( n - j -1)样本有 j 作为它们的中间值(因为有 j 可用于第一个值的较低数字和 n - j -1可用于第三个值的较高数字)。然后我们求和,以确定有多少样本的中间值小于或等于特定的 j 。然后我们将该总和设置为等于样本数,并将 j 求解为样本数的函数。这允许我们从ts_rint(25*24*23/6)
的结果直接确定 j 。找到 j 后, i 和 k 就会轻松跟进。有趣的部分是sum是一个三次多项式,因此它的解决方案使用复杂的算法。
代替进一步推导,这是一个证明正确性的程序:
#include <complex.h>
#include <math.h>
#include <stdio.h>
#define N 25
int main(void)
{
int A[N][N][N] = {{{0}}};
// First, mark each of the 2300 results we ought to find.
for (int i = 0; i < N; ++i)
for (int j = i+1; j < N; ++j)
for (int k = j+1; k < N; ++k)
++A[i][j][k];
/* Next, iterate through each value that ts_rint(25*24*23/6) might return,
generate a triple for each value, and test for whether we generate each
required triple exactly once.
*/
for (int p = 0; p < 25*24*23/6; ++p)
{
complex double t =
cpow(372600 - 324*p + 3*csqrt(11664.*p*p-26827200.*p-80590467), 1/3.);
int j = (50 - t/3 - 1729/t - csqrt(-3)*(t/3-1729/t))/4 + 0x1p-20;
int r = p - (69*j - 79 - 2*j*j) * j / 6;
int i = r%j;
int k = r/j;
/* Given triple (i, j, k), is it one we are supposed to generate, and
have we not seen it before?
*/
if (A[i][j][k] != 1)
{
printf("Error, A[%d][%d][%d] = %d, p = %d.\n",
i, j, k, A[i][j][k], p);
return 1;
}
A[i][j][k] = 0;
}
return 0;
}
答案 1 :(得分:3)
您的代码有效。
作为替代方案,您可以使用:
int i = ts_rint(25);
int j = ts_rint(24);
int k = ts_rint(23);
j += j >= i;
k += k >= std::min(i, j);
k += k >= std::max(i, j);
答案 2 :(得分:1)
如果你真的只需要3个随机整数,你可以这样做:
k = rint (25);
// only 24 values remaining for i
i = rint (24);
// remap k to 24
if (i == k)
i = 24;
// only 23 values remaining for j
j = rint (23);
// remap k to 25 (or 24 if it's taken)
if (j == k)
j = (i == 24) ? 23 : 24;
// remap i to 24
else if (j == i)
j = (k == 24) ? 23 : 24;
如果您需要将其缩放到更多值,最好创建一个包含所有可能值的向量,并在随机选择时从中删除值。
答案 3 :(得分:1)
我想解释如何有三个随机数而没有它们可以相等的可能性,我不会给出任何代码; 你需要从没有前一个数字的0到25区间生成随机数,例如:当你生成i时你需要从0到25的间隔中提取k (抱歉英语不好)
答案 4 :(得分:1)
int k = rint(25 * 24 * 23);
int i = k / (24 * 23);
k %= 24 * 23;
int j = k / 23;
k %= 23;
if (j >= i)
{
++j;
if (k >= i)
++k;
if (k >= j)
++k;
}
else
{
if (k >= j)
++k;
if (k >= i)
++k;
}
答案 5 :(得分:1)
修改:此解决方案有误,需要进一步改进,请参阅下面的评论。
没有循环的简单解决方案:
srand(time(0));
int i = rand() % 25;
int j = rand() % 25;
int k = rand() % 25;
if (i == j) j++;
if (i == k) k++;
if (j == k) k++;
(对不起rand()
,这只是为了简洁起见)
答案 6 :(得分:1)
您是否考虑过将您的解决方案基于Fisher-Yates shuffle?以下在O(k)时间内生成k元组,并保证具有相同概率被选择的所有元素的不同结果。如果你需要生成多个k元组,则不需要重新初始化数组 - 改组不依赖于初始排序来产生均匀分布的结果。
#include <stdlib.h>
#include <stdio.h>
#define NUM_VALUES 26
static int values[NUM_VALUES] =
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};
void generate(int n) {
for(int i = NUM_VALUES - 1; i > NUM_VALUES - (n + 1); --i) {
int j = arc4random_uniform(i+1);
if (i != j) {
int tmp = values[i];
values[i] = values[j];
values[j] = tmp;
}
printf("%d ", values[i]);
}
printf("\n");
}
int main(void) {
for(int i = 0; i < 100000; ++i) {
generate(3);
}
}
这可能会变得更干净,我的C生锈了。我的编译器似乎没有ts_rint()
所以我使用arc4random_uniform()
代替,但我认为这是替换它的简单替代。
答案 7 :(得分:0)
编辑:这是一个错误的答案,在运气不好的情况下无法产生正确的结果
int i, j, k;
i = ts_rint( 25 ); /* casually get a random number with 1/26 probability */
/* you're done with the i */
j = ts_rint( 24 ); /* get a random number with 1/25 probability */
/* now, this number has the right probability, */
/* but it was not to be picked from [0, 24] */
/* rather from [0, 25] \ { i } or in other words */
/* [0, i - 1] union [i + 1, 25], so... */
if ( j >= i ) j++; /* <<< this will achieve that */
k = ts_rint( 23 ); /* same story, two fold */
if ( k >= i ) k++;
if ( k >= j ) k++;
然后,所有的解释都作为评论给出。
编辑:从k >= i
到k >= j
的最后一行不正确