簡體   English   中英

是否有一種算法可以在沒有循環的情況下快速找到具有大整數的多項式的值?

[英]Is there an algorithm, to find values ​of a polynomial with big integers, quickly without loops?

例如,如果我想找到

1085912312763120759250776993188102125849391224162 = a^9+b^9+c^9+d 代碼需要帶上

一=3456

b=78525

c=217423

d=215478

我不需要具體的值,只要符合a、b和c最多6位,d盡可能小的事實即可。

有沒有快速找到的方法?

我很感激你能給我的任何幫助。

我嘗試過嵌套循環,但它非常慢並且代碼卡住了。

VB 或其他代碼中的任何幫助將不勝感激。 我認為在這種情況下結構比語言更重要

Imports System.Numerics
Public Class Form1

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim Value As BigInteger = BigInteger.Parse("1085912312763120759250776993188102125849391224162")
        Dim powResult As BigInteger
        Dim dResult As BigInteger
        Dim a As Integer
        Dim b As Integer
        Dim c As Integer
        Dim d As Integer

        For i = 1 To 999999
            For j = 1 To 999999
                For k = 1 To 999999
                    powResult = BigInteger.Add(BigInteger.Add(BigInteger.Pow(i, 9), BigInteger.Pow(j, 9)), BigInteger.Pow(k, 9))
                    dResult = BigInteger.Subtract(Value, powResult)
                    If Len(dResult.ToString) <= 6 Then
                        a = i
                        b = j
                        c = k
                        d = dResult
                        RichTextBox1.Text = a & " , " & b & " , " & c & " , " & d
                        Exit For
                        Exit For
                        Exit For
                    End If
                Next
            Next
        Next
    End Sub
End Class

更新

我用vb寫了代碼。 但是用這段代碼,a是對的,b是對的但是c不對,結果不對。

a^9 + b^9 + c^9 + d 是一個比初始值大的數。

代碼應該帶來

一 = 217423

b= 78525

c = 3456

d= 215478

總價值可以= 1085912312763120759250776993188102125849391224162

但代碼帶來

一 = 217423

b= 78525

c=65957

d= 70333722607339201875244531009974

總值大於等於=1085935936469985777155428248430866412402362281319

我需要更改什么代碼才能使 c= 3456 和 d= 215478?

代碼是

導入 System.Numerics Public Class Form1 Private Function pow9(x As BigInteger) As BigInteger Dim y As BigInteger y = x * x ' x^2 y *= y ' x^4 y *= y ' x^8 y *= x ' x^9 返回 y 結束 Function

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim a, b, c, d, D2, n As BigInteger
    Dim aa, bb, cc, dd, ae As BigInteger
    D2 = BigInteger.Parse("1085912312763120759250776993188102125849391224162")
    'first solution so a is maximal
    d = D2
    'a = BigIntegerSqrt(D2)
    'RichTextBox1.Text = a.ToString
    For a = 1 << ((Convert.ToInt32(Math.Ceiling(BigInteger.Log(d, 2))) + 8) / 9) To a > 0 Step -1
        If (pow9(a) <= d) Then
            d -= pow9(a)
            Exit For
        End If
    Next
    For b = 1 << ((Convert.ToInt32(Math.Ceiling(BigInteger.Log(d, 2))) + 8) / 9) To b > 0 Step -1
        If (pow9(b) <= d) Then
            d -= pow9(b)
            Exit For
        End If
    Next
    For c = 1 << ((Convert.ToInt32(Math.Ceiling(BigInteger.Log(d, 2))) + 8) / 9) To c > 0 Step -1
        If (pow9(c) <= d) Then
            d -= pow9(c)
            Exit For
        End If
    Next

    ' minimize d
    aa = a
    bb = b
    cc = c
    dd = d
    If (aa < 10) Then
        ae = 0
    Else
        ae = aa - 10
    End If

    For a = aa - 1 To a > ae Step -1 'a goes down few iterations
        d = D2 - pow9(a)
        For n = 1 << ((Convert.ToInt32(Math.Ceiling(BigInteger.Log(d, 2))) + 8) / 9) To b < n 'b goes up
            If (pow9(b) >= d) Then
                b = b - 1
                d -= pow9(b)
                Exit For
            End If
        Next
        For c = 1 << ((Convert.ToInt32(Math.Ceiling(BigInteger.Log(d, 2))) + 8) / 9) To c > 0 Step -1 'c must be search fully
            If pow9(c) <= d Then
                d -= pow9(c)
                Exit For
            End If
        Next
        If d < dd Then 'remember better solution
            aa = a
            bb = b
            cc = c
            dd = d
        End If
        If a < ae Then
            Exit For
        End If
    Next
    a = aa
    b = bb
    c = cc
    d = dd
    ' a,b,c,d is the result
    RichTextBox1.Text = D2.ToString
    Dim Sum As BigInteger
    Dim a9 As BigInteger
    Dim b9 As BigInteger
    Dim c9 As BigInteger
    a9 = BigInteger.Pow(a, 9)
    b9 = BigInteger.Pow(b, 9)
    c9 = BigInteger.Pow(c, 9)
    Sum = BigInteger.Add(BigInteger.Add(BigInteger.Add(a9, b9), c9), d)
    RichTextBox2.Text = Sum.ToString
    Dim Subst As BigInteger
    Subst = BigInteger.Subtract(Sum, D2)
    RichTextBox3.Text = Subst.ToString
End Sub

結束 Class

[更新]

下面的代碼試圖解決像 OP 這樣的問題,但我在閱讀它時犯了錯誤。

下面是1085912312763120759250776993188102125849391224162 = a^9+b^9+c^9+d^9+e並最小化e

只是對 OP 的有趣難題過於興奮並且閱讀得太快。

我稍后再回顧這個。


OP的方法是O(N*N*N*N) - 慢

下面是一個O(N*N*log(N))的。

算法

讓 N = 1,000,000。 (看起來 250,000 足以滿足 OP 的總和 1.0859e48。)

定義 160+ 寬 integer 數學例程。

定義類型:pow9

int x,y,
int160least_t z

形成數組pow9 a[N*N]填充x, y, x^9 + y^9 ,對於 [1...N] 范圍內的每個x,y

z上對數組進行排序。

到目前為止的成本O(N*N*log(N)

對於索引為 [0... N*N/2] 的數組元素,對另一個數組元素進行二進制搜索,使得總和為 1085912312763120759250776993188102125849391224162

總和最接近的就是答案。

時間: O(N*N*log(N))

空間: O(N*N)


很容易從 FP 數學開始,然后通過 crafter 擴展 integer 數學得到更好的答案。

嘗試使用較小的N和總和目標來解決實施問題。

如果a,b,c,d可能為零,我想到了一個快速簡單的解決方案:

首先是比蠻力搜索a^9 + d = x更好的東西,這樣a是最大的(確保最小d )......

  1. d = 1085912312763120759250776993188102125849391224162

  2. 找到最大值a使得a^9 <= d

    這很簡單,因為我們知道 9 次方會將操作數的位寬乘以 9 倍,因此最大值最多可以是a <= 2^(log2(d)/9)現在只需搜索從該數字開始的所有數字到零(遞減) 直到它的 9 次方小於或等於x 這個值將是我們a

    它仍然是蠻力搜索,但是從更好的起點開始,因此需要更少的迭代。

  3. 我們還需要更新d所以讓

    d = d - a^9

現在只需以相同的方式找到b,c (使用越來越小的余數d )......這些搜索沒有嵌套,所以它們很快......

b^9 <= d; d-=b^9;
c^9 <= d; c-=b^9;

為了進一步提高速度,您可以通過平方使用功率對 9 次方進行硬編碼...

這將是我們的初始解決方案(在我的設置中,使用 32*8 位 uint 花費了約 200 毫秒),結果如下:

x = 1085912312763120759250776993188102125849391224162
    1085912312763120759250776993188102125849391224162 (reference)
a = 217425
b = 65957
c = 22886
d = 39113777348346762582909125401671564

現在我們想要最小化d所以簡單地遞減a並向上搜索b直到a^9 + b^9 <= d仍然較低。 然后像以前一樣搜索c並記住更好的解決方案。 a 應該向下搜索以在中間遇到b但由於ab具有相同的權力,只有少數迭代可能就足夠了(我使用了 50)從第一個解決方案(但我沒有證據證明這只是我的感覺)。 但是即使使用了全范圍,它的復雜性也比你的要低,因為我只有 2 個嵌套for s 而不是你的 3,而且它們的范圍都較低......

這里是 C++ 的小例子(抱歉幾十年來沒有用 BASIC 編寫代碼):

//---------------------------------------------------------------------------
typedef uint<8> bigint;
//---------------------------------------------------------------------------
bigint pow9(bigint &x)
    {
    bigint y;
    y=x*x;  // x^2
    y*=y;   // x^4
    y*=y;   // x^8
    y*=x;   // x^9
    return y;
    }
//---------------------------------------------------------------------------
void compute()
    {
    bigint a,b,c,d,D,n;
    bigint aa,bb,cc,dd,ae;
    D="1085912312763120759250776993188102125849391224162";
    // first solution so a is maximal
    d=D;
    for (a=1<<((d.bits()+8)/9);a>0;a--) if (pow9(a)<=d) break; d-=pow9(a);
    for (b=1<<((d.bits()+8)/9);b>0;b--) if (pow9(b)<=d) break; d-=pow9(b);
    for (c=1<<((d.bits()+8)/9);c>0;c--) if (pow9(c)<=d) break; d-=pow9(c);

    // minimize d
    aa=a; bb=b; cc=c; dd=d;
    if (aa<50) ae=0; else ae=aa-50;
    for (a=aa-1;a>ae;a--)       // a goes down few iterations
        {
        d=D-pow9(a);
        for (n=1<<((d.bits()+8)/9),b++;b<n;b++) if (pow9(b)>=d) break; b--; d-=pow9(b); // b goes up
        for (c=1<<((d.bits()+8)/9);c>0;c--) if (pow9(c)<=d) break; d-=pow9(c);          // c must be search fully
        if (d<dd)               // remember better solution
            {
            aa=a; bb=b; cc=c; dd=d;
            }
        }
    a=aa; b=bb; c=cc; d=dd; // a,b,c,d is the result
    }
//-------------------------------------------------------------------------

function bits()僅返回占用的位數(類似於log2但速度更快)。 這里最終結果:

x = 1085912312763120759250776993188102125849391224162
    1085912312763120759250776993188102125849391224162 (reference)
a = 217423
b = 78525
c = 3456
d = 215478

它花了 1689.651 毫秒......正如你所看到的,這比你的快得多但是我不確定搜索迭代的次數,而微調a是可以的,或者它應該按a/b或什至整個范圍縮小到(a+b)/2會比這慢很多...

最后一件事我沒有將 a,b,c 綁定到999999所以如果你想要它你只需添加if (a>999999) a=999999; 任何a=1<<((d.bits()+8)/9) ... 之后的語句

[Edit1] 添加二進制搜索

好的,現在所有對第 9 根的完整搜索(除了a的微調)都可以使用二進制搜索來完成,這將大大提高速度,同時忽略 bigint 乘法復雜性導致O(n.log(n))對你的O(n^3) ... 這里更新了代碼(將完整迭代a時間以使其安全):

//---------------------------------------------------------------------------
typedef uint<8> bigint;
//---------------------------------------------------------------------------
bigint pow9(bigint &x)
    {
    bigint y;
    y=x*x;  // x^2
    y*=y;   // x^4
    y*=y;   // x^8
    y*=x;   // x^9
    return y;
    }
//---------------------------------------------------------------------------
bigint binsearch_max_pow9(bigint &d)    // return biggest x, where x^9 <= d, and lower d by x^9
    {                                   // x = floor(d^(1/9)) , d = remainder
    bigint m,x;
    for (m=bigint(1)<<((d.bits()+8)/9),x=0;m.isnonzero();m>>=1)
     { x|=m; if (pow9(x)>d) x^=m; }
    d-=pow9(x);
    return x;
    }
//---------------------------------------------------------------------------
void compute()
    {
    bigint a,b,c,d,D,n;
    bigint aa,bb,cc,dd;
    D="1085912312763120759250776993188102125849391224162";
    // first solution so a is maximal
    d=D;
    a=binsearch_max_pow9(d);
    b=binsearch_max_pow9(d);
    c=binsearch_max_pow9(d);
    // minimize d
    aa=a; bb=b; cc=c; dd=d;
    for (a=aa-1;a>=b;a--)       // a goes down few iterations
        {
        d=D-pow9(a);
        for (n=1<<((d.bits()+8)/9),b++;b<n;b++) if (pow9(b)>=d) break; b--; d-=pow9(b); // b goes up
        c=binsearch_max_pow9(d);
        if (d<dd)               // remember better solution
            {
            aa=a; bb=b; cc=c; dd=d;
            }
        }
    a=aa; b=bb; c=cc; d=dd;     // a,b,c,d is the result
    }
//-------------------------------------------------------------------------

function m.isnonzero()m!=0相同,只是速度更快... 結果與上面的代碼相同,但a的完整迭代的持續時間僅為821 ms ,如果使用之前的代碼,則為數千秒。

我認為除了使用一些多項式離散數學技巧我不知道只有一件事需要改進,那就是計算結果pow9沒有乘法,這將大大提高速度(因為bigint 乘法是迄今為止最慢的操作)就像我在這里做了:

但我懶得推導它......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM