[To be] limit_denominator algorithm

When I was watching Fraction, I saw the limit_denominator method and I was very interested!
Writing a code according to the concept is very simple, violently from beginning to end, but there should be room for optimization!
The full text is not perfect yet, it can be used as a starting point. After all, if in-depth optimization, it will involve a high level of knowledge and can’t afford to play~ it
will be improved in the future!

2021/3/17 second time

import random,math,fractions
l1=[]
l2=[]
s=set()
for i in range(1000):
    x=random.randint(1,10000)/10000
    if x<0.001:continue
    if 0.999<x:continue
    m=float('inf')
    p=math.ceil(1000*x)
    if p/x>1000:p-=1
    n=1000
    nn=n%1
    if nn<=0.5:
        n=math.floor(n)
    elif nn>=0.5:
        n=math.ceil(n)
    else:continue
    if n>1000:continue
    s.add(n)
    if (tt:=(math.ceil(x*n)/n-x))<=m:
        m=tt
        t=n
    if (tt:=(x-math.floor(x*n)/n))<=m:
        m=tt
        t=n
    n=p/x
    nn=n%1
    if nn<=0.5:
        n=math.floor(n)
    elif nn>=0.5:
        n=math.ceil(n)
    else:continue
    if n>1000:continue
    s.add(n)
    if (tt:=(math.ceil(x*n)/n-x))<=m:
        m=tt
        t=n
    if (tt:=(x-math.floor(x*n)/n))<=m:
        m=tt
        t=n
    
    for i in range(p,0,-1):
        n=i/x
        nn=n%1
        if nn<=0.25:
            n=math.floor(n)
        elif nn>=0.75:
            n=math.ceil(n)
        else:continue
        if n>1000:continue
        s.add(n)
        if (tt:=(math.ceil(x*n)/n-x))<=m:
            m=tt
            t=n
        if (tt:=(x-math.floor(x*n)/n))<=m:
            m=tt
            t=n
            
    if t==(f:=fractions.Fraction(x).limit_denominator(1000)).denominator:l1.append(x)
    else:
        l2.append(x)
        print(x,t,math.ceil(x*t)/t-x,f,f-x,p/x-1/x,f.denominator*x)
    #     break
    # if (f:=fractions.Fraction(x).limit_denominator(1000).denominator) not in s:
    #      print(x,i,f)
print(len(l1),len(l2))

This time it’s a bit messy, because I found a lot of accidents on the initial basis, mainly 1000, and the first contact, these do not comply with the 0.25 and 0.75 rules, as for the optimization of the cycle law, I will write when I have the energy that day, this time because The mathematics caused me a lot of distress, so now it comes to an end.

Summarize the following questions:
1. It is correct to follow the small cycle of /x, and all the results are in this set.
2. The result is not the nearest number greater than x, but the nearest number greater than x, that is to say the result Half of it may be less than
3, the last period of x , or the first number calculated from the back. Don’t consider it according to 0.25 and 0.75, but take it as a reference value first, when it is within the range of 1000 When a cycle is not completed, usually the last number is the result

the first time

Fraction('3.141592653589793').limit_denominator(1000)
Out[52]: Fraction(355, 113)

t=3.141592653589793
c=0
for i in range(100,1000):
    if (tt:=((3.141592653589793*i)//1+1)/i-3.141592653589793)<t:
        t=tt
        c=i
c
Out[63]: 113

Insert picture description here
The result seen from the graph is periodic, but you cannot be sure that the bottom of a cycle is the bottom of the entire range. I have not studied this step
Insert picture description here
yet
. If you move one bit forward, you can simplify the cycle
above from the graph. The result is.
Insert picture description here
00141592653589793 In the overall situation, there is only one lowest point

For a look at the number:
.1112
Insert picture description here.0011125
Insert picture description here
this difference is more obvious, but obviously I can see, which is the lowest point in the back of the former.

for i in range(100):
    x=random.randint(1000,10000)/10000
    if Fraction(x*0.01).limit_denominator(1000).denominator<Fraction(x).limit_denominator(1000).denominator:print(x)

x=0.1218
l1,l2=[],[]
for i in range(100,1000):
    l1.append(i)
    l2.append(((x*i)//1+1)/i-x)
print(Fraction(x).limit_denominator(1000))
plt.plot(l1,l2,'r')
119/977

Insert picture description here
= .001218 the X-
1/821
Insert picture description here
.3818
365/956
Insert picture description here
.0003818 3
1/873
Insert picture description here
the X-.3727 =
243/652
Insert picture description herethe X-.0003727 =
5
1/537
Insert picture description here
At this time, I suddenly thought of a problem, the minimum value is cyclical, and if the second half If there is no trough, then there will be no trough in the first half, then the minimum value of the second half is the minimum value (this is similar to the square root of half), and then you can divide by toss and turns.

Ideas

According to this line of thinking, when you encounter a trough, you will encounter the next trough. If the values ​​of the two troughs are the same, it is a true trough. Take the last trough and divide it.

If halfway through the calculation, no true trough is encountered, then there is no true trough in this period, just take the second half minimum value.

This is based on a small period that cannot be directly calculated. Of course, a mathematical genius will not have a method to calculate a small period, which is unknown.

Then from the numerical consideration:

for i in range(100):
    x=random.randint(1,10000)/10000
    f=fractions.Fraction(x).limit_denominator(1000).denominator
    z=f/(1/x)
    if (z<0.5 and z>0.05) or (z>0.5 and z<0.95):print(x,fractions.Fraction(x).limit_denominator(10),z)

10:
0.0733 1/10 0.7330000000000001
0.1349 1/7 0.9442999999999999
0.058 1/10 0.5800000000000001
0.0572 1/10 0.572
0.0603 1/10 0.603
0.0691 1/10 0.691
0.0748 1/10 0.7480000000000001
100:
0.0082 0 0.8200000000000001

Basically only at 10, 0.1349 1/7 0.9442999999999999

fractions.Fraction('0.0055').limit_denominator(100)
Out[102]: Fraction(1, 100)

fractions.Fraction('0.000055').limit_denominator(100)
Out[103]: Fraction(0, 1)

In fact, if the number is small, you don’t need to think about optimization, but need to consider optimization on a large order of magnitude.

l=[]
for i in range(10000):
    x=random.randint(1,10000)/10000
    f=fractions.Fraction(x).limit_denominator(10).denominator
    # l.append(f/(1/x)%1)
    if f!=10:l.append(f/(1/x)%1)
sorted(list(set([round(i,3) for i in l])))
...
 0.24,
 0.241,
 0.242,
 0.245,
 0.246,
 0.247,
 0.248,
 0.249,
 0.25,
 0.751,
 0.755,
 0.756,
 0.757,
 0.758,
 0.759,
 0.76,
...

It can be seen that it is very likely that the value (0.25, 0.75) is the vacuum period. The specific mathematical derivation will be discussed later. Now we will only optimize the process according to the most likely situation.
For example, given a number, we do not use the limit method, but do it ourselves Calculate, then he gets the reciprocal of the number or his complement, which can reduce the amount of calculation, and ignore the (0.25, 0.75) part to further reduce the scope of calculation.

if f==100 or f==1:

0.9099 91/100
0.3307 33/100
0.33 33/100
0.5703 57/100
0.0033 0
0.0901 9/100
0.9959 1
0.9978 1
0.1302 13/100
0.0901 9/100
0.3315 33/100
0.53 53/100

if f!=100:
0.0102 1/98
0.1851 5/27
0.6057 43/71
0.8737 83/95
0.2309 3/13
0.6181 34/55
0.5637 31/55
0.3995 2/5
0.0784 4/51
0.7583 69/91
0.4359 17/39
0.6879 64/93

As for the exceptions:

1/0.9099
Out[150]: 1.0990218705352237

1/(1-0.9099)
Out[151]: 11.098779134295233

1/0.0033
Out[152]: 303.03030303030306

1/(1-0.0033)
Out[153]: 1.0033109260559847

Fraction('0.009').limit_denominator(100)
Out[155]: Fraction(1, 100)


Fraction('0.0049').limit_denominator(100)
Out[156]: Fraction(0, 1)

Fraction('0.005').limit_denominator(100)
Out[157]: Fraction(0, 1)

Fraction('0.0051').limit_denominator(100)
Out[158]: Fraction(1, 100)

Fraction('0.005000000000000001').limit_denominator(100)
Out[169]: Fraction(1, 100)

round(0.005,2)
Out[164]: 0.01

round(0.0049,2)
Out[165]: 0.0

Can this situation be rounded? It seems that the rule of limit is 5+

In short, once you know the rules, you can simplify the process. Here, mathematics is still the core problem. If you can get definite number theory, you don't need to summarize the data, and the result of number theory is certain!

Guess you like

Origin blog.csdn.net/jhsxy2005/article/details/114682513