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では正しい値が計算されている.

メモリを使い切るとハング状態になる

FFFFを16進表記で65535と変換したまではよいが,そこでハングしてしまった.何かまだバグが残っているのだろうか?⇒notationを書き直したときには,一文字入力するたびに,Nを再計算して更新するようになっている.しかし,FFFFまで入力するとその後はカーソルが画面内に入らなくなってしまう.なにかバックグラウンドで作動しているような感じだ.convertflagというのがある.ConvertClickとConvertNum2Stringで使われている.ConvertClickはNをB進表記に書き直す関数で,ValueChangedから呼び出されている.これは,B進表記を更新した際の文法エラーを訂正するためのものだ.ConvertNum2StringはDispInvertとMakeRecurringDecimalから呼び出され,BCD変換を実行してbcdNumberを返す関数だ.

非常に奇妙なのはFFFFの4文字が入ると制御が効かなくなるという点だ.カーソルを置いたままで連続入力すればFFFFFのように先に進むこともできる.FFFFでは966桁になるので,かなり長くはなっているが処理できないというレベルではない.bcdNumberは大域変数のバイト配列だが,生成時に長さを指定していないので,ReDimする必要がある.この操作はToBCDの中でやっている.

どうも,MSは大きな計算をやろうとすると,それを並列実行化しようとしているのではないだろうか?どうも何か余分なことをやろうとしているような気がするのだが…⇒リリース版をショートカットから実行した場合にはこのような現象は起きない.一応アプリとしては正常動作しているように思われるので,これでよいことにしておく.⇒いや,どうもまだおかしなところがある.他のことをやっていて,元の画面に戻ろうとしたら真っ白になっていた.しかし,これもちょっと放置しておいたら元に戻った.⇒78645を入力してリターンで砂時計になってしまった.それほど時間が掛かる処理とは思えないのだが…それも一応収まった.7864という十分小さな数でも砂時計になる.確かにInvertの計算はコストが掛かるものではあるが…8桁くらいは楽にこなせていたような気がするのだが…123→リターンで砂時計だ.5桁しかない.

メモリ使用量がほぼ満杯状態になっている.16GB搭載で15.7GBとほぼ使い切っている状態だ.確かに,このアプリでは大きな配列を常駐させているので,立ち上げただけでメモリを消費するというのはあり得る話かもしれない.VSを落としても,まだ13GB使っている.やはり,現行方式には少し無理があるようだ.どうも,配列はその都度取るしかないのではないか?大きな数を扱うときにはそれなりの時間が掛かるのはやむを得ないが,小さい数を扱うときでも砂時計では問題がある.

どうも,アプリとして実行するより,開発環境で走らせた方がまだ速いような気がする.1234567891の結果がまだ出て来ない.どうすればよいのか?結局,inverseは表示されなかった.多分これは打ち切りになったものと思われるが,桁数も0, 0のままになっているというのが解せない.処理中はテキストボックスに入力できないようにするというのも必要かもしれない.とりあえず,すべての配列をサイズ未指定として,使うときにRedimするように書き直してみよう.

カーソルをChangeCursorを使ってプッシュ・ポップするように変更した.これでカーソル形状が途中で戻ってしまうという不具合はほぼ根絶したのではないかと思う.1234567890では逆数の循環小数表示は出ないが,1234567891なら出る※.ただし,素数のカラー表示が出なくなってしまった.いや,処理完了しているのに制御が戻らない.メモリの使用量も上限に張り付いたままだ.おそらく,外部に置いてもあまり意味がないのだと思う.むしろローカルで処理終了でリリースするようにした方がよい.⇒※これは話が逆だ.1234567890では計算完了していてその結果が残っているというだけだ.

今度は,1234567890でも逆数表示できた.結局,メモリ不足が不良の原因だったと考えられる.アイドリング時のメモリ使用量は7.5GBだ.QTとbcdNumberは外部にある.関数間の受け渡しがあるためだ.この程度はまぁよいのではないだろうか?かなりリラックスした感じがする.1234567891は素数ではないのではないか?実際,1,3,3,3607,3803,のような素因数を持っている.かなりまずい.確かにこの数は素数だ.どこかで処理を壊してしまっているような気がする.軽くなったのはよいが,誤動作するようになってはお終いだ.

なぜ,こんなことになってしまったのだろう?FactoringSubでは正しい答えを出している.もう一度計算したら正しい値になった.これはどういうことだろう?かなりまずいような気がする.素数インジケータもオンになっている.しかし,処理完了しているのに,メモリが解放されていない.カーソルはデフォルトに戻っているが,テキストボックスには入らない.まだ処理が完了していないのだろうか?メモリ上限に達するといずれ動作不良が起こるのは避けられないような感じだ.カーソルもいつの間にかビームになってしまっている.

1234567891はまだ一度も最後まで計算完了したことはなかったのではないか?2023/04/22のログでは,素数であることは確認されているが,「れ以上続けても埒が明かないので,一度中断しておこう」で中断している.iの現在値は{44396982}でnは{1234567891}だから,やはり,状況は同じだ.素数であることと循環節の長さの関係は調べておく必要がある.MAXARRAYSIZEを当初より16進一桁分だけ落としてみた.メモリ使用量は上限の半分くらいから徐々に増加する傾向にある.これでパスできなければ,この数は越すに越されぬ関門,つまり処理能力の限界ということになる.

QTというのは,もっと小さいテーブルでよいのではないだろうか?QT(i)<nだが,QT(i)<Bでよいはずだ.だとすれば,BYTE配列でもよいのではないか?実際,それをコード化したものが循環節なのだから…

DispParametorでは,nが素数であるか否かをφ数がn-1であるか否かで判定しているが,これは誤っている.nが素数ならφ(n)=n-1となるが,その逆は必ずしも成立しない.いや,違うかな?「φ(n) = n − 1 if and only if n is prime」は成立している.Lehmerのトーシェント問題というのは,「合成数nでφ(n)がn-1を割るようなものは存在するか?」という問題だ.⇒φ→ψという方向を考えるしかなくなってきた.

B進小数表記に関してはほぼ完全になったのではないか

かなり進んだ.B進小数表記に関してはほぼ完全になったのではないかと思う.というか,チェックしたのは10進法だけなので,B進表記のすべての動作を確認した訳ではないが,主要な論理は通っているはずだ.昨日は障害が発生したところで止まっている.続きをやることにしよう.

1234567891という数字を与えて,InvertFuncで停止する.RT(rindex) <> 0が起きている.⇒初期値としてこの数を設定して起動→どこかでハングしてしまっている.⇒どうも,Enumerable.Repeat(Of BigInteger)(0, arraysize).ToArray()で手間取っているようだ.arraysize=536608768.この数字はMAXARRAYSIZEですでに限界に達していることを示している.IT(arraysize)を生成するのにもかなり掛かっているようだ.RTとITも固定で外に出してしまった方がよいのではないだろうか?使うときには必ず初期化が必要になるので,大したメリットはないかもしれないが…

ウォッチパネルでこれらの配列の中を見ようとするとそれだけでハングしてしまうので,開けることもできない.問題が起きているのは,rindex={454561898}なので,ここだけ見ることはできるだろう.このときのRは{991170666}だ.IT(454561898)には2415という値が入っている.しかし,不審なのはRTにrindexの値が入っているという点だ.rindexを設定している箇所はこの関数の中で7箇所もある.これはかなり間違え易い論理だ.R=454561898でrindex=454561898となっている.このときは,まだRTには書き込まれていない.従って,ここに書き込むまではノーマルな動作だ.⇒すでに書き込まれていたときの空セル検出の論理が間違っている.

RTはハッシュテーブルなので,テーブルの末端まで検索しなくてはならないのにデータカウントまでで打ち切っていた.どうも10進10桁というのは,このツールの限界のように思われる.循環節の長さが十分短ければもっと小さいテーブルでもよいのだが,一般に大きい数では周期も長くなることが多いので,あまり小さくすることはできない.対象数の約数と循環節の周期には相関があるだろうか?もし,それがわかればある程度調整できるのではないか?BとNが互いに素の場合が最長になるのではないかという気がするのだが…

1234567891は素数だった.3は素数だが,循環桁数は1なので,Nが素数であるか否かと循環桁は直接結びつかないが,数字が大きくなると循環桁が伸びる傾向にあるのは確かだ.相当時間が経過しているが,まだ10%程度しかこなしていない.これ以上続けても埒が明かないので,一度中断しておこう.配列の初期化には相当の時間が掛かるので,上書き可能な配列は初期化しないことにする.RTはハッシュテーブルなので初期化する以外ないが,ITとQTは初期化しなくても動作するはずだ.

画面を処理に先行して表示するために,ValueChangedの実行をMyBase.Shownイベントが発生するまで抑制するようにした.これで,画面が開かれたときには,すでに因数分解も完了し,φなどのパラメータも表示された状態になっている.その数が素数であることも明示したい.⇒「P」というラベルのボタン型チェックボックスを新設した.

ビジー状態だと,カーソルが飛んでしまうため,STOPボタンを押すことができない.ESCキーを受け付けるようにしておこう.⇒実装した.Stopは効くようになったが(効きはあまりよくない),停止しない.⇒MyBase.Shownイベントが反復掛かってきているようだ.⇒フラグを見るようにして,一応解決.

なぜか理由はよく分からないが,RTはInvertFuncのローカル変数としておいた方が速い.ITは内部に置くとかなり時間が掛かってしまうのだが… メモリを大量消費した後のガベージコレクションのような作業で手間取っているような感じ.とりあえず,これが最速なのでこれでフィックスということにしておきたい.

N=12でエラー終了になった.stopflagをリセットしていなかったためではないか?⇒対処した.

ESCキーの効きは悪いが,なぜかStopボタンが押せるようになった.ただし,あまり効きのよいものではない.何度も繰り返し押すうちに入るという感じだ.Stopで停止した後もまだ,しばらく制御が戻ってこない.なぜだろう?走行中にブレークポイントを設定できないくらいなのだから,よほどビジーなのだろう.まぁ,これはこれ以上どうしようもない… タスクバーのアイコンを点滅させるという仕組みは完全に廃止.

加納氏の出題に応答するために,べき剰余検定の機能を少し変更することにしよう.現行ではボタンが3つあり,「n^p%k」「p=1→k」「n=min→max Test」となっているが,「p=1→k」のところを,「n^p^m m=1→k %k」とすることにする.「p=1→k」と同等動作にするためには,p=1で実行すればよいというだけだから,十分な拡張になっている.「n^p^m m=1→k %k」の動作は,まず,n^p%k=αを計算したのち,α^p%kを実行するようになるものと思われる.ただし,これだけではたとえば,

2021^2022^2023

のような計算をストレートに実行することはできないが,いまのところは,これが限界だ.しかし,2021^2023%100=41のとき,41^2023%100=21になってしまうのはなぜだろう?これでは話が合わないような気がするのだが…この辺り,動作を確認しながら少しチェックする必要がある.とりあえず,ここで一度バックアップ.

計算は完全に(wolframと)合っている.計算完了後制御が戻るまでにしばらく掛かるという現象がある.いや,今度はすぐ戻ってきた.41^2023%100という計算なのだが…再現しなくなってしまった.⇒原因は分かった.テキストボックスに入力すると即時応答しようとしているためだ.これは不要な機能だろう.いや,おかしい.TextBox1ではTextChangedを取っていない.

どうも,動作がおかしい.Button2.Clickイベントが入っているようだ.⇒ボタン名を変えておこう.modulo1, modulo2, modulo3としておく.どうも,かなり様子がおかしい.押してもいないのに,SeedTestボタンが入っている.Clearボタンも青くなっている.

One Shotを3回繰り返すと,ハング状態になる.このとき,

‘Kinai.exe’ (CoreCLR: clrhost): ‘C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.17\System.Runtime.CompilerServices.Unsafe.dll’ が読み込まれました。

などのDLLが追加で読み込まれてくるのだが…どうも,これを読み込む間コントロール喪失状態になっているようだ.上記のSeedTestボタンはClearボタンを押すつもりで押し間違えた可能性がある.どうも,まだやはり具合の悪いところがある.今度は別のDLLガロードされてきた.

‘Kinai.exe’ (CoreCLR: clrhost): ‘C:\Program Files\dotnet\shared\Microsoft.NETCore.App\5.0.17\System.Collections.Concurrent.dll’ が読み込まれました。

DLLのロード中はコントロールが効かない.ロードし終わると問題なく動作するようになる.リリース版をビルドしてみよう.やはり,同じ現象が起こる.復旧するまでの時間はかなり長い.イベントループが回らなくなっているというか,詰まっている感じ.ボタン処理を実行している間,砂時計を出すようにした.Periodicでは出力画面に書き込みしたあともまだ何かやっているようだ.

BigInteger.Pow→.Mod をModPowでまとめてやるようにして,何とか収まったようだ.modulo1は現行のままとし,べき乗の結果の大きな値を画面出力できるようにしておこう.

2021のSeedTestで停止した.「WRONG SAMPLE」fixed=0かつk=0つまり桁数ゼロという状態になっている.このテストはN=1~nをテストするもので,n=1, b=10で始まっている.1/1=1.0で固定桁数というのは小数部しか含まないので,この場合は,fixed=0, k=0となるのは仕方ない.つまり,不良ではない.

Daily Epsilon of Mathで手一杯

どうも,FBのDaily Epsilon of Mathのカバーで手一杯になっている.日めくりカレンダーなので,提出した課題は翌日には解かなくてはならない.誰かが回答ないしヒントを寄せてくれた場合はよいが,昨日の設問にはまったくコメントが付かなかった.かといって,それで放置という訳にもゆかない.そうなるとあとは自力で何とか解くしかないのだが,わたしからすると絶壁を直攀するような難事だ.昨日の分に関してはネットを探しまくってなんとか回答をまとめた.かなり厳しい.今日もまだ少し仕事が残っている.回答に補足を付ける作業だ.それをやっておかないと,あとで同じような問題に出くわしたとき,また一から同じことを繰り返さなくてはならない.⇒片付いた.今日の課題は暗算問題だから,回答を付けるものも簡単だ.ようやく仕事に戻れる.

大体まとまってきているはずなのだが,いま躓いているのは,3という小さな数だ.⇒3は正しく処理されているが,6で間違えている.fixed=0, k=1で/A:0.&1/としている.これは/A:0.1&6/でなくてはならない.j=4, IT(j)=0となっている.i=2だ.しかし,ITに0が入っていること自体おかしいような気がする.いや,違うR = RT(0)という理由でfixed = IT(j) – 1としているためだ.どうも,まだ読み損なっているような気がする.いまの場合,計算は10\6を計算するところから始まる.R=4はRT(0)とRT(rindex=4)に格納されている.⇒ようやく収まったのではないか?判定のところでR=1を見るようにして切り分けできるようになった.3や9の場合にはR=1で脱出するようになっている.これは初期状態ですでに周期に入っているということを意味するからだ.

出力が整合しているかどうかを確認する方法を考える必要がある.現行のInvertFuncのように整数化して検査すれば確実なことが分かるが,ここで浪費する時間コストを削減するために修正しようとしているのだから,もっと軽い処理でなくてはならない.倍精度で出力し,小数点以下の数字を拾い出すというのではどうか?それほど数が大きくならない限り,正確な検査ができるはずだ.倍精度をテキスト出力してそれと直接比較すればよいのではないか?比較する桁数は固定部+循環部とすればよい.ということになるとすると,MakeRecurringDecimalでもう一種類の出力を作り出さなくてはならない.つまり,普通の小数だ.それもよいのではないか?倍精度の有効桁数までの文字列を生成するというのは悪い発想ではない.double.ToString(“Exx”)で出力桁数を指定できる.しかし,これでは前方の0の部分が分からない.”Gxx”で有効桁数を指定できるが,これではやや指定があいまいだ.”Nxx”という指定が分かり易いのではないか?これは小数部の桁数を指定するものだが,指数表示部がないので,正確なポジションが分かる.

doubleの有効桁数はこんなに少なかったのだろうか?1/3を小数24位まで出力させたら,こんな数字が出てきた.

0.333333333333333314829616

16桁しかない.確かに単精度で7桁,倍精度で15桁というのが上限のようだ.decimalという整数型なら28桁まで格納できる.しかし,もちろん小数は扱えない.とりあえず,16桁まで検査できればチェックにはなるだろう.⇒いや,どうもあまり大した検査にはならないような気がする.1234567という7桁の数値を小数化したとき,固定桁が1,循環桁が68041が正しいかどうか知りたいのだが,16桁では話にならない.固定桁は”0”一桁ということになっているのだが,これを知るためには,少なくとも68041桁の次に続く数字を見なくてはならない.現在4種類の数字列を出力しているが,すでに正規化されているため,循環節の続きは出力されていない.

いや,DispInvertでは2*k桁まで見ているはずだ.ValueChangedの中でQTの内容をダンプしているが,fixed+kで打ち切っている.これをもう少し伸ばせばよい.⇒いや,QTテーブル自体打ち切りになっているようだ.中身がゼロの並びになってしまっている.いや,実際循環部の終端を検出するとInvertFuncのループから離脱するようになっているのだから,当然のことだ.これはもはや,現在の論理を信頼するしかないのではないか?QTというテーブルはQ = BigInteger.DivRem(x, n, R)を格納しているというだけだから,出口でもう少しテーブルを増長させるということは可能なのではないか?一度終了してバックアップを取ってから着手することにしよう.InvertFuncの出口を一箇所に絞りたいのだが… 一番簡単なgoto文で飛ばしてしまえばよいのではないか?

n=2でどこかでハングしてしまう.⇒MakeDecimalStringでおまけを付けているところで,k=0であるため,ループから抜けられなくなっている.⇒今度は例外が発生した.MakeDecimalStringで後ろにゼロを付け足していないためではないか?

対処完了した.完全に接続した.wolfram は循環節の長さを出せるので,比較チェックしてみよう.123456:107桁,1234567:34020桁,12345678:335616桁,123456789:6855006桁.さすがのwolframもここまでは届かなかったようだ.標準の計算時間制限を超えました…で打ち切りになってしまう.ただし,おそらく有料版なら出力できるのだろう.桁数を計算するまでは十分高速なのだが,数字列を組み立てるところでは相当な時間を消費してしまう.これはどっちみちダンプできる分量ではないので,どこかで打ち切るようにした方がよい.

まず,テキストボックスに格納できるバイト数というのが一つの目安ではないだろうか?現行ではテキストボックスは32767が上限となっているので,ここで打ち切ることにする.⇒少し削り過ぎてしまったのだろうか?Inverseのボックスが空のままだ.TextBox5だ.DispInvertを丸ごと止めているからだ.ここで書き込んでいたはずだ.inverseは入るようになったが,桁数が更新されない.これらの値は,DispParametorで出力するのが適当だろう.

123456789と1234567890の桁数が同じ数字6855006になっているが,大丈夫だろうか?6855006は内部的な上限なのではないだろうか?MAXARRAYSIZE=536608768だから,それよりもだいぶ小さい.PSIで時間を消費しているが,PHIのあと,MakeDecimalStringに入るまでのところでも時間が掛かっている.確かに,arraysizeがMAXARRAYSIZEになっている.QTのRedimを行わないようにしたら簡単に抜けてきた.やはりPSIがネックになっている.

1234567890を最後まで計算して抜けてきたが,やはり循環節の長さは同じだ.いや,これはこれでよいのだろう?後ろに0を1個追加しただけなのだから,周期が変わらないのは当然かもしれない.

▲12345678791を入力して,InvertFuncで停止した.RT(rindex) <> 0が発生している.rindex={454561898}でかなり大きな数字だ.RT(rindex) にはrindexと同じ数が入っている.かなり

InvertFuncで直接循環周期列を生成

InvertFuncの中で直接循環周期列を生成するという方式変更がまだ収束していない.⇒ようやく整理が付いたが,まだ不具合がある.2は通ったが,3で不一致が生じている.1/3=0.3333…だから,固定桁0, 循環桁1でなくてはならないのに,固定1,循環1になっている.⇒調整した.今度は4で0.2という値が出てきた.x=1から始めているので,10÷4=2になってしまう.勘違いしていた.1/4=0.25が正解だ.旧版で0.25は出ているが,訂版でQが足りない.0.20となっている.Qを格納する前に離脱しているためだ.QTはQが確定した時点で書き込みできるので,先行して格納してやればよい.

1/10で停止した.ただし,今回は訂版の方が正しい,旧版が0.0に対し,新版は0.1と正しい答えを返している.旧版にも穴があったということだろうか?7桁になるとさすがに重くなる.点滅も出ない.⇒8桁の12345678までの動作は確認した.旧版でn=10, b=10のとき,誤動作が起きる件に関しては別途しらべておく必要がある.この論理は最終的に破棄されることになるので,やらなくても構わないのだが,一応その原因は突き止めておいた方がよい.

いや,まだ12345678の処理は完了していない.ToBCDの引数のvalが配列サイズ上限の536608768を超えてしまっている.処理ではオーバーフローした分は切り捨てるようになっているようだが,最後まで実行できるだろうか?この小数は固定桁1,循環桁335616なので,改訂版なら問題なく処理できる範囲だが…⇒まだまだ掛かりそうなので一端打ち切ることにしよう.n=10, b=10の場合,ConvertNum2Stringをnn=1, b=10で呼び出して,nnstrに値が入ってこない.

ConvertNum2Stringから呼び出しているToBCDでは,val≦1では無動作で抜けている.ToBCDではvalをbで割る計算をしているので,n=1ないし,b=1では停止しないためではないか?いや,ここではこれらの値を除外する理由はないように思われる.いや,少なくともb=1ではこの論理では無限ループになってしまう.⇒b=1では抜けるようにした.これで正しく動作するようになった.

n=1, b=2でInvertを実行したら,inverseの値が消えたままになる.リターンキーで更新を実行しても埋まらない.なぜだろう?この値はTextBox5として表示されている.DispInvertでは暫定措置として,n=1の場合はTextBox5を空として離脱している.これは,n=1の場合のテキストが無闇に長くなることを回避するための措置と考えられるが,nnstr = “/” + basestr + “:1.0&/”をそのまま表示でよいのではないか?⇒大体これで収まったのではないか?いや,まだ数値が合っていない.

両方間違っている.n=123ではn=123 b=10 fixed=1 k=5 keta=6としているが,実際はfixed=0 k=6でなくてはならない.実際1/123=0.00813008130081300813008130081301で循環部は,0081300813だ.InvertFuncにまだ不良が残っている.⇒fixed = IT(j) – 1のように調整してみたが,却って悪い.たとえば,n=12の場合,1/12=0.083333だが,固定桁1, 循環1で/A:0.0&8/のようになってしまう.RT(0)を格納して,i=1の場合はfixed=0となるように調整した.

n=10, b=10の場合,fixed=0, k=0になってしまう.1/10=0.1だから,固定1でなくてはならないのだが… ダメだ.まだ合わない.n=6, b=10でfixed=0 K=1になってしまう.1/6=0.1666 でfixed=1,k=1でなくてはならない.InvertFuncの論理では,Q=x*b\n…Rを計算している.初回は1*10\6=1でR=4となる.次回は4*10\6で6…4.ここでR(0)=10%6=4なので,fx=0,k=1となってしまう.

大体合うようになったが,3の場合,fx=1, k=1 になってしまう.1/3=0.333なのでfx=0, k=1でなくてはならない.結局,3と6の切り分けがつかない状態になっている.