簡體   English   中英

如果已知非常大整數 N 的因式分解,則快速計算浮點 1/N

[英]Fast calculation of floating 1/N if factorization of very large integer N is known

如果我有我知道因式分解的整數N ,那么將1/N計算為浮點數的最快(最有效)方法是什么? 應該使用大的浮點(或整數)算術。

我想用 C++ 做這個(或者用 Python 做實驗)。

我的N非常大,大小為 Giga/Tera 位。 結果浮點N也應該具有很高的精度,大約與初始N相同的位大小。

需要精確的浮點值,這意味着如果我請求浮點精度Log2(N)位,那么至少所有95%的結果前導位都應該是精確的(與理想值中的所有位相同)。

當然,如果它有助於和/或簡化任務,則可以將4^Ceil(Log2(N)) / N為整數除法,而不是浮點計算。 對我來說,這兩個任務(整數和浮點數)本質上是相同的,因為整數表示可以轉換為浮點數,反之亦然。

一個重要的注意事項是N因式分解只有很小的質因數,它們的大小都是 32 位(當然最多可能是 64 位)。

我想知道是否有N因式分解以及因數很小的事實,它能否以某種方式幫助解決任務?

當然,我沒有首先實現我自己的部門,而是嘗試使用高度優化的GMP庫來完成這項任務,但它(據我所知)並沒有使用N已經被分解的事實。

任何人都可以建議我是否要為此實現自己的功能,只是為了通過實驗確定它是否會比 GMP 更快,那么我應該使用哪種算法?

我發現這里可以使用 3 種算法 1) Long Division ,這是一種學校級算法。 2)巴雷特減少 3)蒙哥馬利歸約

其實我不知道任何其他算法。 你能推薦其他的嗎? Barrett 和 Montgomery 歸約只有在相同的素因數重復多次時才有幫助,否則單次除法不值得 Barrett 和 Montgomery 所需的預先計算。

此外,巴雷特/蒙哥馬利的減少仍然需要一次性計算4^Ceil(Log2(N)) / PrimeDivisor 所以他們不會讓你免於做長除法算法。

對於長除法算法,我肯定會使用2^64作為基數而不是基數10 (如在學校中)。

我已經使用 Long Division 和所有其他整數算法以及橢圓曲線算法實現了我自己的實驗庫。 現在它是通用的,因此不比 GMP 快。 現在我需要特殊的除法算法,它至少比 GMP 快幾倍。

當然,在長除法中我可以使用蒙哥馬利和巴雷特,因為在每一步它都需要短除法(128 位整數除以 64 位整數),如果它有任何提升。

同樣在長除法的每個步驟中,我都可以使用快速傅立葉變換數論變換進行乘法運算。

以上是我所知道的唯一優化。 還有其他可能的優化嗎? 也許FFT可以用於直接做除法(不僅僅是乘法)?

大概的概念

N可以分解為小整數的事實會有所幫助。 實際上,這意味着N = a1 * a2 * ... * an 因此, 1/N = 1/(a1 * a2 * ... * an) = (1/a1) * (1/a2) * ... * (1/an)

問題是計算1/a的許多因素a可能比計算1/N快。 的確:

  • 1 / a的十進制/二進制展開周期應該遠小於1 / N因為log2(a)遠小於log2(N)這意味着1/a的精確表示可以以非常緊湊的方式存儲並且很快;
  • 因子的倒數可以獨立計算,因此可以並行計算;
  • 當一個因子在 N 的因式分解中多次使用時,其代價高昂的倒數只能計算一次;
  • 乘數應該比計算倒數或除法快得多
  • 最終的基於乘法的歸約可以使用成對歸約策略並行完成。

然而,有一個問題:這種方法需要很多乘法,因為有很多因子,雖然它們大部分可以並行計算,但這仍然是一個相當昂貴的計算(特別是最后一個乘法很難執行)平行線)。 因此,我不確定該方法是否比在 GMP 中實施的非常優化的方法快得多,但它確實值得一試。


筆記

將相同大小的數字相乘或什至將具有最小十進制/二進制擴展周期的第一個數字相乘可能更好(以最小化計算倒數的符號表示的大小,從而導致更小的內存占用和更快的速度)乘法)。

大約有 2 億個素數適合 32 位,但N大多數因子應該適合 16 位(因為較小的因子更頻繁)​​並且只有大約 6500 個素數適合 16 位,所以如果您計划計算不同N多個倒數,則可以預先計算它們的倒數。

e很大時,您可以使用平方算法的運算來有效地計算p^e的倒數。 N很大時,這樣的項經常以N的素數分解的指數形式出現。

如果十進制/二進制擴展的周期大於最終浮點數,您可以截斷它。 不過,這可能會影響該方法的准確性。 我認為至少需要一些額外的數字才能獲得准確的結果(特別是由於應用了許多乘法)。

對於涉及巨大符號表示的最后乘法,您可以生成大浮點數並將它們提供給 GMP,以便它可以使用非常優化的實現(通常基於快速傅立葉變換)。


例子

為了清楚起見,這是一個小N = 307230的示例,使用十進制表示(十進制擴展的周期帶有下划線):

1/307230 = 0.0000032548904729355857175406047586498714318263190443641571461120333300784428603977476157927285746834619015070142889691761872213
              ------------------------------------------------------------------------------------------------------------------------------

307230 = 2 * 3 * 5 * (7^2) * 11 * 19

1/2 = 0.50
         -
1/3 = 0.3
        -
1/5 = 0.20
         -
1/7 = 0.14285714
          ------
1/11 = 0.090
          --
1/19 = 0.0526315789473684210
          ------------------

k1 = ((1/2) * (1/3)) * ((1/5) * (1/11)) = 0.0030
                                          --

k2 = k1 * (1/19) = 0.000159489633173843700
                        ------------------

k3 = (1/7)^2 = 0.0204081632653061224489795918367346938775510
                  ------------------------------------------

1/N = k2 * k3

對於最終的乘法,您可以使用精確算法或 GMP 的快速近似。

暫無
暫無

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

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