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