问题 找到给定随机实数的最接近整数分数


给定两个正整数范围x:[1 ... n]和y:[1 ... m]和从0到1的随机实数R,我需要找到x和x的元素对(i,j) y使得xi / yj最接近R.

找到这对的最有效方法是什么?


7183
2017-12-08 08:43


起源

到目前为止你有什么? - Kobi
我保持习近平固定并得到最接近的易建联。我发现我不够亲近。我知道我可以通过上下踩着Xi来看看我能得到什么,但这看起来很糟糕。 - John Shedletsky
乍一看似乎很容易,但我认为这可能很难。如果没有像1/2 = .5这样的完美解决方案,可能会有多个正确答案。实际上我猜在那种情况下还有多个答案,比如2/4。在有多个答案的情况下,我想要范围内最大的Xi和Yi。 - John Shedletsky
看到 这个答案 - Gareth Rees
x []和y []是一个数字列表/数组还是一系列数字? - Axn


答案:


使用 Farey序列

  1. 从a = 0开始,b = 1,A = {最接近a,b到R}。
  2. 设c是a和b之间的下一个Farey分数,由c =(num(a)+ num(b))/(denom(a)+ denom(b))给出(确保不包括num(c)和denom (c)通过gcd(num(c),denom(c)))。
  3. 如果c的分子或分母超出输入范围,则输出A并停止。
  4. 如果c比A更接近R,则将A设置为c。
  5. 如果R在[a,c]中,则设置b = c,否则设置a = c。
  6. 转到2。

这在O(1)空间,O(M)时间最差情况和O(log M)平均值中找到最佳近似值。


10
2017-12-08 08:59



-1:为什么你甚至期望这个工作?请记住,分子和分母是受限制的。
@moron:它实际上适用于受限分母和0到1之间的数字(这种情况就是这种情况)。事实上,我很确定它可以适用于受限制的分子(限制分母,给定数字)。 - lijie
我不确定O(log M)的平均情况,现在没有时间分析。 - ybungalobill
@John:x = [5],y = [8],R = 3/5。这输出1并停止(在步骤3中),这甚至不是可行的解决方案。
@Echsecutor:因为两者都是单调增加的,所以当第一个超过界限时,就没有必要进一步观察。 - ybungalobill


用有理数逼近实数的标准方法是计算 继续分数系列 (见[1])。在计算系列的部分时限制分母和分母,并且在打破限制之前的最后一个值是非常接近实数的分数。

这将非常快速地找到非常好的近似值,但我不确定这总是会找到最接近的近似值。众所周知

任何收敛[连续分数展开的部分值]比分数小于收敛分数的任何其他分数更接近连续分数

但是可能存在较大分母(仍然低于极限)的近似值,这些近似值是更好的近似值,但不是收敛值。

[1] http://en.wikipedia.org/wiki/Continued_fraction


5
2017-12-08 09:00



我可能会误解 - 我不想要一个连续的分数作为答案,我想要一个单独的分子和分母。你是说如果我找到了连续的分数,那么我对更简化的分数有一些最优保证吗? - John Shedletsky
您可能想要的是“最佳有理近似”(在维基百科页面上的连续分数),它或者是连续分数的收敛,或者其中一个收敛的最终商数减少了1。 - Nabb
+1 en.wikipedia.org/wiki/... - starblue
连续分数确实产生有理近似(通过使用最后收敛的小分子/分母)。但是,在给定的提名者/衡量者范围内,为什么这应该是R的最佳近似值? - Echsecutor


鉴于R是一个实数,这样 0 <= R <= 1,整数 x: [1 ... n] 和整数 y: [1 ... m]。假设是 n <= m,因为如果 n > m 然后 x[n]/y[m] 将大于 1,它不能是最接近的 R

因此,具有分母d的R的最佳近似值将是 floor(R*d) / d 要么 ceil(R*d) / d

这个问题可以解决 O(m) 时间和 O(1) 空间(在Python中):

from __future__ import division
from random import random
from math import floor

def fractionize(R, n, d):
    error = abs(n/d - R)
    return (n, d, error)  # (numerator, denominator, absolute difference to R)

def better(a, b):
    return a if a[2] < b[2] else b

def approximate(R, n, m):
    best = (0, 1, R)
    for d in xrange(1, m+1):
        n1 = min(n, int(floor(R * d)))
        n2 = min(n, n1 + 1) # ceil(R*d)
        best = better(best, fractionize(R, n1, d))
        best = better(best, fractionize(R, n2, d))
    return best

if __name__ == '__main__': 
    def main():
        R = random()
        n = 30
        m = 100
        print R, approximate(R, n, m)
    main()

1
2017-12-08 10:42



蛮力并不总是最好的算法;) - Echsecutor


Prolly变得火热,但是在我们计算每个可能值的所有小数值时查找可能是最好的。因此,简单地索引通过小数部分索引的2d数组,其中数组元素包含实际等价物。我想我们有离散的X和Y部分所以这是有限的,它不会是相反的方式....啊,是的,实际的搜索部分....呃reet ....


0
2017-12-08 08:54



在我的特定应用中,n和m大约为100,000。这使得预计算不合需要。我希望能进行某种类型的爬坡优化。 - John Shedletsky
这就像QI,我只是回答了白痴的回答大声笑.... - brumScouse


而不是完全强力搜索,在最短的列表上进行线性搜索,使用round来找到每个元素的最佳匹配。也许是这样的:

best_x,best_y=(1,1)
for x in 1...n:
    y=max(1,min(m,round(x/R)))
    #optional optimization (if you have a fast gcd)
    if gcd(x,y)>1:
        continue

    if abs(R-x/y)<abs(R-bestx/besty):
        best_x,best_y=(x,y)
return (best_x,best_y)

完全不确定是否 gcd “优化”将更快......


0
2017-12-08 09:00



这怎么不是“完全蛮力”? - Echsecutor


解决方案: 你可以这样做 O(1) 空间和 O(m log(n))时间:

无需创建任何搜索列表,

伪代码可能是错误的,但想法是这样的:

r: input number to search.
n,m: the ranges.

for (int i=1;i<=m;i++)
{
    minVal = min(Search(i,1,n,r), minVal);
}

//x and y are start and end of array:
decimal Search(i,x,y,r)
{
   if (i/x > r)
      return i/x - r;

   decimal middle1 = i/Cill((x+y)/2); 
   decimal middle2 = i/Roof((x+y)/2);

   decimal dist = min(middle1,middle2)

   decimal searchResult = 100000;

   if( middle > r)
     searchResult = Search (i, x, cill((x+y)/2),r)
  else
     searchResult = Search(i, roof((x+y)/2), y,r)

  if  (searchResult < dist)
     dist = searchResult;

  return dist;
}

将索引作为读者的家庭工作。

描述:我认为你可以理解代码的想法是什么,但是跟踪一个for循环: 当i = 1时:

你应该在以下数字内搜索: 1,1 / 2,1 / 3,1 / 4,...,1 / n的 你用(1,1 / cill(n / 2))和(1 / floor(n / 2),1 / n)检查数字并对其进行类似的二元搜索以找到最小的数字。

应该为所有项目执行此循环,因此它将完成  时间。并且每次都需要O(log(n))。这个函数可以通过一些数学规则来改进,但它会很复杂,我跳过它。


0
2017-12-08 08:58



任何聪明的优化都要比O(nm)空间和O(nm lg(nm))时间更好? - John Shedletsky
@John Shedletsky,@ ybungalobill答案很好。 - Saeed Amiri
不它不是。特别是没有证据。
@Moron,你要证明什么?如上所述的算法以指定的顺序运行,并将得到最佳答案,例如对于二进制搜索,你说的是证明,它找到完全匹配?不,因为算法描述了信任,关于顺序,很容易证明它,如果有任何歧义告诉描述它。 - Saeed Amiri
我回应你对约翰的评论。不是你的答案。