PowerResidueFuncの論理は間違っている

昨日の修正でいくつかの項目が表示できなくなっている.まず,それらを補充しておこう.TextBox14に表示していた剰余周期数列が出なくなったのは,ResidueFuncからPowerResidueFuncに切り替えたためだ.とりあえず,ResidueFuncで行っていた出力を切り出して関数化しておこう.DispResidueCycleという関数を起こした.一応動いているが,どうも間違っているような気がする.⇒かなり厄介な話になってきた.ResidueFuncが生成する剰余列とPowerResidueFuncが出す剰余列はまったく別物だ.これでは使い物にならない.ということは,PowerResidueFuncの論理が間違っているということになる.

もう一つおまけに,FBの数学物理談話室の問題に応用しようとしたところ,Kの範囲が狭すぎて使い物にならないことが分かった.少なくともInt64の範囲までは扱えなくてはならない.また,K≧2となっているが,1でもよいことにしたい.というのは,単純にN^mを求めたい場合があるからだ.⇒Kの最大値をNと同じ9223372036854775807に設定して動作するようになったが,剰余周期数列の計算が収束しない.これは打ち切りでよいのではないか?

どうも完全に仕上がったのではないだろうか

一応循環単位数Uを表示できるようにはなっているが,まだだいぶ問題がありそうだ.というか,この過程で肝心の桁数の計算もおかしくなっている気配がある.総合的な点検が必要だ.

N=3,B=10のとき,Uが空になっている.固定部1循環部1という数字で,k循環節も/A:0.3&0/のようになっている.1/3=0.3333なのだから,/A:0.&3/でなくてはならないはずだ.str3の表示も0.3000…のようになっているので,間違いだ.つまり,固定部0,循環部1でなくてはならない.⇒とりあえず,強引に収めた.

N=7, B=10のとき,固定部5, 循環部6でUが700000となっている.これは明らかに間違いだ.1/7=0.1428571428571428…で循環節は142857でなくてはならない.つまり,固定部は0のはずだ.⇒IT(j)=0を見る,つまり,初項に一致した場合はfixed=0で抜けるようにした.

N=14, B=10でnUが9999990となるが,これはどういうことか?⇒循環節Uが714285となるのは正しい.714285✕14=9999990となるので,計算は合っている.N=15の場合も,U=6で6✕15=90となり,末尾に0が付いてくる.N=24の場合,U=6でRepunitは144となる.1/N=0.0416666666…なので固定部は.041の3桁,循環部は6で1桁となるから,U=6で正しい.従って,6✕24=144という計算は合っている.N=28のとき,U=571428となっている.これも数字は合っている.従って,571428✕28=15,999,984は正しい.

一見した限りでは正しく動作しているように思われる.B=10の場合には,①nUが99999…のようなレピュニット型になる場合,②99999…の末尾に0が付く場合,③それ以外の3パターンに区分できる.これらのパターンが発生する条件については,別途調べることにして先に進もう.

PowerResidueFuncで新旧不一致が発生している.N=7, B=10でValueChangedPro→ResidueFuncPro(n, K, False)を実行しているところだ.⇒明らかにこれは改訂版の方が間違っている.従来版では周期4だが,改訂版ではゼロになっている.⇒初項をRT(max)に格納するというのは余分だったようだ.この論理を外して動作するようになった.

どうも完全に仕上がったのではないだろうか?⇒MakeRecursionUnitというのはかなりコストの掛かる処理だ.Uが巨大数になってしまう.N=12345678のとき,桁数は335616もある.10進100桁でも十分大きいのでとんでもない数だ.⇒Nが10桁まではそこそこに出せるようになった.11桁ではさすがに時間が掛かる.現行ではMAXARRAYSIZE = &H7FFFFFFとしている.InvertFuncで処理する数の上限を決めた方がよい.⇒除数が10進で10桁を超える場合はエラーで戻るようにした.

これで12桁くらいまでは処理できるようになったが,FactoringSubで呼ばれるTotientFuncがネックになっている.この関数のアルゴリズムは十分効率的ではあるが,対象数が大きくなるとかなり厳しい.TotientFuncは素数判定のために使っているのだが,何かもっと効率的な方法はないものだろうか?⇒現状では12桁というのが限界のように思われる.過去(2023/04/28)には20桁のサンプルをテストしていたこともあるのだが…何が原因でこれほど重くなってしまったのか?⇒Bの大きさにも関係している.Bが素数である方が有利に作用する.

現在時間が掛かっている処理は,φの約数を取り出す処理なので上限を設けるか打ち切ってもよいのではないか?⇒あれこれやりくりしてかなり速くなった.こんなものではないだろうか?

循環単位数(recursion unit)Uは計算できるようになった

循環単位数(recursion unit)Uは計算できるようになった.これにnを掛けたnUがレピュニット(の整数倍)になることを確認する.この数はB進で表記したいのだが… notationにはnをB進表記した数が表示されている.⇒ConvertNum2Stringという関数があった.⇒計算はできるようになったが,話が少し違うような気がする.B=10の場合,N=3→9,6→36,7→999999,9→9,11→990,12→36,13→9999990,14→9999990,15→90,17→99999999999999990,18→90,19→9999999999999999990

N=7を除いて,すべて999…の末尾に0が付いている.中には6や12の場合のように,9の倍数ではあるが9の並びではない数字さえ出てくる.⇒明らかにこの末尾の0はゴミと考えられる.N=21, B=10のとき,MakeRecursionUnitはfixed=1, keta=6で呼び出される.このとき,QTには{0,4,7,6,1,9,0,0,}のような値が入っている.このfixedの1は冒頭の0のことで,そこから桁数分取ると476190になる.桁数は間違っていないと思うので,fixed=1というのが間違っているのだろう.つまり,476190ではなく047619なのだと思う.これは結局,InvertFunc → PowerResidueFunc がまた間違っていることを意味する.

ごく初期のバージョンを除いてすべて間違っている.正しく動作しているのは,「久留島喜内 2023-04-16」だけだ.このバージョンではまだRTはハッシュ化されていないので,R = RT(j)ならば,単純にfixed = jとしている.しかし,動作がかなり違うような気がする.RTには{1, 10, 16, 13, 4, 19}が入っていて,R=1を検索しているため,j=0でヒットしている.これに対し,現行版ではR=RT(0)を見ているため,R=10を検索する動作になっている.現行版ではRは{10, 16, 13, 4, 19, 1, 10}のように発生しているので,初項10から始まることになる.

旧版と現行版ではかなり大きな違いがある.旧版ではxがnを超えるまではパスする仕組みがある.いや,そもそもRT(0)が違うのではないか?確かにそれはあるが,RT(0)に1を書き込んでも変化しない.いずれにしてもRT(0)に対する書き込みには疑問がある.RTはハッシュテーブルだから,ハッシュ値が0になるということは当然あり得るのに,そこに先住者がいるというのはかなりおかしい.少し考え直す必要がある.

少なくとも現行版ではRT(0)を考慮する必要はない,というより,考慮するのは間違いだと言える.もし,初期値をどこかに格納する必要があるのなら,RT(0)ではなく,むしろRT(max)だろう.ここならどこからも届かない安全な置き場所だ.しかし,現行論理ではいきなり If R = RT(0) Then となる.かなりまずいと思う.

べき剰余数列と循環小数節の統合

べき乗剰余数列の周期を求める計算と循環小数の循環節長を求める計算ではどちらも剰余演算になるのでアルゴリズム的にはかなり類似したものになっている.これを統合することは可能か?というのが目下の課題だ.すでにかなりのところまで煮詰まってはいるのだが,まだ完全に解決したとは言い難い.強い類似性はあるが,相違する点も大きい.実際,真逆の計算なのだから違って当然なのだが,それを一つの計算で間に合わせようというところにかなりの無理がある.ただし,もしそれができれば,この2つの計算の「関係」がかかりクリアに見えてくるのではないかという期待がある.

PowerResidueFuncというnの逆数の循環周期を求める関数をべき剰余列にも適用するというのが目標だ.逆数1/nの循環周期では基数Bのべきを法nで除した剰余RにBを乗ずるという計算,つまりR_i=R_(i-1)*B mod H を反復することで周期を決定しているが,除算の対象を剰余Rではなく,R_i=B^i mod K のように切り替えることでほぼ同等の計算が実現できるという考え方だ.問題はRが反復していることの判定に微妙な差異があるという点だ.その前に一つよくわからない例外が発生した.

SeedTestClickで例外が発生する.K=7でi=24のとき,num0.valueにi値を書き込むところでオーバーフロー例外が発生する.しかし,書き込もうとしている値は24という小さな数であり,整数範囲を超えているなどのことは考えられない.何が起きているのか訳が分からないというのが実情だ.num0の上限値はInt64の最大値を指定しているので,9223372036854775807という十二分に大きな数字だ.⇒障害の真因は不明だが,最終的にこのパーツを作り直すことで問題解消した.

大体動くようになったが,nがKの倍数の場合に従来論理と一致しない現象が残っている.剰余数列は{0, 0}のようになるが,現行ではこれを固定部0,循環部1と解釈している.しかし,これは少しおかしいような気もする.循環小数としてみると,1/7を7進表記した場合には0.1となり,固定部1,循環部0となる.つまり,小数ではゼロが発生した時点で打ち切っている.剰余数列もそのような解釈でよいとすれば,固定部1:循環部0というのが正解になるような気がする.

たとえば,N=6,K=8の場合,剰余周期は{6*,4*,0,0}で固定部2,循環部1となっているが,これは固定部2,循環部0でよいのではないだろうか?だとすれば,剰余周期の表示も{6*,4*}のようになるはずだ.これは言い換えれば,統合版の論理の方が正しいということになる.もし,これでよいとすれば差し替えて終わりということになるのだが,従来論理を見直して一応修正しておこう.従来論理はResidueFuncから切り離して,FindOutCycleという独立の関数になっている.

FindOutCycleでは最初に剰余数列をストレートに生成し,末尾項から遡って末項の出現位置を探索,そこまでのステップを「周期」として確定した後,今度は初項から末項までドロップ項を探してカウントしているが,いくつかの点において問題がある.今の場合は,剰余数列には0項しか入っていないので,それを周期カウントに含めるのは問題がある.逆にドロップ項の検査では0項は対象に含まれていない(これは正当かもしれないが…)末項が0の場合は循環しないと断定してよいのだろうか?それは,当然だろう.従って,末項が0の場合は非ゼロ項が末項になり,そこから初項までが固定部ということになる.今の事例のようにすべてゼロ項の場合は固定部1ということになる.⇒対処した.

K=8 N=2のとき,新旧で固定部の不一致が起きた.現行では2,改訂版では3になっている.剰余数列は{2*,4*,0,}で末尾の0は循環には入らないから,固定部2桁というのが正しい.従って,改訂版の論理が間違っていることになる.しかし,これは末尾の0を固定部に入れてしまうという考え方もあるのではないか?というのは,完全に割り切れる場合には{0*}という固定部が生じるのは避けられないと考えられるからだ.言い換えると,末項の{0}は明示的に固定部に含めるという考え方でよいのではないか?もし,それが通用するのであれば,改訂版が正しいので,現行版を修正する必要があるということになる.FindOutCycleを修正してこの件は解決したが,まだ不一致が残っている.

K=12,N=2のとき固定部の不一致が生じる.改訂版では2,現行版では1になっている.循環部はどちらも2だ.剰余数列は{2*,4,8,4,}のようになるので,固定部は1というのが正しい.従って,現行版の方が正しく,改訂版は修正が必要ということになる.⇒一応動くようになったが,確信は持てない.もう少し整理する必要があるような気もする.ともかく,少し動かしてみよう.

どうも大体仕上がってしまったようだ.パラメータを一定範囲で変化させる包括検定を実施しても停止しないようになった.もう少し整理できそうな気もするが,先に進むことにしよう.試してみたいことが2つある.①小数循環節を整数化してその性質を調べる,②小数循環節に関連するレピュニット数を生成してその性質を調べる,の2点だ.まず,①から取り掛かることにしよう.⇒Recursion Unit U は10進数として表記する.(B進数として表記すると1/Nの循環節とダブってしまう).

レピュニット数の議論ではoriginatorという用語が出てくる.

B=1の場合の逆数の進数表記をどうするか?

N=7, B=1で起動するとInvertFuncで例外が発生する.QTなどの配列のRedimをPowerResidueFuncに移してしまったため,ここではQTにアクセスすることはできない.暫定的にQTのRedimはInvertFuncで実施することにしておく.これで例外の発生は抑制されるようになったが,問題は残っている.B=1の場合の逆数の進数表記をどうするか?という問題だ.2023/04/26には以下のような記述がある.

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)=φとなるため,三者がすべて異なる値を持つという特殊ケースになる.

とりあえず,これでよいということにしておこう.実装もそのようになっている.さて,このPowerResidueFuncを使い回しできるかどうか?が問題だ.つまり,この関数を使ってResidueFuncを実現できるかどうか?言い換えれば,InvertFuncとResidueFuncはどこが共通で,どこが違うのかを明らかにする必要がある.これらが一種の逆関数であることは明らかだが,剰余演算として実装されているところに共通点がある.しかし,もちろん,大きな違いがある.一方の対象がNであるとして,他方の対象は1/Nだ.これを共通処理化可能だろうか?

どうもかなり難しそうだ.その前に一度ResidueFuncをPowerResidueFuncのように抽象化してみてはどうか?そうすれば,もう少し見えてくるものもあるのではないか?

N=3, B=10で固定部1になっている.これはおかしい.1/3=0.333なのだから,固定部0でなくてはならない.どうも直近の修正で壊してしまったようだ.⇒PowerResidueFuncのループの入口にあったはずの「RT(0) = B Mod n」が消えてしまっている.RTを外部で初期化するように修正した際に削ってしまった模様だ.

ひとつ不良が出ている

ひとつ不良が出ている.n=7のとき1/nで固定部が1となっている.これは誤りだ.固定部:0でなくてはならない.10進数表記すると1/7=0.142857142857…で,循環節U=142857でnU = 142857*7 = 999999 = 9*111111となる.以下のURLによると,

An Efficient Factoring Algorithm by Repunit Number Method
http://www.aya.or.jp/~babalabo/repunit/index.html?fbclid=IwAR0HOaEACHvZ4MyWwXNk6_Dj4Tnr_BAJTjjLMKuBY3PyyhdLo61SbvqT3tY

[8′] Let p be a prime number which is neither 2 nor 5, and the recursion unit of p be U, then pU/9 is a repunit number Rn, i.e., pU=10n-1.

[8′] は証明されているので定理だが,これを拡張した [9] Let m be an integer without factor 2 nor 5, and the recursion unit of m be U, then mU/9 is a repunit number Rn, i.e., mU=10n-1.も定理である.

今のケースではn=7は素数であるから,これを満たさなくてはならない.今回はB進⇔10進の相互変換ができるようになっているので,それだけで十分だろうと思ってレピュニット関係のロジックはすべて削ってしまったのだが,ちょっと早まったかもしれない.ともかく,どこかが間違っていることは確かなので調べてみよう.循環節はTextBox5に書き込まれている.この文字列はConvertNum2Stringで生成しているが,文字列自体には誤りはない.maxfixedに入っている固定桁数が間違っている.というか,maxfixedをここで使っているのが間違っている.

少なくとも初期バージョンでは正しい値が出力されている.⇒正しく出力されるのはバックアップの中で一番古い「久留島喜内 2023-04-16」しかない.それから一つ上がると固定桁:3など間違った値が出始める.この版ではDispParametorの引数で渡されたfixed値をそのまま使っている.現行版ではMakeRecurringDecimalで渡されるfixedの値がすでに誤っている.InvertFuncが返している値が1になっている.fixed = IT(j)でIT()には,{6, 2, 1, 4, 5, 3}が入っている.IT(0)には値が設定されていない.どうも,InvertFuncの論理全体を見直す必要が出てきた.

InvertFuncで剰余が一致したときの操作が間違っている.初項に戻る場合はつねに剰余が1になっているという推定が誤りだ.RT(0)には初項の剰余が格納されているので,それと比較する必要がある.これで多分問題は解決したのではないかと思う.repunitに関する検査を追加しておこう.どこに入れればよいか?レピュニットが関係してくるのは逆数検定に限られている.Prime TestにはDivideRepunitが残っている.

SeedTestを実行して,ValueChanged文字列 str3とstr4の不一致で停止した.10新表記の場合は両者が一致する必要がある.確かに小数第12位で不一致が発生している.

“0.0714285714285714″
“0.071428071428071428071428071428071428″

N=14, B=10で起きている.714285の方が正しい.つまり,str3は間違っている.MakeRecurringDecimalで生成するstr2にも欠陥がある.これしか入っていない.”/A:0.&071428/”.str3を生成しているのはMakeDecimalStringだ.この関数はQT配列から文字列を生成している.QTに入っている値は正しい.引数でfixedとketaを渡しているが,fixedに0が入っている.これは1でなくてはならない.上の修正で初項に一致した場合には強制的に1を代入しているが,これがまずいのだろう.

固定項には0の並びが含まれる場合がある.それをどうやって判定したらよいのだろう?QT(0)=0の場合はfixed=1となるようにして逃げた.とりあえずこれで動作するようになったが,これですべてカバーできるようになっているかどうかは疑問だ.どうもうまく行っていないようだ.n=6, B=10のとき,str3=0.11111111111111… のようになってしまう.R=4でIT(j)=1かつR=RT(0)が成立し,QT(0) が0でないのでfixed=0に設定している.1/6=0.16666…なので,固定部は1でなくてはならないのだが,誤動作している.

どうも,InvertFuncのアルゴリズムは仕上がっていないのではないだろうか?InvertFuncではQT, RT, ITの3つの配列を使っている.ここではB^i mod N を計算し,剰余が一致すれば周期が閉じたと判定して,固定部長と周期を割り出すことになっている.ループからの脱出条件は,①剰余がゼロになった,②一致する剰余を検出,③中止ボタンないしカウントオーバーの3つだ.問題が起きているのは,②の周期の終端に達して剰余が一致したという場合だ.ResidueFuncではドロップ項というのを見ているが,その操作が欠けているのではないだろうか?つまり,剰余が一致したというだけでは不十分なのではないか?

それを確認するためには,QTを見て,同一Qの発生時点まで進む必要があるように思われる.⇒できたようだ.ポイントは2つ.①QT(0)=0つまり,商が立たない場合には商が立つところまで進む必要があること,②異なる商が立っていた場合には,商が一致するところまで進む必要があること.これで,ドロップ項を見なくても固定部を正しく同定することができるようになった.この論理は剰余数列の方にも使えるのではないだろうか?もし,それが可能ならロスタイムを少しでも減少される効果はあるかもしれない.ともかく,一度バックアップを取っておこう.

N=14,B=16のとき,PrimeTestで停止した.fixed > 0 And i <> fixed + ketaが起きている.10進なら1/14=0.07142857142857…だが,16進なのでどういうことになるのか… i=4でfixed=6, keta=6になっている.fixedの6というのは明らかに誤りと思われる.多分,これは正しいのではないかと思う.str3=0.12492492492492492 だとすれば,固定部1,循環部3ということになる.1+3=4=iで計算も合う.

QT(0)=1で最初から商は立っている.Qは9なので,上からQTを探して,QT(3)=9を検出し,fixed=3としている.どこが間違っているのか?⇒QT(0)が非ゼロのとき,Qを探しに行ってオーバーランしている.i の範囲を超えたときには,fixed=1としなくてはならない.なぜなら,IT(j) = 1 And R = RT(0)であるから,初項から循環に入ることは間違いではないが,循環が完成するためにはRだけでなく,Qも一致する必要があるが,周期が短いときには,初項で発生するQがまだどこにも出現していない場合がある.そのような場合でも,初項のRが一致していることは初項の次の項から循環が始まることを意味しているからだ.

これでまず,穴は全部塞げたのではないかと思う.検算を兼ねてレピュニット関係の検定を導入しておくことは意味があると思う.まず最初に冒頭に出てきたnUというのを作ってみよう.nと除数pが互いに素の場合には循環周期Uをn倍したもの/p-1がレピュニット数になるというものだ.つまり,nのbベースの循環節をUとするとき,nとbが互いに素であれば,nU=n^(b-1)/(b-1).実装されているレピュニット関係の関数を集めておこう.まず,現行バージョンには以下がある.

  1. DivideRepunit ∑B^i mod n ある桁数のレピュニット数のnを法とする剰余
  2. RepuitFunc ∑B^i ある桁数のレピュニット数を求める

オリジナルソースを見てみたが,これですべてだ.つまり,大したことはやっていない.DivideRepunit はレピュニット数が桁数で割り切れるかどうかを見ているだけだ.これはちょっと後回しにして,InvertFuncとResidueFuncで同じ論理が使えるかどうかを見ておくことにしよう.まず,InvertFuncから主要ロジックを切り出してみよう.この処理の主眼は,nとbを指定して固定桁と循環部の長さを決定することだ.

N=7, B=2のとき,PowerResidueFuncで i <> fixed + keta のエラーになった.i=4 <> fixed=2+keta=3=5.N=7は2進表記では111だが,1/7は0.00100100100…のようになるので,fixed=2, keta=3が正しいように思われる.⇒ fixed ≠ IT(j) となる場合はあり得る.今の場合がそうだ.QT(0)=0の後に0が続く場合はそのようなことが起こる.⇒このような場合には(フラグを立てて)パスするようにした.

▲n=7, B=1のとき,ValueChangedで停止した.If QT(i) > Bというエラーだ.keta=0でfixed=6だ.B=1の場合はQT()は1の並びにならなくてはならないはずなのだが… ⇒従来論理ではEXITINVERTFUNCでQTの補充というのをやっているが,暫定的に止めてある.また,B=1, N=1の場合にはPowerResidueFuncを通さないでストレートにEXITINVERTFUNCに飛ぶようになっているので,QTが前の状態のまま残留しているのだろう.⇒どうも,これはかなり難しい問題だ.

φ(N)とψないし@(剰余数列周期)のGCM(φ, @)を見てみたい

φ(N)とψないし@(剰余数列周期)のGCM(φ, @)を見てみたい.φ(N)と#(循環節周期)のGCM(φ, #)は#と完全一致することが確認されているので,それと比較するというのが動機だ.@はResidueFuncで計算されているので,そこで出力できるだろう.テキストボックス名はTextBox15だ.ResidueFuncを呼び出しているResidueFuncProというラッパがある.どちらを使ったらよいか?

ResidueFuncを使えば抜け目なくすべての場合に出力される.ResidueFuncProを呼び出しているのは,ValueChangedPro,modulo3.Click,GoButton,TestMatrixの4箇所だけだ.ただし,これら以外の場所ではValueChangedProが呼ばれているので,実質的な効果は同じなのではないか?@を出力しているのはResidueFuncProなので,ここが適切だろう.いや,ResidueFuncProではφにアクセスできない.やはり,ResidueFuncを使うしかない.

いや,ResidueFuncはφ(N)を持っていない.ただし,ResidueFuncが呼び出しているPsiFunctionでは内部でφ(K)を使っている.GCM(φ(N), @)ではなく,GCM(φ(K), @)なのではないか?しばらく,実験的にResidueFuncProの中で両方を計算して比較してみることにしよう.TextBox15とTextBox3だ.⇒やはり,GCM(φ(K), @)の方だ.こちらなら100%一致する.Build Matrix は外部にテーブルを1個表示するというのが本旨なので,画面上のパラメータは不変としてよいのではないだろうか?⇒TestMatrixで画面を更新している.⇒対処した.

そう言えば,「素数積」という話もあったが,どうなっているのだろう?素数積というのは以下のような話だ.

「べき乗の剰余数列で①nとkが互いに素の場合には,落伍項は生じない.②kが素数の単純な積である場合にも落伍項は生じない,③kの素因数がべきになっている場合には落伍項が生じる.」

確かに言えているようにも思われるが,それほど単純な話ではない.kの素因数にべきが含まれている場合でも,ドロップする場合としない場合がある.(N, K)=1の場合は確実にそうなるが,.(N, K)=Kの場合もドロップは発生しない.というか剰余がゼロになって,周期1になる.(N, K)の中にべきがある場合でも,ドロップする場合としない場合がある.たとえば,N=32, K=24で(N, K)=8では{8, 16}のように@=2でドロップなしだ.N=34, K=24のときは(N, K)=2で{10*,4*,16,16}のようにドロップ2が発生する.

Seed TestとResidue Testは合併してもよいのではないか?そもそも,Seed Testと言っているものの趣旨がよく分からない.Seed TestではInvertFuncを実行している.Residue TestではResidueFuncを実行しているので,やっていることは真逆だ.Prime Test ではBを変化させながら,InvertFuncを実施している.これはInvert Testと基本的に同じだ.ただし,Prime Test ではDivideRepunitというのを実行し,さらに,計算結果を解析してマーク付けを行っている.Invert Testでは,DispInvertとDispRecurringDecimalを実行して循環節を表示している.PrimeTestとInvertTestは合併してもよさそうな気がする.

▲循環節の固定部の切り出しが間違っている.n=7のとき,1/7=0.142857142857だから,固定部[0],循環部[6]{142857}でなくてはならないが,固定部[1]となっている.

プーチンの夢を見てしまった

またプーチンの夢を見てしまった.これで三度目だ.前の二篇はかなり苦しそうな様子だっが,今回のは結構おもしろかった.大学構内のような雰囲気の路上で出会い,声を掛けたら付いてきたので一緒に喫茶店に入った.わたしは何か数学上のプロジェクトを抱えているみたいで海外から届いた分厚い論文を若い連中と輪読することになっていた.プーチンは前に座っていた若い学生に何か謎掛けのようなことを問いかけ,彼がうまく答えられなかったので「こいつはダメだ」みたいにつぶやいた.彼がわたしの隣に座っていた肥満女性の腰に手を回して踊るフリをすると周りから「プーチンはもてるんだよね~」などの声が漏れた.

画面は大体固まったのではないかと思う.あと追加すべき情報としては,φの約数数列とべき剰余数列がある.φの約数はψや循環小数の桁に関係する.GCM(φ,循環節桁)は循環節桁と一致すると予想されている.ψはB進数表記には直接関わりはないが,べき剰余数列の桁には関わりがあるはずだ.ともかく,値を出力してみよう.以前はφの約数の代わりにN-1の約数を出そうとしていた形跡があるが,Nが素数の場合にはφ=N-1となるので,φの約数とした方が適切であると思われる.φの約数はφを計算するところで計算できるだろう.ただし,φ数は必ずしも対象がNとは限らないので,その切り分けが必要になる.一般の場合にはPhi()の代わりにTotientFuncを呼び出すようにしておこう.

というか,DispParametorで更新するだけで十分なのではないか?DispParametorはValueChangedから呼び出されているので,脱落はないはずだ.いや,これはGCM(φ,#)に関係しているので,その位置で更新すべきではないだろうか?GCM(φ,#)はTextBox6に書き込まれる.これを行っているのは,ValueChanged→DispParametor2だ.ただし,DispParametor2ではφ(N)は扱っていない.ValueChangedには,φの約数を格納するTextBox2に書き込みしている論理が存在する.これは既存論理でN-1の約数を書き込んでいるところだ.これをφに書き換えればそのまま通用すると思われる.⇒書き換えた.

循環節桁数#はゼロになる場合がある.このとき,gcm(φ,#)=φとなっているのだが,これでよいのだろうか?gcm(x,0)=xという定義になっていたような気はするが…我々の定義では,0は公約数とはなり得ない.なぜなら0で除することはできないからだ.このため,関数GCM()ではゼロが返るようになっている.この点は一貫すべきと思われるので,最大公約数を求めているすべての箇所でGCM()を呼び出すように書き換えておく必要がある.⇒BigInteger.GreatestCommonDivisorをGCMに一括変換しておこう.これで,gcm(φ,#)=#が言えるようになる.※⇒「なぜなら0で除することはできない」というのは論理的に少し弱いので,この件は保留とする

最後はPowMod Cycleだ.この値はResidueFuncでデバッグコンソールに出力していたはずだ.この値を書き込む場所はTextBox14だ.numstrをそのまま書き込むようにした.

剰余計算の表示がかなりおかしい.計算がまったく合っていない.どこか壊してしまったような気配だ.⇒再現しなくなってしまった.⇒指数が入っていた可能性は考えられる…

Kの素数インジケータがおかしい.PrimeKという名前が付いたチェックボックスだ.⇒テキストボックスを数値ボックスに変えたのに,テキストから読み出しているためだ.num0,pow, Bもチェックした方がよい.⇒すべて点検した.問題なさそうだ.

Nのφ数と循環節の桁数のGCMを表示しているが,φとψのGCMも出してみたい.原始根ではψはφを割り切ることになっていたはずだが,一般の場合にも公約数というのはあるはずだ.(φ, #)と#は完全に一致している.同様にψと剰余数列の周期@は(原則的に)完全一致する.

大体思ったような動きになってきた

ResidueFuncで画面出力できるようにしておこう.⇒かなり大量のダンプが出るが,あとで削ればよい.All Matrixでも出せるようになった.かなり時間が掛かる.砂時計が出ていない.bottomlineも実行されていない.⇒処理と描画を切り分けたい.

Nの素因数分解がまったく表示されなくなった.⇒何気に止めていた.DispParameterに移しておこう.⇒TextBox8に書き込みしているところが消えている.どこかでうっかり削ってしまったようだ.⇒補充した.

Nが素数のインジケータも落ちている.⇒DispParametorでは引数でφを受け取っているが,おそらく,対象が違うのだろう.安全のため,関数内で計算するようにしておこう.

ResidueTestではNの因数,φ,ψなどが更新されていない.All Matrixでは何も(Kも)更新されない.⇒時間がかかり過ぎるのでダンプを減らす.⇒Kは更新されているが,ψなど変化しない.φはDispParameterで更新している.⇒TestMatrixでnum0.textを上書きしてValueChangedを実行するようにした.⇒φやψは更新されるようになったが,cycle値がまったく変化しない.⇒TestMatrixの中で直接更新しておこう.

PrimeTest, InvertTestで(φ, K)が変化するのはおかしい.この値はDispParametor2で更新している.φ(N)とketaのGCMを表示している.ketaというのはInvertFuncの戻り値で剰余数列の周期を意味する.この値は暫定的に#としてラベル付けしておこう.

PowerResidueでN=123, K=7のとき,17 % 7 → {3, 2, 6, 4, 5, 1, 3, }と表示されるのはおかしい.123%7=4であり,商が17になっている.ResidueFuncが2回呼び出されている.確かに,DispModPowではQを対象数としてResidueFuncを実行している.⇒DispModPowの中でResidueFuncを実行するというのは,つい最近の修正だ.しかし,明らかに誤っている.DispModPowはValueChangedの中で呼び出されているので,それ以外の場では不要なのではないか?

確かにValueChangedでは剰余数列は更新されない.ResidueFuncの呼び出しが必要だ.ValueChanged→ResidueFuncの部分をルーチン化しておこう.ただし,一つ問題がある.TestMatrixではdrop()とcycle()という配列を管理している.これは,サイズがKの配列でドロップ項数と剰余数列周期を格納している.これはDumpMatrixの中で使われている.modulo3.Clickでは包括的な検定になっているので,配列を整備してもよいが,GoButtonは単発なのであまり適切ではない.Kが更新されたときつねにRedimするようにしておけば,実害はないと思われるが…

多少余分なコストは掛かってしまうが,それが分かり易いのではないか?⇒ResidueFuncProとして実装することにする.ResidueFuncProではs1という配列も使っている.これはTestMatrixの中でRedimしている.この論理は外してTestMatrixに戻しておこう.⇒どうも,やはり,ValueChangedだけでは不十分だ.ValueChangedの代わりにResidueFuncProを呼び出すしかない.しかし,それも若干やり過ぎのような感じもする.ValueChangedは8箇所から呼び出されている.

この意味では,確かにValueChangedの中からResidueFuncを呼び出すという方が理に適っている.ResidueFuncProを呼び出しているのは,今のところModulo3.ClickとTestMatrixだけなので,これらからはValueChangedを呼び出さないとすればよいのだが… ⇒GoButtonが落ちていた.それでも3箇所だ.⇒ValueChangedProというのを作って,ValueChangedとResidueFuncProを呼び出すようにしてみた.

上の3つを除き,ValueChangedをすべてValueChangedProに置き換える必要があるかどうかは,吟味する必要がある.剰余数列周期に影響しないパラメータの場合は,ValueChangedのままの方がよい.少なくともBの書き換えは影響しないはずだ.⇒結局,ValueChangedは5箇所に残ることになった.大体思ったような動きになってきた.もう大きな誤りはないのではないか?ブラッシュアップの段階と言ってもよい.

最終的な着地点も朧気ながら見えてきた

かなりいい感じになってきた.最終的な着地点も朧気ながら見えてきた感じがする.Let’s keep it up!

SeedTestでハングしてしまった.検定範囲は,N-123→100でK=7, B=13.かなり状態が悪い.ブレークボタンで停止することもできない.リモートセッションなどやっていないのに,こんなパネルが出た.

image

一旦終了→再起動で今度は問題なく動作した.ValueChangedで「Kが素数で原始根にならない」というのが出ている.調べておこう.n=123 K=7 ψ=40で起きている.ψがn-1という値を取った場合を「原始根を検出」として,インジケータをオンにしている.原始根は,尽数列になる場合と重なっているが,K=7の場合ではN=3と5がそれに相当する.N=5ではψ=4となり,原始根オンになったが,3ではそうならない.3の場合のψ値は1だ.どうも話がまったく合っていないような気がするのだが… PsiFunctionの引数の順序を逆にしてみたところ,ψが決定できないようになってしまった.どうも,ここの論理は見ているものが逆なのではないかという気がする.何を基数とし,何を指数とするかというところで混乱しているのではないか?

いろいろと手当しなくてはならないところばかりだが,まず,デバッグコンソールに出している情報をすべて出力ペーンに出すようにしよう.⇒いや,それも少しやり過ぎのようだ.やはり選別して出した方がよい.位数と原始根の関係を整理しておこう.「素数pに対して,r^x≡y mod pのとき,y=p-1となる最小のxをrのpに対する位数という」,また,原始根については,「r~r^(p-1) mod pがいずれも1でないようなrをpに対する原始根と呼ぶ」とされる.この定義によれば,素数pに対し,r^(p-1)≡1がつねに成立するため「原始根とは位数がp-1であるようなもの」であると言える.

たとえば,3は7に対する原始根であり,法7に対する2の位数は3である.明らかに現在の実装はどこかで間違えている.ψをφから求めようとしているが,このφはφ(N)ではなくて,φ(K)でなくてはならない.PsiFunctionの中で自前で計算するようにした.⇒正しく動作するようになった.多分,これが一番安全な策ではないかと思われるので,引数から外しておくことにしよう.

N=4, K=7のとき,ValueChangedにおいて,tot <> psisu2で停止した.φ=2,ψ=3.ψ=n-1=3だが,φとは一致しない.これはφ=n-1となるのはnが素数の場合に限られると考えられるので,ここでは成立しなくてよいのではないか?⇒トーシェント関数の対象が間違っていた.

原始根が現れたときにはインジケータをオンにするようになっているが,合わない.N=3はK=7の原始根であるのにインジケータがオンになっていない.⇒これは判定を誤っている.見るべきはψ=K-1なのに,ψ=n-1で判定しようとしている.確かにこれは誤りだが,もう一つ誤りがある.φをnから計算している点だ.ここではφ(K)を見なくてはならない.PsiFunctionでは引数を廃止しているのでこの問題は解消しているが,外部にはまだ誤りが残っている.⇒対処した.

N=5,K=7のとき,DispParametor2において,keta > 0 And gcm <> ketaで停止した.keta=4,gcm=2という値が入っている.fixed=1でnnstr=”/D:0.2&7A52/”だ.B=13になっている.これは多分上記でφ(K)を取るようにしたことの反作用だと思う.後半部ではおそらくφ(N)が求められているのだと思う.⇒対処した.これでおおむね正しく動作するようになった.InvertFuncでは2つの相反することをやっている,というところがポイントだ.

現行ではResidue Testでは出力コンソールに何も表示されない.デバッグコンソールに出しているものを出力するようにしておこう.