横数列の一行は1個の剰余類に相当するが,縦数列をなんと呼べばよいのだろう?

べき剰余マトリックスで「冪剰余算の九九表」を出せるようになった.かなりおもしろくなってきた.この表には付加情報として,φやψ値,異種文字数,(n, k) などを出せるようにしたい.昨日のログではB進数表記は横数列にのみ関係するとしているが,kの剰余を取るということはk進数を考えることに相当するので,縦数列にも関わってくるのではないか?横数列はいわゆる剰余群に関連する.縦数列も同様の周期性を持っているが,この方面の周期性に関してはあまり言及されていないような気もする.横数列の一行は1個の剰余類に相当するが,縦数列をなんと呼べばよいのだろう?

冪剰余算の九九表はk-1xkのサイズで十分と考えられるが,kが素数でない場合の状況をもう一度確認しておきたいので,2kx2kのテーブルを出せるようにしてみたい.これが動くようになったらネット上で公開することを考えてもよいのではないか?ロリポでは一応クラウドが使えるようになっているので,そこに置くのが順当だろう.(使い勝手はいまいちだが,使っているうちにある程度慣れるのではないか?)

いまのところ,べき剰余マトリックスの主機能はBuildMatrixで九九表を出力することだけなので(ある範囲の包括テストも実施できるようにはなっているが),既存の久留島喜内ツールにボタンを1個追加するだけでもよい.このボタンを押すと現在のk値に従った九九表を表示するというので十分だ.これは結局,現在デバッグコンソールに出している情報をすべてGUIで出力するようにするということに相当する.

「べき剰余算の九九表」を出力する

①久留島喜内の道具箱,②べき剰余マトリックスという2つのプロジェクトを1本に統合するという方向に進もうと考えている.①は内部的には(A)循環小数の循環節周期,(B)べき乗剰余数列の周期性の2つのプロジェクトが合体したものだ.特に(B)べき剰余周期数列は②の横数列に対応するので,ほとんど同一視できるように思われる.従って,全体を内容に従って区分すると,(a)循環小数の周期,(b)べき乗剰余横数列,(c)べき乗剰余横数列の3つになると考えられる.

(a)とそれ以外を区分するもっとも大きな理由は(a)では進数表記が問題になるのに対し,(b)(c)にはそれが出てこないという点がある.結局,これらを結びつけているのは,ψ数なのではないだろうか?トーシェント関数φが関係していることは言うまでもないが…従って,このプロジェクトの主たる目的はこのψ数(剰余類群の位相)の特性を明らかにすることになるのではないだろうか?

いましばらくは2つの独立のアプリとして,マトリックスを使ってもう少し遊んだ方がよいような気もする.マトリックスのどこがどうべき乗剰余周期列に対応しているのかを見極めた方がよい.⇒grid.icoをアイコンに指定して,リリース版を起こし,タスクバーにピン留していつでも開けるようにした.このVBアプリでGridViewのテーブルを扱えるようにしてみよう.⇒大体動くようになったが,k=1000で例外が発生する.

image

列のFillWeightとは何だろう?⇒列の幅と見てよいのではないか?その合計が65535,つまり整数の範囲を超えられないということのようだ.⇒FillWeightには値が設定できるので,1を格納してやると65535まで列を拡張できる.ただし,Columns(j).FillWeight = 1のように初期化しただけでは効果がないので,ColumnAddedのイベントハンドラでセットするようにして問題は解決した.ただし,描画までに時間がかかり過ぎるので,実用範囲はかなり限られている.また,仮に65535までは描画できたとしても,我々が興味がある3, 5, 17の次に大きい完全回文数=2^16+1=65537には届かない.

行ヘッダに数字を表示したいのだが,うまくゆかない.この値は.Rows(i).HeaderCell.Value = (i + 1).ToStringで設定できるはずなのだが,効果がない.RowPostPaintイベントのハンドラで描画するようにしてみたが,やはり出てこない.ただし,行ヘッダの部分にカーソルを置くとホバリング状態で表示される「ヒント」のようにその数字が出てくるようになったので,まぁよしとすることにする.⇒いや,これはRowPostPaintイベントで描画しなくても同じだ.

257x256のテーブルを描画するのに7分以上掛かっている.この辺りが実用限界と思われるので,kがそれ以上の場合はパスすることにしておこう.⇒一応動くようになったが,出ている数字がおかしい.k=10のサンプルだが,最右列に10以上の数が現れている.

image

おかしい.再現しなくなってしまった.⇒大きいkでテーブルを作った後にk=10に戻すと再現する.i 行 j 列のとき,0< i ≦ k-1,0< j ≦ k で j の方が 1 大きいところが,反対になっているのではないか?

どうもプロジェクトを壊してしまったようだ

どうも,プロジェクトを壊してしまったようだ.マシンが落ちていたので電源オンで再起動したのだが,「修復しますか?」を無視したところ「プロジェクトが見つかりません」になってしまった.昨日はかなり修正が入っているので,復元するのは大変だ.動くものとしては,昨日の始業時バックアップしかない.⇒昨日の修正は主にテスト時のダンプに関わるもので,論理的修正はほとんどなかったような気がする.おそらく,ほとんどそのまま使えるはずだ.修正が必要な箇所が見つかったら,その場で対応すればよい.

復元できた!久留島喜内とべき剰余マトリックスという2つのプロジェクトが進行しているが,これを一つに統合したい.特にべき剰余マトリックスとべき乗剰余周期列は共通部分が多いと思われるので一つに統合できると思う.①循環小数の周期数列と②べき乗剰余周期数列を対置する形に整えるのが分かり易いと思う.最初は,これら2つを完全分離して別々のタブで操作できるようにしてみたい.かなり大掛かりな工作になるが,どうやればよいだろう?別のフォームを作って,そこにパーツを個別に移動するというのが一番安全であるような気はするが,同じフォームにタブを載せてそれに移動するということは可能だろうか?

べき剰余マトリックスに関しては,GridViewを使ってテーブルを直接表示できるようにしたいのだが…GridViewを使うとすれば,それ自体を1個の独立したフォームとした方がよいのではないか?べき乗剰余周期数列ではB^K%Nという式が使われている.これに対し,剰余マトリックスはI^J%Kという構成だ.うまく(意味のある)すり合わせができるだろうか?Nというのは任意の整数でかなり大きな数になる.というか,巨大数を想定しているが,Kはたかだか整数範囲に収まることを予定している.最終的には巨大数を用いずにすべて剰余演算として整数範囲で計算が完結することが目標となるが,まだ,その段階にはほど遠い.

いや,ちょっと勘違いしていたかもしれない.B^K%Nというのは,画面上のN, B, Kという設定を転用してBが基数となるようにアレンジするためのボタンだ.小数の循環節はB進数表記を基準とする循環だが,マトリックスの周期には進数は関わりがない.PRP(Power Residue Period)には進数は関わりがないので,マトリックスと完全に同一平面にあると考えられる.2つのアプリを比較しながら,もう少し考えた方がよい.マトリックスというのは,いわば,小さな土俵であり,外部世界における計算をすべてこの小世界の枠内に収めることができるという原理だ.土俵というより,リング(環)と呼ぶ方がより適切かも知れない.

φからkを推定することは可能だが…

循環節の周期をkとして,kがφの約数であることは確かなので,φからkを推定することは可能だが,一意に決定する決め手が見つからない.ResidueFuncは「対象数nのべき乗の k による剰余を計算し剰余列の周期を返す」関数なので,剰余周期からなにか言えるのではないかと思ったのだが難しい.ResidueFuncは対象数nと除数kからnのべき乗剰余の周期列を返すようになっているが,kを固定した場合にはほとんど同じ値が返ってくる.つまり,n^bとb^nの区別が付かない.ResidueFuncは時間を消費する関数なので暫定的に探索範囲を2kからkに削減して動作させているが,いまのところ特に問題は起きていないようだ.

n=123456789でb=63のとき,InvertFuncの出口で停止した.fixedとkがともにゼロになっている.これは検定に失敗したことを意味する.途中まではfixed=1 k=17664 keta=17665で来ているのだが… いや,出口までその値がキープされている.MakeDecimalStringもこの値で処理されている.どうも,なにか割り込みが入ってしまったような気配だ.nestcountは1だ.処理中に画面上のパラメータを操作してしまったのではない?処理中はあらゆる入力を禁止するようにするしかない.⇒修正したが,まだ現象は起きる.⇒共有出口ですでにその値になっている.ループカウントオーバーしているためと思われる.

ループカウント上限が32767になっている.これは,FindCycleLengthでk値を決定できることを当て込んだ措置なので,その支援がなければ解けないということを意味する.⇒バッファサイズを倍量にしてエラーは回避できるようになった.⇒いや,変化していない.

▲InvertFunc初期化完了の当たりでカーソルがデフォルトに戻ってしまう.どこかで強制的にデフォルトに設定しているのではないか?⇒ValueChangedでカーソルを設定するようにして解決した.⇒いや,解決していない.この2回目のInvertFuncはどこから起動されているのだろう?⇒初期化完了のところで改めてカーソルを設定するようにした.⇒それでも効かない!初期化完了のところで「ボァン」のような警告音が出るのはなぜだろう?無効な値が入力されたときのような音だ.

Your Daily Epsilon of Math Calendar で始めて解けない問題

FBの数学物理etc談話室に投稿しているYour Daily Epsilon of Math Calendar で始めて解けない問題が出てきた.設問側のミスということも考えられないではないが,正解が28のところ,14という数字しか出てこない.誰もコメンを付けてくれないので,自力で解くしかないが,いまのところ,見通しは立っていない.

15桁くらいまではそこそこ動くようになったが,検定に失敗している模様だ.num=12345678901234 b=63でfixed=0, k=0になっている.失敗はn=123456789012から始まっている.ループカウントオーバーはもっと前から発生しているが… これは当然だ.いまのところ,InvertFuncで決める以外にkを決定する手段がないのだから,ループから落ちれば当然値は不正値になる.バッファを小さくすればもっと小さい値でも発生する.n=12345678で発生した.b=63のときの正しい答えはk=17664だ.この数字はφの約数の中に出てくる.従って,なにか判別する方法があれいば,効率的にkを決定できる可能性はある.

ResidueFuncには動作制限が掛かっていない.冒頭で剰余を最後まで計算しようとしているので,とんでもない時間が掛かる.max=k*2={24691356}だが,まだ i=21652 までしか進んでいない.最初にすべての剰余を計算しておく必要はあるのだろうか?kというのは循環周期で,この値は除数の値だ.

20桁の12345678901234567890のPrimeTestで落ちる

障害が発生している.20桁の数値12345678901234567890のPrimeTestを実行して,MakeDecimalStringで落ちる.b=2. nnstr = New String(“0″c, fixed – 1) + “1”で落ちている.fixedが巨大数になっている.maxfixed を使うようにして解決したが,今度はInvertFuncで停止する.途中で打ち切りになっているため,kが計算不能でゼロのままだ.ψの値が得られていないため,このままでは検定を続けることができない.b=61ならば計算できる.b=60では計算不能となる.φからψを推定する方法はまず,ψが計算可能でなくてはならないが,その条件はbとnが互いに素であることであると思われる.bが素数であればほとんどの場合,この条件をクリアできるが,bが合成数の場合にはこの方式ではψを得ることができず,ψをkに転記することもできない.

1/nの循環桁数はBに依存する.仮にこれをk=K(n, b)のように関数化したとき,既知のbとkの値から別のb’におけるk’の値を推定できるだろうか?ψ関数には周期性があるという指摘がある.⇒確かにある種の規則性は認められる.たとえば,n=1234の場合,b=2~64まで変化させたときに出現するk値は{154, 616, 77, 56, 308, 88, 44, 11, 28, 14…}のようにかなり特徴的な数字の集まりになっている.しかし,完全な周期性というところまでは認められない.

An Efficient Factoring Algorithm by Repunit Number Methodで述べているψ関数の周期性というのは,y=b^x mod n という関数の周期性だ.この関数は明らかにψ(n, b)の周期を持っている.これはある意味当然のことだろう.というのは,y=b^ψ≡1 mod n であり,%nが1になるということは,その周期が繰り返されることを意味しているからだ.従って,この事実はψないしkを推定するためにはなんの足しにもならない.仮に周期桁数kが何らかの方法で決定できたとしよう.その値が実際周期桁数を表す数字であることを示すことができるだろうか?

それを行うためには結局kを求めるInvertFuncの計算を実行するしかないのではないか?いや,kの値がわかっていればこの計算をもっと簡略なものにできる可能性はあるような気がする.たとえば,べき乗と除算をステップ動作するのではなく,一括実行するようなことが考えられる.このようなことは可能であるような気がするので,kを得られる方法があればなんとかなると考えてみよう.

kがφを割り切れることはすでに確定しているのではないか?現在ψを求める計算として行っている手順はむしろkを求める手順と考えるべきではないだろうか?⇒多分,この考え方は正しいと思う.であるとすれば,その値が循環周期を与えるものであるということが言えればよいのではないか?循環周期を示すためには,べき乗剰余が2つのポイントで一致することが示されればよい.これは循環小数の生成ではなく,整数演算の範囲で考えられそうな気がするのだが…

多分,この考え方は正しいと思う.つまり,べき乗剰余と循環節周期は基本的に同じ事柄の二面に過ぎないと思う.試してみよう.たとえば,n=1234, b=64, k=77のとき,b^k mod n = 64^77%1234≡618で,かつ,この冪剰余の周期は{618, 618}つまり,周期1の循環になっている.この618というのはべき乗剰余で,rep%k+1と一致する.このrepという数は,DivideRepunit(b, k, n)で求めた数で,b進数でk桁のレピュニット数のnを法とする剰余と考えられる.この意味ではこの数はかんり重要なパラメータと考えてよい.

ここまで分かると,kを決定できる方法を得たのとほぼ同じではないか?「B^K%N」というボタンを追加してResidueFuncを使った検定を行うことにした.ResidueFuncは1/Nの循環周期を求めるInvertFuncの逆関数とも言うべきもので,Kに周期桁数を与えると,この関数の戻り値が1であることが確認できる.これを使ってKの値を決定できるだろう.

8桁の数値12345678をInvertFuncして,ループカウントオーバーで停止した.⇒桁数制限を掛けているのだから当然だ.停止しないで処理を続行するようにした.

すでにφ→ψ転換は完全に完了しているように思われる.GCD(n, b)=1の場合でψが取得できないというケースは発生しなくなっている.PsiFunctionの中ではこの処理の剰余計算をModPowによって実行しているが,これをPowとDivRemに分割すると多大な時間消費が発生してしまう.また,このループの中でResidueFuncを実行しようとするとほとんどハング状態になってします.従って,PsiFunctionは現在の論理で閉じるものとし,ResidueFuncはInvertFuncの中で使うことにする.ResidueFuncはべき乗の剰余を取っているので,多分ModPowを使うように改造できるのではないかと思う.⇒いや,そうもいかない.ResidueFuncでは最初に剰余配列を生成してから,繰り返しが起きるのを待っているので,べきと剰余が同時に実行されることはない.

ダメだ.ResidueFuncが1を返してくるというのは決め手にはならない.確かに,周期数がφの約数の中に入っていることは確かだが,そのうちのどれかを決める決定的な手掛かりがない.特に固定部の終端が決まらないというのは問題なのではないだろうか?周期が確定するまでは固定長は決定できない.なにか妙案はないものか?

ブラッシュアップのフェーズに入る

そろそろブラッシュアップのフェーズに入ったと考えてよい.⇒まだ,未整備の機能がある.出力の保存機能だ.ディスクボタンをオンにした状態では出力をすべてファイルに保存することになっているので,それを決めなくてはならない.ファイルは一時ファイルとして保存先を指定せず,かならずデスクトップに作ることにしているのだが,ファイル名が問題だ.一番簡単なのはファイル名固定とすることだが,そうすると,複数のアプリを起動したとき,問題が発生する可能性がある.まだ,仕掛けてないからだろうか?特に問題は発生していない.ファイルの取り合いが生じたら,一方を保存オフにすればよいのではないか?まず,機能を整備してからその辺りはチェックすることにしよう.

それより,保存がオンになっているのかオフなのか見ただけでは判別し辛いという問題がある.一応影を見ればオン・オフは見えることになっているのだが…FlatStyleをFlatにしておくと,背景色を変えることができる.これがよいのではないか?StreamWriterを使っているが,システム全体でOutStreamというものを1個だけ使って,これにすべて書き込むようになっている.書き込む地点では個別に

If saveflag Then OutStream = New StreamWriter(DeskTopDirectory + “\PrimeTest.txt”, False, UTF16)

を実行するようになっているが,ストリーム出力関数を一つ作って統合した方がよい.ストリームのオープンクローズは保存ボタンの押下ないし,アプリの起動・終了時のみとするのでよいのではないか?ファイルをCloseしないと実ファイルに書き込みされなかったのではないだろうか?ボタンのオン・オフとファイルのオープンクローズは別に扱った方がよい.起動時には既存ファイルを破棄してつねに新規ファイルをオープンでよいのではないか?ただし,この方式だとファイルの競合の問題が出てくるかもしれない.⇒おかしい.ファイルがまったく生成されていない.⇒ディレクトリ名とファイル名の間に”\”が入っていなかった.⇒ともかく,一応できた.ファイル名は「TotientFunc.txt」とする.

確かに,アプリが一つ立ち上がっているときには競合が発生するため,エラーになる.このアプリは複数並列実行できることが求められているので,保存ボタンのオン・オフでオープン・クローズすることにしよう.ただし,そうなると上書きでは前のログが完全に消えてしまうので,追記でオープンする必要がある.この方式の問題はファイルがどんどん大きくなってしまうという点だ.ユーザはその点に気を付けて,ときどきファイルを削除する必要があるということになる.まぁ,それでもよいのではないだろうか?

実装した.ストリームをどのアプリが持っているかを確定するために,OutStreamがNothingであるか否かで判定しようとしていたが,ストリームをCloseしても,DisposeしてもNothingにならないことが分かった.明示的にNothingを代入することで動作するようになった.この問題は一応これで片付いたのではないかと思う.さて,これからが問題だ.どの方向に進むべきかを決めなくてはならない.目標は,出力情報をもう少し整理して,一般解放できる程度にまとめることだが,そのためには,どのような情報を収集すべきかが決定されなくてはならない.要は,何を知りたいのか?ということがまずわからなくてはならない.

ψ値を求めるとき,現行ではn-1の因数から推定し,この方法で検出できない場合にはψの定義に戻って1から探索するという論理になっているが,①φから推定する方法があるのではないか?②ψ値を決定できない場合とはなにか?どういう条件の場合にそれが起きるのか?をまず,調べておこう.ψはつねにφを割り切るとなっているが,それでよいのかどうか?これは,(φ, ψ)=ψとなることを意味する.(φ, k)=kであることは検証されていて,ψ値がある場合には,ψ=kとなることも確認されているが,(φ, ψ)=ψとは必ずしも言えないのではないか?これに答えることは,結局,②に答えることではないだろうか?

もう一つ,③Composite Criterion(合成数の基準)というのがある.let n=35 and b=2, then y(2,35)=12 as 212=4096=1 mod 35, and y(2,35) = 12 = 2*2*3 and n = 5*7 = (2*2+1)*(2*3+1).という話なのだが… 要は,nの因数はψから合成可能ということのようだが… 逆に考えると,nの因数を{f1, f2,…f_k}として,f_i-1はψの約数であるということになる.言い換えると,(1)ψ値が分かっていれば,ψの約数セット{d1, d2,…d_m}から,nの素因数が(d_i+1)によって割り出せる,(2)nが素因数分解できれば,その因数からψの因数を推定可能ということではないだろうか?最終目標がnの素因数分解であるとすれば,まずψを決定することから始めなくてはならないのだが…

nの素因数分解は出ているので,ψの約数セットからnの因数列を出力するというのは考えられる.ψが決定できる条件はnとbが疎(互いに素)であることである.nが素数であれば,bがnの倍数でない限り,ψは決定できる.nとbが疎の場合には,m=n-1の約数から推定可能と言ってよさそうだ.

b=1の場合,ψ=1となっているが,ψ=0ではないのか?b=1では逆数の小数は後者関数のような形式になるので,循環桁はゼロとなるはずだ.2023/04/26では「基本的にψ=k=gcd(φ, k)になると考えられるが,b=1はそこでψ≠kとなる唯一のケースと考えられる.また,このとき,gcd(φ, k)=gcd(φ, 0)=φとなるため,三者がすべて異なる値を持つという特殊ケースになる.」としているのだが…⇒これはやはり,0とすべきではないだろうか?また,gcd(φ, k)=(616, 0)=616としているが,これも0が正しいのではないかと思う.⇒そのように修正した.

今後本システムでは,aとbのいずれかがゼロのときは gcd(a, b)=0 であるとする.また,b=1 のときの循環桁数とψはいずれもゼロである.

nとbが疎の場合でもn-1から割り出せない場合はある.n=1233の場合,n-1=1232=1,2,2,2,2,7,11で約数は20個もあるが,どの組み合わせからもψは生成されない.n-1の約数から推定可能な場合とは,nが素数の場合に限定されるのではないか?⇒ほぼ確定ではないかと思う.また,ψが求められる条件をnとbが疎として間違いないのではないか?

現行では素数の場合には「P」というインジケータがオンになるようになっている.その隣に「PR」というインジケータがあり,これはbがnの原始根であることを表す標識である.b^n-1 ≡1 mod n でψ=n-1のとき,bはnの原始根であるという.つまり,e<ψではb^e≡1 mod n が成立しない場合である.原始根というのはnとbの関係であるが,どのような場合にbは原始根となるのかを知りたい.おそらく,bが素数である場合には必ずそうなるのではないかと思われるが,そうでない場合もあるのだろうか?⇒bが素数なら必ず原始根になるという訳ではない.ψが定まらない場合には当然そうなる.いや,ψが決まり,bが素数であっても原始根にならない場合はある.

k=ψだから,k=n-1つまり,循環桁数最大の場合と考えられる.このとき,固定桁は1となっているので,k+f=nとなっている.「bが原始根で素数でない」という場合もある.n=1231, b=24, ψ=1230,b=30, 33, 34, 42, 48, 54, 57などいくらでもある.それでは,nの原始根というのは一つしかないと言えるだろうか?多分それは言えるのではないか?いや,言えないような気がする.素数n=1231に対し,原始根となるbには{3, 23, 24, 30, 33, 34, 42, 47, 48, 53, 54, 57, 61,… }のように無数にある.もちろん,ψはすべて同じ1230だ.

これらの循環節はすべて異なっていて,おそらく巡回置換にはならない.例えば,b=3では循環節に0が多数現れるが,それ以外では疎らにしか出現しない.というか,bが異なるのだからそもそも字母が同じではない.なぜ,このような数を原始根と呼んでいるのか?理由はよく分からない.原始根を別の言い方をすると,φ=ψ(n, b)となるようなbとしてよいのではないか?原始根は素数に対してしか存在しないのではないか?⇒これはまず,間違いないと見てよい.実際,φ=n-1となるのは素数の場合に限定されるからだ.Bが素数であるか否かをインジケータ表示してもよいのではないか?⇒対処した.

n-1からψを推定するための条件としてnが素数であることを仮定したが,反例がある.n=4, b=53でψ=1では53^1≡1 mod 4だが,nは素数ではない.それ以外にも,(n, b, ψ)=(9, 53,2), (26, 53, 1),(27, 53, 2),(28, 53, 3),(39, 53, 2),(45, 53, 4),(52, 53, 1),(351, 53, 2) など無数にある.おそらく,nとbが互いに素というのは必要条件であると思われるが…

11桁の数値12345678901→リターンで算術演算オーバーフローが発生した.PSIの計算中に起こっている模様だ.⇒GCM関数の引数がIntegerになっていた.⇒動作するようになった.

PSIを再探索で相当な時間が掛かりそうだ.12345678901を因数分解すると 1857 x 14405693 となる.一方 φ=12331292352 として得られているのだから,ここから出発するのが早いのではないか?まず,整数Nを因数分解して,その約数のリストを出力する処理をルーチン化しておこう.⇒GetDovosorsとした.Psi()の代替関数としてPsiFunctionを立てた.大体動作するようになったが,大きな数を処理するとバカになって,画面がまったく更新されなくなる.小さい数に戻しても戻らない.

なにかフラグでも立っているのではないだろうか?nestcountが上がったままになっている.InvertFuncの中でDoEventsを実行しているため,キーイベントが入ってしまうのだろう.⇒ValueChangedの間はvalueボックスをdisableにして操作できないようにしてみた.この他,Bとnotationも操作禁止にした方がよい.いずれにしても11桁のvalueを処理するのは時間コスト的に不可能と考えるしかない.循環節文字列を表示できる限界を超えて求めるのは意味がない.表示文字列は表示できる範囲までを計算して,打ち切りでよいのではないか?ψはすでに計算済みなので,桁数にはそれを借用すれば済む.

φからψを割り出す手法に関しては実装完了して動作しているが,nとbが疎でない場合にはこの方法ではψを得ることはできない.従って,ψをkに転記することもできない.そうなると,結局,InvertFuncの重い処理を実行するしかないということになる.nの因子からψを計算するという手は通用するだろうか?試してみる価値はあると思うし,いずれやらなくてはならない.ただし,この計算はBを選ぶ可能性がある.つまり,どのようなBでも可能という訳ではないのではないか?

1234567890123を対象値として,MakeDecimalStringで例外が発生した.⇒maxketaがIntegerになっていた.その他にもcountとsupがIntegerになっていた.⇒この数の循環桁は20570320500もある.200万桁を超えている.

▲20桁の数値12345678901234567890を処理して,MakeDecimalStringで例外が発生した.いや,今度は動いている.PrimeTestを実行して落ちる.b=2で落ちたようだ.

昨日仕掛けたテストがまだ走り続けている

昨日仕掛けたSeedTestがまだ走り続けている.対象数は560330000で,1~この数字までの検定を行うという仕掛けだ.現在n=522670の辺りを走っている.きびきびとした動きで気持ちよい.完全に安定動作するようになったと言えそうだ.まだ対処必要なところは多々あるが,おおむね仕上がりに近付いていると言ってよい.とりあえず,ここで一端打ち切って先に進むことにしよう.

Seed Testに限ってQの値が変化するのはなぜか?これは,quotientという名のテキストボックスだ.⇒Divisionで更新している.この関数ではgcm(n, b)も更新している.この関数は,divisor.TextChangedとValueChangedから呼び出されている.このような仕様になっているのは,このツールを電卓代わりに使って剰余計算できるようにしたいという動機による.現在はこのツールを主に剰余演算に使おうとしているので,むしろ,one shotのときのみ更新されるようにした方がよいのではないか?あるいは,値が変更されたときには,oneshotを実行するようにしてもよい.⇒テキスト入力で自動更新ならone shotボタンは不要になる.それでよいのではないか?Divisionも廃止しておこう.

べき乗剰余周期検定でもパラメータの変化を実時間表示してみようと思ったのだが,変化が速過ぎて読めないのであまり意味がないということになったので,現状のままとする.これでほぼ実装は完了したのではないだろうか?出力の内容は未整理のままだが,これは必要に応じておいおい手を入れてゆくしかない.しかし,リリースするとなれば,簡単な取説は必要になるだろう.少し,長時間ランニングさせてみたいのだが,その際にチェックすべき点があるだろうか?

一応,現時点で5つのテストが主要機能として残ったことになるが,それらのテストの要点は何なのかも明らかにする必要がある.もう一つ,過去に作ったコードで仕様から外されているものがあるが,それらで何をやろうとしていたのかも調べる必要がある.まず,それをやっておこう.②PrimeTestClickの中でコメントアウトされている処理として,①InversePowerというのと,ModuloMultiというのがある.これらはなにものか?どちらも,InvertFuncと同じパラメータを返しているので,同じ機能の別バージョンとも考えられる.

InversePowerはnとbを与えられてk,fixed,Rを返す関数と考えられる.値を返すとしたらそのパラメータはbyrefでなくてはならないが,古い版ではグローバル変数で返していた可能性もある.InversePowerは古いコードなので,PFactorを使っている.ただし,これはチェック用でPFactor(b) = bを検査しているだけだ.PFactor(b) = bというのはbが素数ということだろうか▼マークを付けているのだが…この関数の手法はInvertFuncと基本的には同じだが,RTもITもQTも使っていないかなり単純な仕掛けだ.つまり,剰余が0になるか,1になる場合しか見ていない.多分,この関数はすでにお役御免なのではないだろうか?

ModuloMultiというのはもうちょっと複雑な関数だ.この関数ではn-1の因数分解をやろうとしている.この関数ではいくつか配列を使っている.nが奇数の場合のみ処理の対象とし,n-1の約数を配列Fに格納している.また,約数の個数をfとしたとき,2^fのサイズの配列E=を生成して,約数の積のようなものを格納している.これは結局,n-1の約数の積としてψを計算しようとしているのではないだろうか?どうもちょっと読みきれないが,Psiで返す値と比較してみればなにか分かるかも…

どうも,この関数は仕上がる前に放棄されていたのではないだろうか?簡単に配列オーバーフローが発生してしまう.Fという配列はサイズnの配列として生成されているが,約数の個数がそれを超過してしまっている.どうも,PFactorが壊れているような感じだ.n=123なので,n-1=122=2*61で約数は2つしかない.PFactorは一番小さい約数を返す関数なのでxを対象数として,x-1から割り始めて割り切れればその値を返すようになっている.この動作は間違ってはいないような気がするが…PFactorの動作は間違っていない.Q=2となった後,2÷2=1が格納され,その次に,Q=2をその1で割って2を返している.

このループはQ>1の間はループするようになっているので,いつまで経っても停止しない.つまり,PFが1に達した時点で終了していなくてはならないところだ.一応動作するようになったが,まだエラーが出てくる.どういうことを考えているのかよくわからないが,UというULOngに2のべき乗の値を格納している.このべきが615という大きな数になっている.2^615は10進で186桁というとんでもない数だ.

exという数は約数の積の形になっているのだが,Uという数を作って何をしようとしているのだろう?どうも読みきれないところだが,ろくなことを考えていなかったような気がする.おそらくここで考えていたことは,すべてを2進ベースで考えるということだったのではないだろうか?いずれにせよ,想定外の状況にはまってしまっていたように思われる.これ以上追求しても意味がないように思われるので,中断してとりあえず,廃棄ということにしておこう.

Prime Testにはn-1というのがしきりに出てくる.ちょっと調べてみよう.現行論理ではn-1の約数からψを割り出しているので,n-1\ψは当然割り切れているはずだが,amariが生じたときには◯を表示するようになっている.というか,ほとんどのケースで◯になっている.これはどういうことだろう?n-1という数はかなり重要な数なので,その約数を表示してみたい.n-1をkで割った余りは表示されている.

確かに,n=123でn-1=122=2×61だから,10で割れば2余ることになる.それではこのψの10という数はどこから出てきたのか?nとBは互素なので,(φ, K)=ψ=Kになっているのだが…いや,この値は計算で得たものではなく,探索によって得られたものだ.ともかく,この辺りはもう少しじっくり調べる必要がある.

ψ数をn-1の約数から直接求めることができるようになった

ψ数をn-1の約数から直接求めることができるようになった.かなり,おもしろくなってきた.ただし,この方法が適用できるのはnが素数の場合に限定される.実際,13681では解けたが,13680は解けない.まず,ψが0になってしまう上,kを適用してもb^k=1 mod nが成立しない.この辺りの事情をもう少し詳しく知る必要がある.Psi=0になってしまうということはψの値が得られていないことを意味する.これはb^e≡1 mod nという数字が存在しないことを意味するのだろうか?それとも計算できなかったというだけなのか?

それほど大きな数でなければ,全数チェック可能なはずだから,試しておくべきだろう.⇒13680の場合は,やはり出て来ない.13679はもしかして素数なのではないだろうか?確かにそのようだ.13679は素数で,循環桁数は6839=ψとなっている.nとn-1はある種の相補的というか双対的な関係になっているような感じがする.

nとbが互いに素であることはψ数の定義の中に入っている.であるとすれば,bを素数に限定するということは意味があるかもしれない.64より小さい最初の素数は61なのでこれを使ってみよう.13680は61の倍数ではないので,GCMは1となるはずなのに,36という数字が表示されている.これはかなりおかしい.1231と3のGCMが1230と表示された.どこかで間違っている.

GCMの入っているテキストボックスはTextBox6だ.リネームしてgcmtextとしておこう.GCMは,①DispParametor2とDivisionで書き込まれている.DispParametor2ではφとkのGCMを計算し,Divisionでは引数のaとdのGCMを書き込んでいる.後者の場合は,aはnum0の値,dはdivisorの値であることを仮定している.DispParametor2でやっていることは,ψがφを割り切ることの確認のためと思われるが,GCMの値をここで書き換えるのは適切ではない.とりあえず,割り切れない場合は停止するように暫定修正した.

nとbが互いに素というのはψを計算する上での絶対条件のように思われる.どこかにこの値を常時表示しておく方がよい.ψの横に表示するようにした.ψの値が計算できないときには,テキストボックスの背景色を白抜きとしてテキストが抜けていることを強調するようにした.これでnとbのGCDが1とならない限り,ψが計算できないことがはっきりした.また,それ以外の場合は循環桁数=ψとなっていることも確認された.φと循環桁数は常時計算可能であり,かつψはφをつねに割り切るとなっているので,循環桁数がつねにφを割り切るかどうかも見ておきたい.φの因数分解を表示するか,ないしφと循環桁数のGCMを出しておくことにしよう.⇒(n,%), (φ, k), (n, b)の3GCMを並べて表示した.

b=1のとき,MakeDicimalStringで落ちる.小数コードの生成で後ろにMAXNUMSTRING=36文字分の糊代を作っているところで,MAXNUMSTRING – countが負になったため.⇒チェックしてゼロ以下の場合には実行しないようにした.

b=1というのはかなり特殊な場合で,ペアノの公理の後者関数のような形式になっている.このとき,b^ψ=1^1=1となり,いかなるnに対してもψ=1となると考えられるが,1進数の1/nは0.000…1 のような固定桁のみの数字になるため,k=0となり,ψと一致しない.gcd(n, b)=gcd(n, 1)=1でψが有効となるケースは基本的にψ=k=gcd(φ, k)になると考えられるが,b=1はそこでψ≠kとなる唯一のケースと考えられる.また,このとき,gcd(φ, k)=gcd(φ, 0)=φとなるため,三者がすべて異なる値を持つという特殊ケースになる.

かなりわかり易くなってきたのではないかと思う.k=0となるのは,nがbの約数になっている場合に限定されるのだろうか?

n=56033411, b=64でSeedTestボタンを押して例外発生.⇒OverFlowがどこかで発生している.算術演算のオーバーフローだ.SeedCheckでDim dmax As Integer = BigInteger.Log(k) / BigInteger.Log(2)が整数範囲を超えている.⇒kが0で,0の対数を計算しようとしていた.⇒対処した.

n=560330000, b=64でハングしてしまった.PSIを再探索で深掘りになっている.⇒一応抜けてきた.(n, b)=16でnとbは互いに素ではないため,ψは決定できないということらしい.(φ, k)とkはともに4250で一致している.つまり,(φ, k)=kはつねに成立するのではないだろうか?ただし,b^k≡1%nは成立しないので,それだけでkを決定することはできない.(n, b)≠1%nのときには,おそらくPSIの再探索というのは意味がないのではないかと思う.⇒再探索しないようにした.

基数64で1234567891の逆数の計算を完了

一晩走らせているが,n=1234567891の逆数の循環節長の計算がまだ終わらない.進捗率10%というところだ.nが素数の場合には桁数がn-1になることが多いので,おそらくこの数もそのくらいの桁数になるのだろう.ψはφを割り切るので,φ=n-1のときは,n-1を因数分解してみれば,その約数の候補を列挙することができる.1234567890 = 2 * 3^2 * 5 * 3607 * 3803 なので,1234567890/2=617,283,945 となるから,この数字まで達したら残りは1234567890しかないことになる.しかし,そこまでやらなくても,事前にその検査をすれば少なくとも桁数だけは実際に計算しなくても割り出すことは可能だ.

まず,以下の論理を導入する必要がある.そのためには,①n-1を因数分解し,②n-1の約数を列挙して,そのそれぞれについて(小さい方から),n^d=1 mod kとなるかどうかを検査し,③成立すればその数をψとする.これを実装するのはそれほど難しくないのでやっておくべきだろう.循環節を実際に出力する論理は,テキストボックスのサイズ内で打ち切ればよい.これなら,かなり高速に結果が出せるのではないだろうか?厄介なのは,nが合成数の場合だ.nが合成数の場合にはn-1はψでは割り切れないと予想されている.いや,この予想は,ψではなくφについてのものだ.n-1とψの整除関係に関してはもう少し調べる必要がある.ただし,合成数の場合には比較的簡単に実計算からでもψが計算できるはずなので,とりあえず上記の論理を適用するのはnが素数の場合に限定しておくとしてよい.

基数を64に設定して,1234567891の計算を完了した.桁数は68587105でn-1の1/18.n-1=1234567890=2 * 3^2 * 5 * 3607 * 3803 なので,2X3X3で割り切っている.任意基数を使えるように拡張することも考えたが,まだ調べることもいろいろあるので,しばらくは基数最大64という現行版でゆくことにする.ただし,上記の修正は入れておくことにしよう.まず,約数のセットを作り,それをソートして小さい順にテストするというところから始めなくてはならない.ただし,この方法が適用できるのはnが素数である場合にのみ限定される.

nが合成数の場合にはn-1はφでは割り切れないと予想されている.逆に,ψの素因数の一つをpiとして,pi-1はnの素因数を約数として持つという予想がある.ともかく,nの素因数分解から始めなくてはならない.素因数分解ルーチンは実装されているが,文字列を出力するだけなのでもう少し扱い易いように改造する必要がある.nの約数の最大個数maxはnが2のベキになっているときと考えられるから,max = log_2(n) でよいはずだ.⇒因数分解の部分はできた.あとはこれを使ってテストするだけだ.最初に約数を列挙してそれを昇順にソートする必要がある.これが意外と厄介だ.約数の個数は計算できるようになった.約数の列挙は再帰を使うのが順当だが,ループで間に合わせた.

個別の約数は高さ一律の木になるので,木を巡回する手順が必要になる.これは再帰関数を作って呼び出すしかないのではないか?⇒配列に書き込むのは,最後の葉になっているノードで行うことにする.葉ノードはつねに末尾ノードだから,そのノードがしかるべき位置に書き込めばよいのではないか?あるいは,飛び飛びになることは分かっているのだから,すべてのノードで必要な計算をして値を書き込むというのでもよいのではあるが,たとえば,13680の約数は60個あり,指数が4, 2, 1, 1であったとすると,最初の数では,60/5=12個に同じ数を書き込むことになる.次の数では60/3=20に同じ数を書き込み,それ以外では60/2=30に同じ数を書き込むことになる.

ただし,それをどうやって書き込むかが問題だ.1段目では12個づつ同じ数を連続的に書き込めばよいだけだが,最後の段では一つ置きに書き込まなくてはならないだろう.かなり厄介な計算になりそうな気がする.そのノードの下にあるノードの数がわかれば,よいのかもしれないが,それより再帰の方が間違いないのではないだろうか?どちらがより効率的であるかは一概には言えない.掛け算の回数はまとめて書き込む方が少なくて済むはずだが,ノード数の計算などの余分な計算が入る.ノード数の計算はそれほど難しくはないはずだが,書き込みのループを構成するのが面倒なのではないか?いや,それほどではないような気もする.やってみることにしよう.

まぁ,なんとか整った.あとは,PSIのテストを行うだけだ.ψ数というのは,b^e ≡1 mod n となるような最小のeと定義されている.⇒できたようだ.少なくともn=13681では正しい値が計算されている.