Rationals是可枚举的。例如,此代码在开放区间0..1中找到第k个有理数,如果{n1, d1}
假定{n2, d2}
是互质的,则(d1<d2 || (d1==d2 && n1<n2))
的排序为{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}
或者也许有可能有效地生成具有不同“感觉像均匀”分布的有界分母的有理数?
<小时/> 编辑这是Mathematica代码,它运行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]
答案 0 :(得分:6)
我强烈建议您查看The "guess the number" game for arbitrary rational numbers?有关您潜在问题的一些启发。
如果您的目标是尽快大致统一,并且您不介意选择具有不同概率的不同理性,则以下算法应该是有效的。
lower = fractions.Fraction(0)
upper = fractions.Fraction(1)
while lower < upper:
mid = (upper + lower)/2
if 0 == random_bit():
upper = largest_rational_under(mid, denominator_bound)
else:
lower = smallest_rational_over_or_equal(mid, denominator_bound)
请注意,这两个辅助函数都可以通过将Stern-Brocot树走向中间来计算。还要注意,通过一些微小的修改,您可以轻松地将其转换为迭代算法,该算法会吐出一系列有理数,并最终在区间内的任何位置以相等的可能性收敛。我认为这个属性很好。
如果您想要最初指定的确切分布,并且rand(n)
为您提供从1
到n
的随机整数,则以下伪代码将用于分母绑定{{1 }}:
n
对于大Try:
k = rand(n * (n+1) / 2)
do binary search for largest j with j * (j-1) / 2 < k
i = k - (j * (j-1) / 2)
if (i, j) are not relatively prime:
redo Try
answer = i/j
平均而言,您必须n
约2.55次。所以在实践中这应该非常有效。
答案 1 :(得分:2)
在分母上有一个界限,理性分布不均匀(例如,1/2与其他所有东西分开了一个很好的差距。
那说,就像
In[300]:= Rationalize[RandomReal[1, 10], 0.001]
Out[300]= {17/59, 45/68, 11/31, 9/16, 1/17, 13/22, 7/10, 1/17, 5/21, 8/39}
为你工作?
答案 2 :(得分:1)
以下是您提出的问题的随机想法。我没有仔细检查数学,所以我可以在这里或那里离开1。但它代表了我会遵循的那种推理。
我们只考虑区间(0,1)中的分数。这种方式更容易。我们可以稍后处理1/1和不正确的分数。
Stern - Brocot Tree唯一地按顺序列出每个减少的正公共分数(因此每个正有理数小于或等于1),并且以简化形式,作为树中的节点。在这个二叉树中,任何节点以及任何分数都可以通过从最上层开始的左右转弯的有限序列到达(为方便起见,称之为-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的分数。
我不知道数字生成是真正随机的。我甚至都不知道怎么说。但是对于它的结果,我没有发现任何明显的偏见来源。