6

階乗計算を高速化する数学的な「最適な」ベースはありますか?

背景:楽しみのために、私は自分のbignumライブラリを実装しています。(-:これは私の最初の間違いですか?:-)。n階乗(n!)の正確な値(10進数)を出力することにより、内部表現と回帰テストで使用されるさまざまなベースを実験しています。

私のbignumライブラリが整数を表し、乗算を行う方法では、時間は内部表現n​​!の「1」ビットの総数に比例します。内部表現で2、4、8、16、2 ^ 8、2 ^ 30などを使用すると、特定の数値に対してまったく同じ「1」ビットの総数が得られます。

間違いがない限り、基数18で表される階乗(n!)は、基数10または基数16または基数19で表される同じ値よりも「1」ビットが少なくなります。したがって、(原則として)基数を使用します。 18を使用すると、10進数または2進数の2 ^ w基数または基数19を使用するよりも、bignumライブラリの実行速度が速くなります。これは、n!基数10または基数16または基数19よりも基数18で印刷した場合、より短いか、より多くの「末尾ゼロ」があるか、またはその両方です。基数18よりもさらにうまく機能する他の基数はありますか?言い換えれば、nを表すベースはありますか?ベース18よりもさらに少ない「1」ビットで?

これは、「bignumライブラリと素数判定アルゴリズムの便利なベースは何ですか?」の重複ではありません。「2と3の因子がたくさんある、大きな階乗であることがわかっている整数を処理するための最適なベース」は、「小さな因子を持たず、おそらくプライム」。(-:階乗計算を高速化していますか?おそらく他の種類の計算を犠牲にして-私の2番目の間違いですか?:-)

編集:例:

(decimal) 16! ==
(decimal    ) == 20,922,789,888,000 // uses decimal 14 "1" bits
(dozenal    ) ==  2,41A,B88,000,000 // uses decimal 10 "1" bits
(hexadecimal) ==    130,777,758,000 // uses decimal 18 "1" bits
(octadecimal) ==     5F,8B5,024,000 // uses decimal 14 "1" bits

(私は多かれ少なかれ右側の数字をコンマなしで保存し、それにメタデータのオーバーヘッドもあります)。(「ベースを増やすと、特定の数値を表すために使用する「1」ビットが少なくなる」、または「ベースを増やすと、特定の数値を表すために使用するゼロ以外の数字が少なくなる」と考える人もいるかもしれません。例は、それが常に正しいとは限らないことを示しています。)

各桁を小さな整数(「int」または「longint」または「byte」)として格納しています。数字を保存する他の合理的な方法はありますか?私のコンピュータはこれらの整数を2進数で格納していると確信しています。各「1」、「2」、「4」、「8」、および「G」の数字は1つの「1」ビットを使用します。各「3」、「5」、「6」、「9」、および「A」の数字は、2つの「1」ビットを使用します。各「7」および「B」桁は3つの「1」ビットを使用します。各「F」桁は4つの「1」ビットなどを使用します。

この値(16!)の10進数と8進数の両方の表現には、14"1"ビットが必要です。そのため、以前の計算で間違いを犯しました。すべてのnについて、nを表します。8進数では、同じ値を10進数で表すよりも「1」ビットが常に少ないとは限りません。しかし、疑問はまだ残っています。大きな階乗を格納するために必要な1ビットの数が最も少ない他の「最適な」ベースはありますか?

誰かが尋ねます:「あなたはそれらの番号をどのように保存しますか?」さて、それはまさに私の質問です-nの形の数を保存する最良の方法は何ですか!?内部的に、基数10、2の累乗の基数、基数18、またはその他の基数の数字を使用できます。どれが一番いいですか?これらの整数を1Dの数字配列として内部的に格納できますが、すべての桁を格納するには長さが必要です。100を印刷する合理的な方法はありますか?そのような配列なしで10進数で?

4

4 に答える 4

5

階乗を計算するために実行時間を最適化しようとしていて、ベースの変更が変更する唯一のパラメーターである場合、最適なベースには小さな要素が含まれている可能性があります。60が妥当な選択かもしれません。実験したい場合は、(2 ^ a)(3 ^ b)(5 ^ c)の形式のさまざまなベースを試してみます

乗算の速度を改善することは、おそらく最良の方法のパフォーマンスです。乗算にはどのアルゴリズムを使用していますか?(教科書、カラツバ、トゥームクック、FFT、...)

考慮すべき他の要因もあります。数値を10進数に頻繁に変換する場合は、10の累乗の基数を使用すると、変換が可能な限り高速になります。

何年も前に、2または3で乗算/除算を繰り返す問題を解決するために、ベース6の浮動小数点ライブラリを作成しました。ただし、特定の問題を解決しようとしない限り、より良い結果が得られると思います。階乗を最適化しようとするだけでなく、一般的にアルゴリズムを最適化することによって提供されます。

casevh

(*)プログラムが12Mhz 80286で何日も実行されたことを思い出すまで、私は最初に「数年前」と言いました。

于 2010-06-20T22:09:39.163 に答える
2

純粋に数学的な観点からは最適な基数はeですが(そして最も近い整数-3に丸めた後)、コンピューター上のbignumライブラリの実用的な観点からは、数値システムの基数としてマシンワードサイズを選択します(2^32または2 ^ 64)。はい、それは巨大ですが、bignumシステムのより高い抽象化層がチョークポイントであり、マシンワードの基礎となる計算が高速な部分であるため、自分の作業を最小限に抑えながら、CPUの低レベルの命令にできるだけ多くの計算を委任します。

いいえ、それは間違いではありません。とても良い学習演習です。

于 2010-06-21T15:59:32.187 に答える
1

「1」ビットが数字を意味する場合は、256または65536のベースをお勧めします。言い換えると、数学の目的で、各バイト/単語を「数字」にします。コンピューターはこれらの番号を定期的に処理し、そのために最適化されています。あなたの階乗は迅速になり、他の操作も迅速になります。

言うまでもなく、コンピュータはこれらと同様のベースからの大量の変換を簡単に処理します。(意図しない韻を踏む)

于 2010-06-20T22:49:25.443 に答える
1

私は数学を知っているふりをしないので、あなたがおそらく探している聖なる「最適」として私の答えを受け取らないでください。階乗をできるだけ速くする必要がある場合は、乗算はコストのかかる演算であるため、近似(スターリング近似など)を試すか、乗算の数を減らします。数値をk-baseで表すと、シフトを使用してkによる乗算をシミュレートできます。2ベースを選択した場合、すべての乗算の半分がシフトになります。他の乗算はシフトと1ビットスイッチです。数の表現で「1」の数を最小化することを目的とする場合、これは表現する数によって異なります。ベースを増やすと、特定の数値を表すために使用する「1」は少なくなりますが、注文ごとにより多くのビットが必要になります。これは、より多くの潜在的な「1」を意味します。私はそれが少なくとも少し役立つことを願っています、そうでなければ、ただ尋ねてください、私は答えようとします。

于 2010-06-19T23:49:22.597 に答える