Random rational numbers generation

前端 未结 3 1338
失恋的感觉
失恋的感觉 2021-02-04 04:26

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&

相关标签:
3条回答
  • 2021-02-04 04:49

    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.

    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)
    

    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 from 1 to n, then the following pseudocode will work for denominator bound 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
    

    On average for large n you'll have to Try about 2.55 times. So in practice this should be pretty efficient.

    0 讨论(0)
  • 2021-02-04 04:55

    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.

    0 讨论(0)
  • 2021-02-04 05:01

    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

    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}
    

    work for you?

    0 讨论(0)
提交回复
热议问题