Algorithm 伪丢番图方程极小化的快速算法

Algorithm 伪丢番图方程极小化的快速算法,algorithm,minimum,number-theory,Algorithm,Minimum,Number Theory,我们正在寻找一种算法来解决O(N)下的这个问题 给定两个实数a和b(在不丧失一般性的情况下,您可以假设它们都在0和1之间) 在-n和n之间找到一个使表达式最小化的整数n: |a n-b轮(a n-b)| 我们曾认为欧几里德算法可能会很好地解决这个问题,但无法解决这个问题。当然,看起来应该有比对整数n进行穷举搜索更快的方法来实现这一点 注意:在我们的情况下,a和b可能会经常变化,因此为查找表修复a和b是可能的,因为N也可能变化,所以它变得有点难看。尚未详细查看查找表,以了解它作为N的函数可以有多小

我们正在寻找一种算法来解决O(N)下的这个问题

给定两个实数a和b(在不丧失一般性的情况下,您可以假设它们都在0和1之间) 在-n和n之间找到一个使表达式最小化的整数n:

|a n-b轮(a n-b)|

我们曾认为欧几里德算法可能会很好地解决这个问题,但无法解决这个问题。当然,看起来应该有比对整数n进行穷举搜索更快的方法来实现这一点


注意:在我们的情况下,a和b可能会经常变化,因此为查找表修复a和b是可能的,因为N也可能变化,所以它变得有点难看。尚未详细查看查找表,以了解它作为N的函数可以有多小。

您正在有效地搜索使表达式
aN-b
尽可能接近整数的整数N。
a
b
是否固定?如果是,您可以预先计算查找表,并具有O(1):-)


如果不考虑n,使<代码> < <代码> > <代码> i+b>代码>所有整数>代码> i < /c> > /p> < p>听起来你可能正在寻找类似……/p>之类的东西。 它们有什么关系?假设你可以用有理数b1/b2代替b。现在你在寻找整数n和m,这样an-b1/b2大约是m。换句话说,你在寻找n和m,使得(m+(b1/b2))/n=(mb2+b1)/nb1,一个有理数,近似为a。设置a1=mb2+b1和a2=nb1。从连分数近似中找到a1和a2的值,并求解n和m

另一种方法可以是:

  • 为a和b找到一个好的有理逼近:a~a1/a2和b~b1/b2
  • 求解n(a1/a2)-(b1/b2)=m表示n和m

  • 不过,我不太确定它会起作用。A的精度取决于N和B.

    首先,让我们考虑一个简单的情况,其中B=0,0<A<1。F(a,n)=一轮(an)|

    让步长_size=1

    Step 1. Let v=a
    Step 2. Let period size p = upper_round( 1/v ).
    Step 3. Now, for n=1..p, there must be a number i such that F(v,i) < v.
    Step 4. v = F(v,i), step_size = stepsize * i
    Step 5. Go to step 2
    
    第1步。设v=a
    第二步。让周期大小p=上轮(1/v)。
    第三步。现在,对于n=1..p,必须有一个数字i,使得F(v,i)

    正如你所看到的,你可以把F(v,*)降低到你想要的任何水平。最终解n=步长。

    您可以计算比率a/b的连分数。分母大于
    N
    或近似值足够好时,可以停止

    // Initialize:
    double ratio = a / b;
    int ak = (int)(ratio);
    double remainder = ratio - ak;
    
    int n0 = 1;
    int d0 = 0;
    
    int n1 = ak;
    int d1 = 1;
    
    do {
        ratio = 1 / remainder;
        ak = (int)ratio;
        int n2 = ak * n1 + n0;
        int d2 = ak * d1 + d0;
        n0 = n1;
        d0 = d1;
        n1 = n2;
        d1 = d2;
        remainder = ratio - ak;
    } while (d1 < N);
    
    //初始化:
    双倍比率=a/b;
    int ak=(int)(比率);
    双余数=比率-ak;
    int n0=1;
    int d0=0;
    int n1=ak;
    int d1=1;
    做{
    比率=1/余数;
    ak=(int)比率;
    int n2=ak*n1+n0;
    int d2=ak*d1+d0;
    n0=n1;
    d0=d1;
    n1=n2;
    d1=d2;
    余数=比率-ak;
    }d1
    您要查找的
    n
    的值为
    d0
    (如果仍然小于
    n
    ,则为
    d1


    这不一定会给出最小解,但它可能是一个非常好的近似值。

    a和b不是固定的。我们早就想到了。我们已经考虑过为N个小的建立N个查找表,但这是用O(N)空间换取O(1)速度,我们通常不喜欢这种方法,但这是我们的退路。你试过绘制方程并尝试一些启发式方法吗?不,对这一个的启发式方法不太感兴趣。这至少可以提供一些见解。
    a
    b
    是实数还是精度有限的浮点整数?可能是浮点,也可能是双精度。这是要在计算机上实现的东西。如果你打算测试k个不同的n,那么我可以提供一个解决方案,保证| a n-b-round(a n-b)|<1/k。我们正在搜索所有n个整数,这样| n |我肯定他知道连分数是什么,但这有什么帮助,是吗?你不觉得找到实数的有理近似值有什么相似之处吗?“我太累了,现在无法写出一个像样的论点。@JoniSalonen寻找有理近似!=解决方案在这里。即使x/y大约等于a,那么| ya round(ya)|可能仍然很高。例:a=0.1111111110874642873287。。。。x=1,y=9是一个很好的近似值。但| 9*a-轮(9*a)|大致等于1。编辑答案以使想法更清晰@ElKamina不会一轮9*a(9*a)更像.000000000 212821440417,而不是最低需要1。为什么d0或d1是我要找的数字?如果b=0,那么让n=0(n在-n和n之间,包括-n和n),我们得到的表达式是零。我假设你正在研究子问题,其中n在1和n之间,包括1和n?你能描述一下你的算法在做什么吗?看起来像某种连分数表达式吗?@John这给出了一个介于1和无穷大之间的解。现在我详细地看了你的问题,是的,这对你的问题不起作用。