Finding the closest integer fraction to a given random real between 0..1, given ranges of numerator and denominator

泪湿孤枕 提交于 2019-11-27 03:24:44

问题


Given two ranges of positive integers x: [1 ... n] and y: [1 ... m] and random real R from 0 to 1, I need to find the pair of elements (i,j) from x and y such that x_i / y_j is closest to R.

What is the most efficient way to find this pair?


回答1:


Use Farey sequence.

  1. Start with a = 0, b = 1 and A = {the closest of a and b to R}.
  2. Let c be the next Farey fraction between a and b, given by c = (num(a) + num(b))/(denom(a) + denom(b)) (make sure to divide num(c) and denom(c) by gcd(num(c), denom(c))):
  3. If c's numerator or denominator is out of your input range, output A and stop.
  4. If c is closer to R than A, set A to c.
  5. If R is in [a, c] set b = c, otherwise set a = c.
  6. Go to 2.

This finds the best approximation in O(1) space, O(M) time worst-case, and O(log M) on average.




回答2:


The standard approach to approximating reals with rationals is computing the continued fraction series (see [1]). Put a limit on the nominator and denominator while computing parts of the series, and the last value before you break the limits is a fraction very close to your real number.

This will find a very good approximation very fast, but I'm not sure this will always find a closest approximation. It is known that

any convergent [partial value of the continued fraction expansion] is nearer to the continued fraction than any other fraction whose denominator is less than that of the convergent

but there may be approximations with larger denominator (still below your limit) that are better approximations, but are not convergents.

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




回答3:


Given that R is a real number such that 0 <= R <= 1, integers x: [1 ... n] and integers y: [1 ... m]. It is assumed that n <= m, since if n > m then x[n]/y[m] will be greater than 1, which cannot be the closest approximation to R.

Therefore, the best approximation of R with the denominator d will be either floor(R*d) / d or ceil(R*d) / d.

The problem can be solved in O(m) time and O(1) space (in 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()



回答4:


Prolly get flamed, but a lookup might be best where we compute all of the fractional values for each of the possible values.. So a simply indexing a 2d array indexed via the fractional parts with the array element containing the real equivalent. I guess we have discrete X and Y parts so this is finite, it wouldnt be the other way around.... Ahh yeah, the actual searching part....erm reet....




回答5:


Rather than a completely brute force search, do a linear search over the shortest of your lists, using round to find the best match for each element. Maybe something like this:

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)

Not at all sure whether the gcd "optimization" will ever be faster...




回答6:


The Solution: You can do this O(1) space and O(m log(n)) time:

there is no need to create any list to search,

The pseudo code may be is buggy but the idea is this:

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;
}

finding the index as home work to reader.

Description: I think you can understand what's the idea by code, but let trace one of a for loop: when i=1:

you should search within bellow numbers: 1,1/2,1/3,1/4,....,1/n you check the number with (1,1/cill(n/2)) and (1/floor(n/2), 1/n) and doing similar binary search on it to find the smallest one.

Should do this for loop for all items, so it will be done m time. and in each time it takes O(log(n)). this function can improve by some mathematical rules, but It will be complicated, I skip it.



来源:https://stackoverflow.com/questions/4385580/finding-the-closest-integer-fraction-to-a-given-random-real-between-0-1-given

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!