Math 随机有理数生成
理性是可以列举的。例如,此代码在开放区间0..1中找到第k个有理数,排序为Math 随机有理数生成,math,random,wolfram-mathematica,Math,Random,Wolfram Mathematica,理性是可以列举的。例如,此代码在开放区间0..1中找到第k个有理数,排序为{n1,d1}在{n2,d2}之前,如果(d1在分母上有一个界,则有理数不是均匀分布的(例如,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} 为你工作吗?
{n1,d1}
在{n2,d2}
之前,如果(d1在分母上有一个界,则有理数不是均匀分布的(例如,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}
为你工作吗?我强烈建议你去寻找一些关于你潜在问题的灵感
如果您的目标是尽快实现近似一致,并且您不介意选择具有不同概率的不同理性,那么以下算法应该是有效的
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)
对于大的n
你平均需要尝试大约2.55次。因此在实践中,这应该是非常有效的。以下是一些关于你提出的问题的随机想法。我没有仔细检查数学,所以我可能会在这里或那里被1淘汰。但它代表了我将遵循的推理方式
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)
我们只考虑区间(0,1)中的分数,这样就容易多了。我们可以用1/1个和不正确的分数来处理。
唯一列出每个缩减的正公共分数(因此每个小于或等于1的正有理数)一次,按顺序并以缩减的形式,作为树中的一个节点。在这个二叉树中,任何节点和任何分数都可以通过从最上层开始的有限的左右旋转序列来达到(为了方便起见,我们称之为级别-1),包含0/1和1/0。[是的,1/0。这不是印刷错误!]
给定分母k,您最多需要转k圈才能达到任何缩减分数j/k,其中j小于k。例如,如果分母为101,则分母为101或以下的所有可能分数都将位于树中级别1(包含1/1)和级别101(包含最左侧位置的1/101)之间的某个位置
假设我们有一个生成0和1的数字生成器(请不要问我怎么做,我不知道)。让我们任意决定左=0和右=1
假设我们有另一个数字生成器,它可以随机生成1到n之间的整数。进一步假设生成的第一个数字是0,即左转:这保证分数将在间隔(0,1)内下降
选择最大分母k。随机生成一个介于1和k之间的数字m。然后生成一个随机的R和L列表。沿着旋转列表遍历(即下降)Stern Brocot树。到达目标分数时停止
如果那个分数的分母等于或小于k,停止,这就是你的数字
如果分母大于k,则向上爬树(沿着您下降的同一路径),直到到达分母不大于k的分数
我不知道数字生成是真正随机的。我甚至不知道如何判断。但值得一提的是,我没有发现任何明显的偏差来源。问题是Farey序列只有一个递归表达式…@belisarius,所以我应该称之为RandomFarey。一个人可以通过以下方式从Farey序列生成随机元素吗在二元树上随机行走?这不需要存储在内存中就可以做到吗?不太好。但我的数论已经过时了。我想你可以试着在MathOverflow中问它,是的,但是随着分母的增加,有理数越来越近。我的目标是生成有理数,以便在sampl上经验分布的CDF
当分母界变大时,E趋向于直线。考虑<代码> CDF= CDF[经验性分布[随机逻辑1[ 50, 10 ^ 4 ] ],X];情节[{x,CDF},{x,0, 1 },排除->,ProptPosits -> 250,PrpType -> {黑,橙} < /代码>。克莱默Von米塞斯检验也表明分布接近于一致的<代码>柱状图[表]。很不幸,图像不能用于评论。评估cdf1=CDF[Randomational1[100,10^3],UniformDistribution[]],{10^3}];cdf2=CDF[RandomReal[1,10^4],1/25]],x];行{cdf1,x},x},ImageSize->250],绘图[{cdf2,x},{x,0,1},ImageSize->250]}
您可以看到,合理化的随机实数往往比从RandomRational1生成的随机实数慢得多。@Sasha RandomRational1生成的不同的有理数是合理化方法的5倍左右……此算法可以工作,但不会收敛到任何更接近均匀分布的数。@B请解释一下n、 它会偏爱某些分数吗?@David树中[L,L,R,R,L](或任何人)位置的公式是什么?@belisarius您可以在本演示的源代码中找到它。(下载源代码;它不太长).左和右是矩阵。Knuth的具体数学阐述了我开发的代码的基本原理。我会解释它,但我认为你会从演示中的代码中更快地理解它。@david carraher:它会强烈地支持某些区域而不是其他区域。例如,只有当e前10个选项是“L”,它只发生大约0.1%的时间。谢谢。这正是我想要的。后一种算法更适合Mathematica中的矢量化。据我所知,您只需选择带有I的成对(I,j)
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]]
]
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]}]];
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]
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}
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)
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