有理数是可数的。例如,此代码在开区间 0..1 中查找第 k 个有理数,如果 ,则 {n1, d1}
位于 {n2, d2}
之前(d1 假设 {n,d}
是互质的。
RankedRational[i_Integer?Positive] :=
Module[{sum = 0, eph = 1, den = 1},
While[sum < i, sum += (eph = EulerPhi[++den])];
Select[Range[den - 1], CoprimeQ[#, den] &][[i - (sum - eph)]]/den
]
In[118]:= Table[RankedRational[i], {i, 1, 11}]
Out[118]= {1/2, 1/3, 2/3, 1/4, 3/4, 1/5, 2/5, 3/5, 4/5, 1/6, 5/6}
现在我想生成随机有理数,给定分母上界,均匀地排序,以便对于足够大的分母有理数将在单位区间上均匀分布。
直观上,我们可以在具有相同权重的小分母的所有有理数中进行选择:
RandomRational1[maxden_, len_] :=
RandomChoice[(Table[
i/j, {j, 2, maxden}, {i,
Select[Range[j - 1], CoprimeQ[#, j] &]}] // Flatten), len]
是否可以更有效地生成具有这种分布的随机有理数,而不需要构造所有有理数?这张桌子不需要太多就能变得很大。
In[197]:= Table[RankedRational[10^k] // Denominator, {k, 2, 10}]
Out[197]= {18, 58, 181, 573, 1814, 5736, 18138, 57357, 181380}
或者也许可以有效地生成具有不同“感觉均匀”分布的有界分母的有理数?
EDIT This is Mathematica code which runs acceptance-rejection generation suggested by btilly.
Clear[RandomFarey];
RandomFarey[n_, len_] := Module[{pairs, dim = 0, res, gcds},
Join @@ Reap[While[dim < len,
gcds = cfGCD[pairs = cfPairs[n, len - dim]];
pairs = Pick[pairs, gcds, 1];
If[pairs =!= {},
dim += Length@Sow[res = pairs[[All, 1]]/pairs[[All, 2]]]];
]][[2, -1]]
]
以下编译函数生成整数对 {i,j}
,使得 1<=i j<=n
:
cfPairs =
Compile[{{n, _Integer}, {len, _Integer}},
Table[{i, RandomInteger[{i + 1, n}]}, {i,
RandomChoice[2 (n - Range[n - 1])/(n (n - 1.0)) -> Range[n - 1],
len]}]];
以下编译函数计算 gcd。它假设输入是一对正整数。
cfGCD = Compile[{{prs, _Integer, 1}}, Module[{a, b, p, q, mod},
a = prs[[1]]; b = prs[[2]]; p = Max[a, b]; q = Min[a, b];
While[q > 0, mod = Mod[p, q]; p = q; q = mod]; p],
RuntimeAttributes -> Listable];
然后
In[151]:= data = RandomFarey[12, 10^6]; // AbsoluteTiming
Out[151]= {1.5423084, Null}
In[152]:= cdf = CDF[EmpiricalDistribution[data], x];
In[153]:= Plot[{cdf, x}, {x, 0, 1}, ImageSize -> 300]
Rationals are enumerable. For example this code finds k-th rational in open interval 0..1, with ordering that {n1, d1}
is before {n2, d2}
if (d1<d2 || (d1==d2 && n1<n2))
assuming {n,d}
is coprime.
RankedRational[i_Integer?Positive] :=
Module[{sum = 0, eph = 1, den = 1},
While[sum < i, sum += (eph = EulerPhi[++den])];
Select[Range[den - 1], CoprimeQ[#, den] &][[i - (sum - eph)]]/den
]
In[118]:= Table[RankedRational[i], {i, 1, 11}]
Out[118]= {1/2, 1/3, 2/3, 1/4, 3/4, 1/5, 2/5, 3/5, 4/5, 1/6, 5/6}
Now I would like to generate random rationals, given an upper bound on the denominator sort-of uniformly, so that for large enough denominator rationals will be uniformly distributed over the unit interval.
Intuitively, one could pick among all rationals with small denominators with equal weights:
RandomRational1[maxden_, len_] :=
RandomChoice[(Table[
i/j, {j, 2, maxden}, {i,
Select[Range[j - 1], CoprimeQ[#, j] &]}] // Flatten), len]
Can one generate random rationals with this distribution more efficiently, without constructing all of them ? It does not take much for this table to become huge.
In[197]:= Table[RankedRational[10^k] // Denominator, {k, 2, 10}]
Out[197]= {18, 58, 181, 573, 1814, 5736, 18138, 57357, 181380}
Or maybe it is possible to efficiently generate rationals with bounded denominator having a different "feels-like-uniform" distribution ?
EDIT This is Mathematica code which runs acceptance-rejection generation suggested by btilly.
Clear[RandomFarey];
RandomFarey[n_, len_] := Module[{pairs, dim = 0, res, gcds},
Join @@ Reap[While[dim < len,
gcds = cfGCD[pairs = cfPairs[n, len - dim]];
pairs = Pick[pairs, gcds, 1];
If[pairs =!= {},
dim += Length@Sow[res = pairs[[All, 1]]/pairs[[All, 2]]]];
]][[2, -1]]
]
The following compiled function generations pairs of integers {i,j}
such that 1<=i < j<=n
:
cfPairs =
Compile[{{n, _Integer}, {len, _Integer}},
Table[{i, RandomInteger[{i + 1, n}]}, {i,
RandomChoice[2 (n - Range[n - 1])/(n (n - 1.0)) -> Range[n - 1],
len]}]];
and the following compiled function computes gcd. It assumes the input is a pair of positive integers.
cfGCD = Compile[{{prs, _Integer, 1}}, Module[{a, b, p, q, mod},
a = prs[[1]]; b = prs[[2]]; p = Max[a, b]; q = Min[a, b];
While[q > 0, mod = Mod[p, q]; p = q; q = mod]; p],
RuntimeAttributes -> Listable];
Then
In[151]:= data = RandomFarey[12, 10^6]; // AbsoluteTiming
Out[151]= {1.5423084, Null}
In[152]:= cdf = CDF[EmpiricalDistribution[data], x];
In[153]:= Plot[{cdf, x}, {x, 0, 1}, ImageSize -> 300]
发布评论
评论(3)
我强烈建议查看任意的“猜数字”游戏有理数? 以获得有关您的根本问题的一些灵感。
如果您的目标是尽快达到大致均匀,并且您不介意选择具有不同概率的不同有理数,则以下算法应该是有效的。
请注意,这两个辅助函数都可以通过将 Stern-Brocot 树向中间移动来计算。另请注意,通过一些细微的修改,您可以轻松地将其转换为迭代算法,该算法输出一系列有理数,并最终以相等的可能性在区间内的任何位置收敛。我认为那处房产还不错。
如果您想要最初指定的精确分布,并且
rand(n)
为您提供从1
到n
的随机整数,则以下代码伪代码适用于分母绑定的n
:平均而言,对于较大的
n
,您需要尝试
大约 2.55 次。所以在实践中这应该是非常有效的。I strongly suggest looking at The "guess the number" game for arbitrary rational numbers? for some inspiration about your underlying problem.
If your goal is to be approximately uniform ASAP, and you don't mind picking different rationals with different probabilities, the following algorithm should be efficient.
Note that both of those two helper functions can be calculated by walking the Stern-Brocot Tree towards the mid. Also note that, with some minor modification, you can easily transform this into an iterative algorithm that spits out a sequence of rational numbers, and eventually will converge with equal likelihood anywhere in the interval. I consider that property to be kind of nice.
If you want the exact distribution that you originally specified, and
rand(n)
gives you a random integer from1
ton
, then the following pseudocode will work for denominator boundn
:On average for large
n
you'll have toTry
about 2.55 times. So in practice this should be pretty efficient.由于分母有界,有理数不是均匀分布的(例如,1/2 与其他所有值之间有一个很好的间隙)。
也就是说,类似的东西
对你有用吗?
With a bound on the denominator, the rationals aren't uniformly distributed (1/2 gets separated from everything else by a nice gap, for example.
That said, would something like
work for you?
以下是对您提出的问题的一些随机想法。我没有仔细检查数学,所以我可能会在这里或那里落后 1。但这代表了我会遵循的推理。
我们只考虑区间 (0,1) 中的分数。这样就容易多了。稍后我们可以处理 1/1 和假分数。
Stern - Brocot Tree 唯一地列出了每个约简正公分式(以及每个正有理数)小于或等于一)一次,按顺序并以简化形式作为树中的节点。在这个二叉树中,任何节点以及任何分数都可以通过从最上层(为方便起见,我们将其称为层 -1)开始的有限序列的左右转弯来到达,其中包含 0/1 和 1/0。 [是的,1/0。这不是印刷错误!]
给定分母 k,您最多需要转 k 圈才能达到任何约简分数 j/k,其中 j 小于 k。例如,如果分母为 101,则分母为 101 或以下的所有可能分数将位于树中第 1 级(包含 1/1)和第 101 级(最左边位置包含 1/101)之间的某个位置。
假设我们有一个生成 0 和 1 的数字生成器。 (请不要问我该怎么做;我不知道。)Lef 任意决定 Left=0 和 Right=1。
假设我们有另一个数字生成器,可以随机生成 1 到 n 之间的整数。进一步假设生成的第一个数字是0,即。向左转:这保证分数落在区间 (0,1) 内。
选择最大分母 k。随机生成一个介于 1 和 k 之间的数字 m。然后生成 R 和 L 的随机列表。按照转弯列表遍历(即下降)Stern-Brocot 树。当您到达目的地部分时停止。
如果该分数的分母等于或小于 k,停止,这就是您的数字。
如果分母大于 k,则沿树上升(沿着下降的同一路径),直到到达分母不大于 k 的分数。
我不知道数字的生成是否真的是随机的。我什至不知道该怎么说。但就其价值而言,我没有发现任何明显的偏见来源。
Here are some random thoughts on the problem you raise. I haven't carefully checked the math so I could be off by 1 here or there. But it represents the sort of reasoning I would follow.
Let's only consider fractions in the interval (0,1). It's much easier that way. We can deal later with 1/1 and improper fractions.
The Stern - Brocot Tree uniquely lists each reduced positive common fraction (and hence each positive rational number less than or equal to one) once, in order, and in reduced form, as a node in the tree. In this binary tree, any node and thus any fraction can be reached by a finite sequence of left-right turns starting from the uppermost level (for convenience let's call it level -1), containing 0/1 and 1/0. [Yes, 1/0. That's not a misprint!]
Given a denominator, k, you would need to take at most k turns to reach any reduced fraction j/k, where j is less than k. For example, if the denominator were 101, all possible fractions with a denominator of 101 or less will be in the tree somewhere between Level 1 (containing 1/1) and Level 101 (containing 1/101 in the leftmost position).
Let's assume we have a number generator that generate 0's and 1's. (Please don't ask me how to do that; I have no idea.) Lef's arbitrarily decide that Left=0 and Right=1.
Assume that we have another number generator that can randomly generate integers between 1 and n. Assume further that the first number generated is 0, ie. turn left: this guarantees that the fraction will fall in the interval (0,1).
Select the maximum denominator, k. Randomly generate a number, m, between 1 and k. Then generate a random list of R's and L's. Traverse (i.e. descend) the Stern-Brocot tree, following the list of turns. Stop when you reach the destination fraction.
If that fraction has a denominator equal to or less than k, stop, that's your number.
If the denominator is greater than k, ascend the tree (along the same path you descended) until you reach a fraction with a denominator no greater than k.
I don't know that the number generation is truly random. I wouldn't even know how to tell. But for what it's worthe, I don't detect any obvious source of bias.