InvertFuncの中で直接循環周期列を生成するという方式変更

InvertFuncの中で直接循環周期列を生成するという方式変更をインプリメントしているところだが,どうも,かなり問題がありそうだ.既存コードと出力が一致しない.後ろの方が切れてしまっている.従来論理では周期列の2倍の長さのサンプルを用意してそこから切り出すようにしているが,改訂版では周期が判明した時点で処理を打ち切っているというところがまずいのだろうか?もし,そうであるとしたら,どこを修正すればよいのだろう?InvertFuncではQT()という配列に商を格納して返しているのだが,おそらく,冒頭でx≧nになるまで空回ししているところに問題があると思われるのだが,そこの論理は従来と同じなので,まず,従来論理との不一致が発生する理由から突き止める必要がある.

サンプル=1234で10進数のとき,末尾の5008103727が不足している.10桁だ.従来論理にはzerosupという処理が入っいるが,結果として出力されている数列では冒頭部分はまったく同一だ.改訂版にはこの措置は入っていないのに同一文字列になるというのもよくわからない.⇒従来論理では1/nをbのべき乗倍して整数化しているが,数値をnで割っても頭の方では商が立たないため,それを補うためのゼロ補正と考えられる.QTの中には冒頭のゼロも入っているため,同一結果になると考えられる.論理的にはこれでよいのではないだろうか?従って,問題は末尾に並ぶゼロの列ということになる.

やはり,問題はfixedではないだろうか?rcount=kであるということは,fixedの分は配列に格納されていないということになる.いや,rcountは上がっている.むしろ空回しのとき,fixedが上がってない方が問題なのではないだろうか?fixedはR=0のとき,x>=nの場合に限りインクリメントされている.いや,ちょっと違うかな?fixedの値は出口で決めているので,インクリメント操作は受けていない.k=i – IT(rindex)という値を返している.keta=fixed+kで,ketaが配列サイズに等しくなることを期待しているのだが…配列サイズはrcountだが,現在はこのテーブルはハッシュテーブルとして使っているので,必ずしも前詰めされていない.

InvertFuncは最近ハッシュ値を使うように仕様変更しているが,この修正に抜けがあるのではないか?rindexから後方しか探していないが,これでは全数検索したことにならないのでは?この修正は2023/04/17に入れているが,4月16日のコードと比較してみよう.いや,その下のループでそれはやっているようだ.同じコードがダブってしまうが,実害はないと思われるので修正を入れた.あとで整理することにする.

出力文字列が正しいことを検算する方法を考えなくてはならない.InvertFuncを用いずに直接検査することは可能だろうか?方法はあるだろう.文字列から整数を生成してしまうのが速いのではないか?いや,そんな簡単な話ではない.循環列は無限に反復する無限級数になっているので,そのΣを取らなくては元の数字にはならない.InvertFuncの動作(の模倣)ならあるいは可能かもしれない.つまり,nを頭から割り込んで剰余が一致するところが検出できたときの下図が一致すればよいのではないか?⇒検算は必要だが,ここでは保留しておこう.

テキストの長さと桁数では7の差がある.この7という数字は文字列に詰め込まれた記号で/B:0.&/の7文字だ.従って,桁数と配列長は一致している.問題はn=1234で10進数の場合,末尾の5008103727の10桁が欠損しているというところだ.これは結局,QTに書き漏らしがあることを意味する.MakeRecurringDecimalよりも前の問題だ.1から始めよう.現行論理では1は例外として扱うしかない.

φ,ψなどがすべて1になっている.これで正しいか?ここは後でチェックすることにして,2を見てみよう.従来論理では正しく0.5を表示しているが,改訂版では0.0で5が入ってこない.なぜか?xの初期値は1だが,x=x*bから始めるので,i=1でx=10,これを2で割って商が5というのはよいが,fixed=i=1で固定部が立ってしまう.

Open Live Writer の動作がおかしい

Open Live Writer の動作がおかしい.タスクバーのアイコンからオープンしたが,すぐ画面から消えてしまったので,一度閉じて再度開いたところ,随分前のドラフトを開いてきた.

image

このファイルはすでに公開されているし保存もしてあるのだが,これまでにも「修復しますか?」というメッセージが何度も出てその都度処理しているのに,時折思い出したようにゴーストとなって立ち上がって来る.その後,以下のような真っ赤なパネルがポップアップしてきた.

image

このパネルは,前にも少なくとも一度は見たことがある.以下のようなエラーも表示された.

image

エラーレポートには大したことは記載されていなかった.起動時にファイルが画面から消えたというのは,多分,モニターを切り替えたためと思われる.赤いパネルは何かのメッセージと思われるが,意味不明だ.

ともかく,先に進もう.大きい数字を扱えるようにするために可能なことをあれこれやっているが,その一環として,プログレスバーを廃止し,その代わりにタスクバー上のアイコンを点滅させることにした.この動作は一般にアプリをインストールする操作中にパネルが他のウィンドウの影に隠れてしまった場合,ユーザに注意を促すために使われるものなので,用法としてはやや変則だが,点滅が止まれば処理は完了しているというメッセージと解釈できるので,長く掛かりそうな場合には,放置して他のことをやるなどの応対が考えられるので,それなりに有効なのではないかと思う.

もう一つの対策として,現在valueの入力ボックスでテキストが更新された場合にはパラメータ表示を即時更新するようにしているのを,リターンキーが入力されたときにのみ確定入力として処理するよう仕様変更することにした.あちこち仕掛りになっているのだが,使い勝手にも影響するところなので,まずこれを先付けで修正を入れることにする.

キーイベントが入ってこない.なぜだろう?どこかのコントロールにフォーカスがあると,そのコントロールにイベントがパスされて,そこで明示的に放棄しないと回ってこないのではなかったろうか?ZELKOVAでは一覧画面でなにかその辺りを対策していたような気がするのだが… ⇒KeyPreviewというプロパティをオンにすればよい.⇒動作するようになった.Enterキーを受け付けたときは,長い処理でも打ち切らないようにしておこう.(自発的に指示しているので待つことができる)

おかしい,1234567の7桁で配列サイズオーバーが発生した.ToBCDで起きている.ToBCDが使っている配列はInt16.MaxValueの固定サイズだ.循環周期は34020>32767=Int16.MaxValueで明らかにオーバーしている.循環数列は計算に使っているのではなく,単に表示しているだけなのだから,打ち切ってもよいのではないか?実際,小さいテキストボックスに30000文字を格納するというのは現実的ではない.

テキストボックスのサイズは32767になっているから,その範囲なら格納することは可能だ.bcdNumberにはこの制限はかかっていないが,この値は最終的にnotation.Textに格納されるので,それ以上長い文字列を作っても意味がない.現在MAXARRAYSIZEには,536,608,768という数字が入っている.これはInt16.MaxValueよりはずっと大きいので,ここまではとりあえず処理してもよいのではないか?配列サイズをMAXARRAYSIZE固定としてとりあえず,動作した.1/1234567の固定部は73桁,循環部は34020桁で,冒頭は

A:0.000000810000591300431649315104000025920018921613812778083328000829
4406054&91642008898666496026542099375732544284757327872849347180023441
41711223449193117910976075012534759150374179773151234400401112292811973
75274083950081283559336998316008770686402601073898783946112280661964883

のような巨大テキストだ.value=1234567890として10桁入力してENTERでは,Invertまでは完了しているが,inverseの表示が出てこない.桁数も0, 0 のままになっている.どうも,BigInteger.Divideという関数の中で滞留しているようだ.Divideの引数の中で,BigInteger.Pow(b, keta)の計算に手間取っているのでははないか?InverseClickの中でも,DispParametorを実行している.これは余分な処理なのではないか?いや,DispParametorを実行しているのは,ここだけだ.もう一箇所あるが,これは単に初期表示しているだけだ.

ToBCDが結構重い処理になっている.どうも,Debug.WriteLineで糞詰まりしているようだ.InvertFuncが完了した後で,小数を整数化→文字列化しているが,InvertFuncの中でこの数字列を取得することはできないのだろうか?この数字はとても巨大で,Debug.WriteLineですら表示できないような数だ.また,その間,点滅がまったく止まってしまうというのもおもしろくないところだ.valueが7桁の1234567なら,妥当な時間で表示まで進める.

延べ来訪者数がいつの間にか11万人を超えた.ちょっぴりうれしい.

image

循環周期列とInvertの内部コードを比較してみよう.⇒確かに一致している.つまり,InvertFuncを実施すれば,その結果を使って循環周期列を直接生成できる.循環周期列の生成は巨大数を用いたコストの掛かる処理だったので,これが省けるメリットは大きい.まず,DispInvertに相当する関数を作ってみよう.⇒従来論理の出力と比較してみたが,…

ψ関数のテーブルをハッシュ化した

Psi関数を書き換えて,配列サイズが整数範囲を超える場合には固定サイズ配列ハッシングするように修正した.これでかなり大きな数字まで(時間が掛かるのはやむを得ないとしても)処理できるようになった.ここで,Psi関数の仕様上の疑問が湧いてきた.現行インプリメントはψ関数の定義を満たしているのか?アルゴリズムは必ずしも定義に沿ったものにはなっていないように見えるが,これで正しいのか?この値は「b^x≡1 mod n」を満たす最小のxということになっているが,この式が成立するための条件がある.その辺りは押さえられているか?

9桁くらいまではそこそこ動作するが,それ以上になると数を入力しただけでほぼハング状態になってしまう.PSIで手間取っている.num=1234567890 b=10 arraysize=536608768だ.PSIはそれほど時間を消費しないと考えられていたので,プログレスバーも設置していない.しかし,Inverseはとっくに完了しているだが…Invertの方が重い処理のはずだったのではないか?10桁まではそこそこ動作する.11桁になると,PSIでなめくじになってしまう.num=12345678801 b=10 arraysize=536608768.Factoringでφ関数を使っているが,大丈夫だろうか?φは疑似素数でもb^φ≡b mod φ になる.

ともかくPSIが遅過ぎる.なんとかならないものだろうか?そもそも,現行ではPSI数は表示用にしか使われていない.どういうことだろう?一方,PHIは,①FactoringSub,②DispParametor,③SeedTestClick などあちこちで使われている.InvertFuncではいずれも使われていない.結局PSIはただの飾りということになる.PsiとInvertの論理はほとんど同じなので計算量にそれほど大きな差が出るのはおかしい.⇒InvertFuncはvalueが大きい場合には打ち切るようになっている.ψはつねに計算しているため,大きく見えていた.⇒同じ条件で打ち切るようにした場合には,ψの方がInvertより収束は早い.valueに11桁の数値を設定して,InvertFuncで例外が起きた.

image

配列RTでオーバーフローが発生している.これを避けるためには,PSIでやっているようにハッシュ化するしかない.⇒対処した.10進14桁までは進めるようになった.15桁になると流石に重い.⇒プログレスバーを出すようにしたら,10桁でもヒーヒー言っている.それほど影響あるだろうか?⇒確かに多大な影響がある.プログレスバーの代わりになるものはないだろうか?⇒ラベルの長さを変えてプログレスバー代用とするというアイディがネット上にあった.もう少し簡単なものが欲しい.タイマーで文字色を変えるというのもある.

中断ボタンを点滅させるというのが一番適切だが,画像を使っているので背景色の変更はできない.タスクバー上のボタンやタイトルを点滅させることはできるようだ.これがよいかもしれない.FlashWindowExという関数がある.⇒確かに,サンプルコードで点滅できた.ただし,VSのボタンが点滅している.また,停止したときに色が残ってしまっている.⇒GetMainWindowHandleの引数が”devenv”になっていた.”kinai”に変えて正しく動作するようになった.停止したときも元の色に戻っている.これがいい!プログレスバーは光線が横切るようなアニメになっていて,カッコいいのだが,廃止しよう.

https://atmarkit.itmedia.co.jp/fdotnet/dotnettips/723flashwindow/flashwindow.html

なぜだろう?SeedTestでは長いシーケンスに入っているのに点滅しない.Invertでは一度だけ点滅している.カーソルの切り替えは動作している.⇒原因はわかった.DoEventsが入らないと動作しない.15桁くらいまでは動作するようになった.ただし,InvertではB=1はテストしないようにした.B=1では固定列が長くなり過ぎる.

もう少し,仕様変更したい.inverseという値は現在一番興味があるところなので,この値を検定ボタンを押さずに更新したい.リターンキーで受け付けるというのがよいのではないかと思う.従って,テキストボックスの値を変更しただけでは更新されないというのでよいのではないか?値が確定するまでは待たなくてはならないが,Invertを押すと大きい数字の場合には無闇に時間を空費してしまう.

B進数循環小数表示

かなり仕上がってきたのだが,問題が出てきた.基数1のときの動作がおかしい.B=1でInvertを実行すると,n=200のとき,進数表記の値が空(/1:&/)になってしまう.これは本来なら,(/1:0000…1&)となるべきところだ.つまり,199個の0のあとに1という固定部を持ち,循環部なしという形でなくてはならない.これは,ペアノの公理で自然数を定義するために導入された後者関数の構成にかなり似ている.

自然数:後者関数 1進数表記

0:0 0
1:s0 1
2:ss0 10
3:sss0 100
4:ssss0 1000

自然数の逆数 1進数表記 1進循環小数表示

1/1:1.0 
1/2:0.1 /1:1&/
1/3:0.01 /1:01&/
1/4:0.001 /1:001&/

B進数循環小数表示とは以下のような形式の文字列である.

/B:xxx…/yyy…/

ここで,Bは基数を10進数で表示したもの,xxx…は小数非循環部のB進数表記,yyy…は小数循環部のB進数表記.B進数表記では,{0, 1, 2, 3,…9, A, B, C,…Z, a, b, c,…z, {, |の64個のアルファベットが用いられる.B>64の場合のアルファベットをどうするか?また,整数部を持つ小数をどう表現するかについてはまだ確定していないが,この記法を用いれば,任意の基数で循環小数の値を構造的に明示することができる.

基数が2以上の場合の動作は確認できているが,1の場合は暫定的にパスしているので,改めて考える必要がある.2023/04/13のログには,「n=1というのは,1/nが1になるというかなり特殊な数字だ.”循環小数=0.” + nnstrとあるように,ここでは1/nが1より大きくなることを想定していない.⇒暫定的にn=1の場合はエラーを回避して抜けるようにした.」としているところだ.

1進数表記した自然数同士の加算は可能であるから,定義としてはこれで正しいと思われるが,整数部を含む小数の表記が確立していないのは不都合だ.⇒単純に小数点を導入すればよいのではないか?整数部というのは非循環部の一部であり,非循環部で小数点を用いるようにすればそれで問題は可決する.つまり,たとえば,1.5という数をB進循環小数表示すれば,/1:1.00001&/となる.

&で止まっているということは,循環しないことを意味する.これですべての(正の)有理数を表記できるようになった.明らかに無理数はこの表記にはなじまない.非循環部が無限大の長さを持ってしまうため,正確な値をこの方法で表示することはできない.近似値として表示するのはもちろん可能だが…(通常表記でもそれ以上のことはできない)

循環小数進数表記では冒頭の基数を10進数で表記しているが,これもB進数アルファベットで表示した方がよいのではないか?10進表記とB進表記が入り混じっているというのは感心しない.

1/200を16進数表示しようとして,InverseClickで例外が発生した.zerosupが-2になっている.⇒修正ミスだ.進数表記の論理を入れる場所を間違えていた.

できた!16進で1/200を表示すると,/G:0.0&147AE/ のようになる.ややクリティカルなのは,Gという文字は16進数のアルファベットには含まれていないという点だ.16進より上なら入ってくるが,16進で使われるのはFまでの文字だ.16進を意味する文字がGだというのはいまいち,ピント来ないかもしれない.

しかし,この定義でもややあいまいな点は残る.2進数は0と1で表示されるが,1進数でも0だけでは表示できないと考えられるからだ.この意味ではやはり,1進法というのはかなり特殊な進数であると考えられる.16進をFとして表示したらどうなるか?それも分かりづらい.2進数は1と表示されてしまう.従って,16進をGと表記することは正しい.

1進数と2進数で使うアルファベットが同じというのも多少の違和感は残るが,最小限0と1がなければ数字を表記できないことは明らかであるから,やむを得ないだろう.0の個数だけで表記ということも考えられなくはないが,それだと,0が無限個並ぶような場合,判別できなくなる可能性がある.さて,一応収まったので,本題に戻ろう.1進小数の循環進数表記だ.まず,3という数の逆数1/3が表示してみよう.

固定桁,循環桁いずれも0になっている.結局,InvertFuncの計算が誤っていることになる.InvertFuncの論理には誤りはないはずだが,B=1では動作しない.この関数ではb^nをnで割るという操作を行っているが,b=1なので,b^n=1で変化しない.従って,これをnで割っても同じ結果にしかならないから,ループを空回りして空を返しているのだろう.どうすればよいか?大きくならないのだから,nで割るチャンスがない.これを回避するには,引き算しかないのではないか?つまり,除算の代わりに減算するしかないような気がする.修正して以下のような文字列が出てきた.

/:0.00&/

1/3:0.01 /1:01&/ だから,最後の0が1にならなくてはならない.この値はどうやって得ているのか?InverseClickではb^ketaを計算して10000…のような数を作り,それをnで割る操作で1*b^k/nを求めているが,BigInteger.Divideは整数除算で1/nを実行することになるので,nn=0となってしまう.n=1の場合は例外として扱われている.これは1/1は基数bの値に拘わらずつねに1になることによる.この関数の中でnnstrを生成しているので,ここでその答えを作り出してやるしかない.

できた.ほとんど仕上がったのではないか?あとは,3種検定の出力を整理するだけだ.この出力は必要に応じて随時改変すればよいので,とりあえず,最小限の情報を整った形式で出力することを目標とする.

剰余周期列検定でminよりmaxが小さいと何も出力されない.一度は実行するという方がよいのではないか?⇒対処した.

▲valueに巨大数を入れたら,落ちた.以下は呼出履歴

Microsoft.VisualBasic.Conversion.Val(string)
Kinai.Kinai.ValueChanged() 場所: Kinai.vb
Kinai.Kinai.num0_TextChanged(Object, System.EventArgs) 場所: Kinai.vb
System.Windows.Forms.Control.OnTextChanged(System.EventArgs)   
System.Windows.Forms.TextBoxBase.OnTextChanged(System.EventArgs)
System.Windows.Forms.TextBoxBase.WmReflectCommand(ref System.Windows.Forms.Message)
System.Windows.Forms.TextBox.WndProc(ref System.Windows.Forms.Message)
System.Windows.Forms.Control.ControlNativeWindow.WndProc(ref System.Windows.Forms.Message)
System.Windows.Forms.NativeWindow.Callback(System.IntPtr, Interop.User32.WM, System.IntPtr, System.IntPtr)
System.Windows.Forms.Control.ReflectMessage(System.IntPtr, ref System.Windows.Forms.Message)

テキストの長さは6689で上限32767にはほど遠い.Val(num0.Text)でテキストを数値に変換したところで落ちている.受け側はBigIntegerなので受けられるはずなのだが…System.OverflowExceptionが起きている.BigIntegerにはParseという関数がある.これを使ってみよう.⇒The value could not be parsed.というエラーが出た.空文字列では例外が発生する.これはずいぶん厄介だ.⇒BigValというラッパを作って回避することにした.しかし,その後のFactoringSubで,BigInteger cannot represent infinityという例外が発生する.

Math.Sqrtで落ちている.BigIntegerに代替関数はあるだろうか?BigInteger.Sqrtという関数は存在するようだが,どうも.NET Proffessionalでないと搭載されていないような感じだ..NET 3.5が必要ということのようなので,.NET 6.0をダウンロードしてみた.(最新版はすでに7.0だが,敬遠した)インストール完了時に「このソフトは使用状況を収集します」というメッセージが出た.そんな話聞いてないぞ!

Extreme Optimization Numerical Libraries for .NETはやはり,有料だった.2ヶ月間の無料トライアル版というのはある.以下のURLにBigIntegerを使った平方根の計算コードが載っていた.多少の弱点はあるようだが,使えないというものではないようだ.試してみよう

https://www.codeguru.com/visual-basic/using-biginteger-in-visual-basic-2010/

このサイトの説明にも書いてあったが,ゼロ除算が発生した.整数範囲の数ではmath.sqrtで解くように改造して解決した.FactoringSub,Division,ConvertClick,DispParametorをクリアして,InverseClickで例外が置きた.Value was either too large or too small for an Int32.というものだ.いや,違う.DispParametorだ.PSIsuをLongにしておいたのがまずかったのかもしれない.⇒いや,psi関数の中だ.RTとITという配列を使っているが,そのサイズが大き過ぎたようだ.

進捗をみるためにプログレスバーを導入した

プログレスバーを導入したのだが,どうも動作が思わしくない.初期起動で少しだけ進んだ状態のまま止まってしまう.⇒進捗率6%で抜けてしまっている.⇒ループから横道に抜けていた.基数の情報(約数)などを知りたいのだが,常時画面に出すのではなく,Invert出力でよいのではないか?表示されるべき項目には,基数:素因数分解,nとのGCM,bのレピュニット数など.

CASIOのサイトでφ関数が計算できる.その結果と出力が一致していない.n=1234567のとき,CASIOではφ=1224720となっているが,KINAIでは41088が出力されている.Wolframでも同じ数を出しているので,こちらが間違っているのだろう.φの計算はFukuzo氏に紹介されたものをそのまま使っているつもりなのだが…オリジナルのコードは残っているだろうか?⇒オリジナルのコードに戻してみたが,結果は同じだ.1234567は1, 127, 9721, 1234567しか約数を持っていない.従って,1と1234567を除けば,127, 9721, 127×9721の3つしかない.いや,これらの倍数で1234567より小さいものも含まれるから,実数はもっと大きい.確かに41088という数字は小さ過ぎるような気がする.

オリジナルのコードは新潟大の竹内研究室からのコピーだし,最近のものは,奥村晴彦著『c言語による「アルゴリズム辞典」』が出典だ.2つとも間違っているというのはかなり考えづらい.加工の仕方が悪いのだろうか?確かに古いコードでLongという整数型を使っているのは問題かもしれない.それもあるが,PFactorをsieveを使わないように改造したことも影響している.PFactorは小さく約数から返すようになっているが,逆に大きい約数から返すようにしないと動作しないはずだ.オリジナルコードは廃棄してしまったが,sieveを使うようにするか,ないし,単純で非効率なコードに書き換えるしかない.

奥村のコードは少なくとも整数範囲では正しく動作しているので,こちらを改造して対応することにする.⇒なぜだろう?今度は正しい値がでるようになった.修正箇所としては,パラメータを表示している論理をInvertFuncの外に出したといことしかしていないのだが…いや,原因は分かった.InvertFuncは無茶苦茶時間の掛かる処理でまだφを計算するところまで進んでいなかったというだけの話だ.プログレスバーを取り付けてみたが,数分実行しても値はゼロからまったく変化していない.⇒カウンタを10000で割った剰余の1/100を出すようにして動作するようになった.10000点が1サイクルに当たる.

この論理の高速化は可能だろうか?この計算は循環周期が短ければかなり簡単に終わる場合もあり,周期がnに近いような場合にはとてつもなく時間が掛かってしまう.これは避けられない.⇒10000を1000に短縮した.この方が計算が速そうに感じるので心理的効果はある.これだと変化が速いので,10000点くらいまでは我慢できそうだ.いや,せいぜい5000点くらいかもしれない.値の更新では途中で打ち切ることにする.3000くらいで十分なのではないだろうか?⇒いや,もっと短くてもよい.大きい数字の場合にはInvertを使うという仕様だ.

逆数周期表示を見易くするために,記号の前後に空白文字を入れてみたが,コピーするとき切れてしまうので,空白を入れないように変更した.また,この行に固定部と循環部の桁数を出すようにした.これらの値はInvertFuncが最後まで実行されないと与えられない.処理が中断された場合には0, 0 となる.

だいぶいい感じになってきた

だいぶいい感じになってきた.特に,B進数⇔10進数の相互変換が自在にできるようになったのがうれしい.これは相当役に立つと思う.循環小数は基数が決まらないと意味がないので,基数を変化させることができることはその辺りを調査するときに使うツールとしては必須の機能だ.ここまでやると,Invertを実行しなくても,逆数の循環単位などを常時表示できるようにしたくなってくる.整数Nの逆数である循環小数Dの固定部Xと循環部Yを2つの整数とみなすと,XのB進数表記の桁数をx,Yの桁数をyとすれば,0≦x, y<N,0≦X<B^x,0≦Y<B^yで,

D = X / b^x + Y * ρ(x, y) (1)

ここで ρ は ρ(x, y) = Σ{k=0→∞}(1 / {B^y}^k) / b^x のような無限級数.(1)式はどんな小数にも適用できる等式だが,桁数 x, y が不定というところが厄介なところだ.4093という素数をB=11で逆数を取ったところ,循環単位の桁数が2046になった.ρ(x, y) は無限等比級数で,r=1/B^y < 1 により収束する.Σ{n=1→∞}a_n = a_1/(1 – r) .これが正しいとすると,1 – r という数がどのようなものであるのかが気になる.この値を計算するには,B^y という数を決定し,その逆数を取って,それと1の差分を計算する必要がある.どうもこの当たりが鍵になりそうな気がするので,実装を試みることにしよう.

電卓としても使えるようにn^pの計算で剰余だけでなく計算数値も出すようにした.循環小数値をX&Yの形式で表記することを考えてみる.たとえば,252_10であれば,00&390625のようになる.つまり,1/252 = 00&390625(10)と表記できる.この表記では頭のゼロは落とせないので,/00/390625/10とするのがよいのではないだろうか?あるいは,10/00/390625の方がベターかもしれない.⇒このような値を与えられたとき,これから1/252という元の数字を導くことができるだろうか?

InverseClickでエラーが発生した.n=255, b=12のとき,固定桁 fixed=1, 循環桁 k=16で,1+16*2=33桁の数字列を取り出したあと,zerosup = keta – nnstr.Length が –4 という負値になったため, New String(“0″c, zerosup)でエラーが発生した.nnに入っている値は,{1608573608807851864064416092523532}という大きなもので,b^keta / n の値だが,ConvertNum2String でテキストに変換したとき,桁数が37しか取れなかった.

ConvertNum2Stringが誤動作しているようだ.間にNULLキャラが入っているように思われる.いや,”A8”とか,”BA3”のような複数文字がつながった部分がある.⇒エンコードの問題だ.UTF8を使っていたが,UNICODEに変更して動作するようになった.

System.Text.Encoding.Unicode.GetString(BitConverter.GetBytes(c))

SeedTestでWRONG TOTIENTが出ているが,これは何だろう?「pk <> k And tot > 1」という理由だ.tot はφ関数,kは循環単位長,pkはtotとkのGCMだ.SeedTestは1~Nの範囲で検定を行い,整数の属性をチェックしている.pk=2, k=0, tot=2だ.対象数は4で基数は10.⇒ツールで常時φやψが見えるようにしておこう.

InverseClickで「R <> b And R <> 1」で停止した.R=0, b=20, b=128.⇒今度は,R=4, b=10, n=12 で停止した.InvertFuncではまずx=b=10として,x\n=10\12=0…10.次にx=x*b=10*10=100として,100\12=8…4,次に,x=R=4で,x*b=4*10=40\12=3…4.このRは既出だから,循環が閉じて復帰している.この計算は正しい.つまり,循環が閉じるときのRはbや1に限った話ではない.従って,ここで停止する必要はないと言ってよい.

ファイルを開こうとして,競合エラーが発生する.これはおもしろくない.⇒エラートラップを仕掛けてresumeするようにした.⇒ファイルに保存をオプションとする.

InverseClickで「ERROR:Count cannot be less than zero. (Parameter ‘count’)」というエラーになった.zerosupが-1になっている.上で出ていた症状だ.nnstr.Length=2でketa=1のため,差分がマイナスになってしまう.nnstrには”10”という文字列が入っている.nnも10だ.fixed=1でkが0であるため,keta=1+2*0で1になっている.n=1という数が入っている.n=1というのは,1/nが1になるというかなり特殊な数字だ.”循環小数=0.” + nnstrとあるように,ここでは1/nが1より大きくなることを想定していない.⇒暫定的にn=1の場合はエラーを回避して抜けるようにした.

▲φφというパラメータをチェックする必要があるだろうか?この値はφ(φ())で,nのトーシェント関数のトーシェントだから,nを変えない限り変化しない.

▲ψがゼロになる場合がある.このようなときは,循環桁数=φになる.通常は,φ≧ψでψ=循環桁数になっているのだが…これは調べておく必要がある.どうもBの約数と関係があるようなので,Bの約数も表示できるようにするとよいのだが…

ToBCDで例外が発生している.以下の計算式で発生する.

Dim byteCount As BigInteger = Math.Log(val) / Math.Log(b) + 1

n=255と小さな数字だが,逆数を整数化した数は巨大数になる.3921568627450980392156862745098 ToBCDでは冒頭で配列サイズを決めるためにMath.Logを使っている.対数計算しないように方式変更した.⇒最初にInt16.MaxValueサイズの配列を確保し,これを使って直接n\bの剰余(BCD値)を格納して桁数をカウントするようにした.

だいぶ整ってきた

だいぶ整ってきた.

image

対象数値ないし除数,基数を変えると自動的にボックス内の数値を更新するようになっている.除算を実行して余りがある場合にはGCMは1より大きく,割り切れるときにはGCMは除数そのものになる.notationの欄ではB進表記した数を入出力できるようにしたいのだが,まだ実装されていない.画面下部の剰余数列のブロックではkないしnをある範囲で変化させて周期数列を生成しているが,単点のn^p mod k という値を取り出したい場合もあるので,個別に計算できるようにした.ボタンの数は大幅に減って上段では,①PrimeTest, ②SeedTest, ③Invert と④Clear だけになった.これらの処理の内容はまだかなり整理が必要だが,大枠は完全に固まったといってよい.

対象数値をLongの範囲とするという制限は撤廃することにした.どうしても制限が必要な場合は出てくるかもしれないが,原則として無制限としておきたい.重くなる原因としてダンプ文字列が長くなることがあるかもしれない.コラッツのときは文字数制限してある分量を超えると捨てるようにしていたが,かなり効果があった.ただし,ファイル出力を選べばダンプをファイルに保存できるようになっていたので,その機能は必要かもしれない.出力パネルはもう少し横幅があった方がよい.

InvertFuncはPrimeTest, SeedTestからも呼び出している.ダンプの量が多いので,Invertコマンドの場合以外はこれらの値をダンプしないようにした.ただし,ファイルには出力する.逆数の循環数列を設定パネル上に表示して Invertボタンを廃止することも考えたが,対象数が4桁を超えると相当な桁数になってしまうので,現実的ではない.詳細はInvertボタンで表示し,PrimeTestやSeedTestでは隠蔽するというのが妥当だ思う.ディテールはまだまだ整備しなくてはならないが,最後の関門 notationへの変換・逆変換をやっつけてしまうことにしよう.

Convert.ToStringは基数が2, 8, 10, 16の場合しか扱わない.それ以外では例外が発生する.これは自前で作るしかない.ToBCDという関数も思ったような動作にならないので,丸ごと書き換えた.⇒動くようになった.かなりおもしろい.基数の範囲は2~62とした.アルファベットのA~Zとa~zに別々の値を与えて,最大でzzzzzzz…のような数まで表示できる.あとは,これを表記から数値に変換する処理を組み込むだけになった.ただし,こちらはユーザ入力から数値に変換するので,エラーに対処する必要がある.

いや,このエラーは無視してもよい.特に動作上のエラーにはならない.たとえば,2進数列に2という数字が紛れ込んだ場合には,2×2の値がその桁にあるとして計算するだけだ.10進に戻って,もう一度2進で表示すると正しい2進数列になっている.

16という数が入力できない.(6をBSで消去して再入力しようとして)1はBのレンジに入っていないため,弾かれてしまうようだ.⇒1を範囲に加え無処理で抜けるようにした.

N進数への変換・逆変換はほぼ仕上がったようだ.基数は最終的に2~64まで対応ということにした.62でzまで使い切るので,64の場合には{と|が余分に使われる.もし,その進数の範囲を超える文字が入力された場合には,直ちに変換して正しい数字列に書き換わるので,その文字が使えないことを指摘しなくてもよいだろう.あと,残った課題は,①3種の検定の出力を整理して使い易いものにする.②巨大数でハングしないように適切な例外処理を入れる,の2点だけになった.そのあとは,このツールをどう活用するか?というフェーズに入るが,おそらく因数分解の効率化というところから入ることになるのではないかと思う.相当強力なツールになったので,役に立つと思う.

3種テストの方はすべて出力をファイルに保存できるようになっているが,剰余の方は残っている.こちらも保存できるようにした方がよい.ただし,こちらはあまり長いダンプは出ないので,画面からコピーするだけでもよいかもしれない.ファイルを開いて追加出力できればよいのだが…惜しむらくは,文字が少し小さ過ぎるという点ではないだろうか?いまさらフォントサイズを変えるという訳にもゆかないが,もう一回り大きければだいぶ楽だったのではないだろうか?⇒完成間近なのでアイコンを見つけなくてはならない.⇒いまいちパッとしないが,これ「 image 」 でいくことになった.

昨日から走らせている検定がまだ終わらない

昨日から走らせている1281のInvertがまだ終わらない.ψ関数を書き換えて,対数を使って近似値を求め,厳密値を再計算して一致することを確認するという論理にして見たのだが,やけくそ時間が掛かるようになってしまった.この方式では b^x ≡ 1 mod n を与える最小の x を求めるのに,b^x=ny+1 の両辺の対数を取って,x=log(ny+1)/log(b) {y=1→b^n}を計算しているが,まだ,x=10のところを延々とやっている.これで見ると,既存方式の効率の良さが分かる.まぁ,これは見込みないので停止して次に進むことにしよう.⇒やはり,打ち切りボタンは必要だ.⇒元の論理を復活させたら,瞬時に処理完了した.

現行のpsi関数は対象数値が大きくなると時間を消費するものになる.主要な原因は剰余テーブルが大きくなってスキャンに時間が掛かるようになるためだ.Rの大きさはまちまちで順序不定のため頭から全数走査している.もう少し効率的な管理法はないものだろうか?一番簡単なのはハッシュを使うことではないか?ヒットしない場合には多少余分のコストは掛かるが,何もしないよりはましであるような気がする.いや,Rは重複のないユニークな数であるはずだし,R<Nなのだから,単純にT[R]=Rとしておけばよい.これなら相当早くなるはずだ.

いや,それだけでは不十分だ.ψ=i – j で計算されているが,このやり方ではjを決定できない.どこかにこの値を保持しておく必要がある.もう一つ配列を作るか,構造体を作って一緒に格納するか?⇒もうひとつ配列を作ることにした.⇒すでに書き込まれたRというのが出てきた.これはかなりおかしい.対象nは1281で出力ではpsi=60となっている.⇒このテーブルは生成時に初期化されていないのではないだろうか?いや,初期化しても同じだ.

計算は合っている.周期列の桁数は60でψは60になっている.同じRが現れているのにゲームオーバーにならないのはなぜだろう?これらは,冒頭のi=1, 2, 3 で書き込まれた分だ.FORループでは,x=x*bを実行して,bのべきを生成しているが,x≧nになるまでは除算は実行されない.XとRを交換した場合も同じだ.つまり,除算はつねにx≧nに達した時点で実行されるようになっている.多分論理的にはこれで正しいのだろう.問題は重複が発見されたときのインデックスを書き込むかどうか?という点だ.ψは最小である必要があり,そのためにはiから減ずるjは大きい方がよいので,多分書き込むというのでよいのだろう.

「すでに書き込まれたR」が発生するのは,つねにループの冒頭部分だ.これはこれでよいのではないかと思う.⇒修正で相当な効果があるかと思ったのだが,実質ほとんど変わらなかった.12813をテストして,どちらの方法でも約30秒くらい掛かる.テーブルのサイズは2134くらいなので,CPUパワーからすると問題にならないのかもしれない.もう一桁増やして128131を試してみたが,有意差は出なかった.どちらも1分5秒位掛かっている.numが128131に対し,i=3468なので,相対的にはやはりそれほどのものではないということだろうか?まぁ,処理の主要部分は除算なので影響は出ないのかも知れない.処理速度に大差がないとしたら,どちらの論理が優位というのも難しい.まぁ,走査しなくてよいという点では改訂版の方に多少分があるような気もするが…

どうも状態がかなりおかしくなっている.BigInteger.ToStringでおかしな動作が起きている.ゼロが書き込めなくなっていたが,それだけでなく,何も書けない(つねに2が出力される)ような状態になっている.応急措置として,VS2019の修復インストールを試みているところだが,訳が分からない.designerを直接いじるのはまずいということは知っているが,テキストボックスを削除したとき,名前が残っていて誤動作が起きるので削除操作している.しかし,それだけではこれほど具合が悪くならないと思うのだが… 単純ミスだった.すぐ後に置いたGCMの計算でテキストボックスに書き込みしていた.

入力ボックスでnの値を変えると,自動的にφ,ψの値が更新されるようにしようと思ったのだが,少し無理がある.nの桁数が大きくなるとφないしψの計算に多大な時間が掛かるようになり,打ち切りボタンが必要になってくるので,やはり,スタートボタンは必要だ.せめて,φとψの並行計算というのは実施できないだろうか?FactoringSubでは素数判定にφ関数を使っているので,数が大きくなると動作が止まってしまう.

発掘した素数検定ツールも動き始めている

かなり仕事がはかどった.発掘した素数検定ツールも動き始めている.できることが大幅に広がった気がする.ひょっとすると「効率的な素因数分解」まで進めるかもしれない.いまやっている「べき乗の剰余数列の周期性」と「1/nの小数部の循環周期」に繋がりのあることも見えてきた.よく分からないのはPrimeTestとSeedTestだ.おそらくPrimeTestでは素数判定アルゴリズムの検証を試みているのではないかと思われるが,SeedTestのところはいまのところまったく不明だ.出力も雑多な記号の羅列のようになっていて,作成意図がまったく分からない.

先に進む前にいくつか片付けておきたい.まず,ファイルをもうひとつ作って,そこに不要になったコードを移しておこう.廃棄してしまえばそれまでだが,後日何か参照する必要が出てくる可能性もあるので温存しておいた方が無難だ.ファイル名はごみ箱としておけばよい.おそらく,現行版ではまだSieveを使っているはずだが,廃止することにしたので,PrimeTableも破棄ということになる.グローバル変数もごみ箱に移して,何かのときには復活できるようにしておいた方がよい.

PrimeTableはPFactorで使われている.PFactorは最小の約数を返す関数だ.確かに,素数はかなり疎らに存在するから全数検査というのは割が悪い.TotientFuncの論理を使って書き直してみよう.①最初に2をチェックしてその後は奇数だけを検査,②√xの範囲を検査としたのでそこそこ動作するだろう.PrimeTableはPrimeTestSubでも使われている.PrimeTableは素数テーブルなので,これがないと素数判定をランタイムで実行しなくてはならない.⇒代替としてTotient関数を使うしかない.φ値がx-1ならxは素数とみなされる.これしかないのではないだろうか?あまり割がよいとは言えないがやむを得ない.

PrimeTestSubではすべての偶数をチェック範囲に入れている.これはムダなことだ.修正が必要.⇒やってみよう.⇒修正完了した.20614132のInverseを実行したらループから抜けてこない.確かにかなり大きい数ではあるが…この数は,4.85104102370160-10^8だが.周期<20614132であるとしても相当大きなものになりそうだ.このPCでは計算できないかもしれない.⇒おそらく,これはダンプに途方もない時間が掛かっているのだろう.スクロールが止まっているので様子は見えないが,数万あるいはそれ以上の桁数のダンプを出すのは重過ぎる.⇒確かにそのようだ.ダンプを停めたら軽く動いた.

20614132程度の数なら一瞬で因数分解は終わる.これでSieveを使わずに素数判定できるようになった.現在,出力用のテキストボックスが3つあるが,出力はすべてOutボックスに出すようにしてもよいのではないか?その方が画面も簡素になる.あるいは,値を設定すると自動的にφとψを計算して表示するようにしてもよい.その方がおもしろいのではないか?1/nの値を出すのもおもしろい.NotationはOutに出力するのではなく,トグルでBベースと10進を切り替えできるようにするのがよいのではないか?そうすれば,repunitというボタンは廃止できるし,ketaも廃止できるだろう.valueの値を書き換えるという仕様はよくない.

このためにはB進数の文字列⇔数値変換ができなくてはならない.VBにConvert.ToStringという関数がある.ただし,ToStringはInt32だ.この逆変換としてConvert.ToInt32というのがある.入力ボックスに入力される値としてはInt32以上を禁止しても実用上は差し支えないのではないか?φとψを常時画面に表示するようになれば,PrimeTestは不要になる.PrimeTestの目的は φ mod ψ ≡ 0 の検証であると考えられるので,例外が発生した場合にだけ停止するようにしておけばよい.

Inverseの出力ももう少しシンプルなものにしたい.Inverseでは対象数の小数点表示を出すべきだ.周期列とφないしψの関係がくっきり出るような表示が必要だ.一番分かりづらいのがSeedTestだが,狙っているのは冪剰余列でやっているようなところではないのだろうか?べき剰余列でも,φなどを表示するべきだ.冪剰余の連続実行ボタンで,InverseやSeedTestを実行できるようにすることも考えられる.チェックがオンになっている機能を実行するようにすればよい.

Convert.ToStringはかなり動作に制限がある.引数が8ビット,つまり,1バイトの数を指定した進数に変換するというだけだ.つまり,数を一度BCDに変換して格納しておく必要がある.逆数を常時表示しておきたいのだが,表示桁数が足りない.doubleで15桁,decimalでも29桁しかない.InverseFuncで出力を停めているが,ループから抜けてこない.配列サイズオーバーが発生してしまう.とりあえず,対象数値をInt32に限定しないと無理なようだ.Int32に限定してもまだオーバーフローしてしまう.7FEFFFFF=2,146,435,071が限界ということのようだ.⇒1/nを10^m倍して固定小数点化したものを文字列に変換して出力するようにした.これなら桁数がいくら増えても表示できる.

一つおもしろいことに気付いた.n=7として,1/7を計算すると,{142857}という循環節が現れる.これを数とみなしてその逆数1/142857を取ると,この分数の循環単位は{000007}となる.つまり,{142857}と{000007}はある種の逆数のような関係になっている.ψ(n, b)=循環単位桁数であることはほぼ間違いないいが,これらを計算しているコードを見ると,ほぼ事実上同じコードになってしまっている.これでは同じ値になるのは当然だ.両者はそれぞれ独立の概念として定義され,それに従ってコーディングしているつもりだが,実質的には同一のものに別の名前を与えていただけなのだろうか?

ψは,ある基数bのもとで,b^x=1 mod n となるような最小の数として定義されている.循環単位桁数はその言葉通りの意味だ.ψの計算コードが間違っているのだろうか?どうもその気配が濃厚だ.定義によれば,B^x=1 mod n となる数 x を探しているはずなのに,循環が発生する時点での値を返している.どうも,まだ読み切れていないのだろうか?PrimeTestは単点テストと思っていたが,Bの範囲を指定してリスト出力する多点検定だった.⇒処理を中断する打ち切りボタンが必要だ.

356をInvertしてfixedの値が間違っている.前方の0がカウントされていない.⇒対処した.

べき乗の剰余数列の周期性について

2005年に書いた An Efficient Factoring Algorithm by Repunit Number Method に関係するソースコードを発掘したので,手を入れて動かしてみたい.これはVBで書かれていたもので,VB6を再インストーしてみたが,動作しない.VS2017である程度ファイルを読み込めたので,使えそうな部分だけをコピーして蘇生させてみた.とりあえずなんとか動くようになった.これを仕上げておけば,手元に置くツールとして何かと有用なのではないかと思う.剰余演算や因数分解,φ関数,GCD,単位反復数などが出てくる.使い方の分からないところもあり,よく動いていないところもある.

  1. Modulo 動作しない
  2. PrimeTest 動作しない
  3. Repunit 動作しない
  4. Division 除算を実行して,商と剰余を出力
  5. Totient φ(n)を計算しているはずだが,間違っている
  6. SeedTest エラーが発生する
  7. Factoring 因数分解のはずだが,何も表示されない
  8. Inverse エラーになる
  9. GCM 2数の最大公約数を表示

まず,動作しない機能を動かすところから始めよう.

Moduloは,num0, base, Factorの入力値を取り出して1~Factorまでの剰余数列を画面出力している.これは結局べき剰余でやっていることと同じなので統合してしまうことにしよう.⇒並列動作できるようにしてみたが,両者がやっていることはかなり違う.Moduloの場合は,y*b^p mod k でbは固定,pを1~Factorまで変化させている.つまり n^p mod k で見ると,p^0, p^1, … p^F mod k を出力している.

Modulo では,yが0になると抜けるようになっているので,k=10でb=10の場合は,0を出力しただけで終了してしまう.⇒ようやく,話が合い始めた.結局のところやっていることは同じだ.つまり,ModuloボタンとGoボタンは当機能と言ってよい.Moduloは捨ててよいだろう.

image

この時期はまだ,周期性というのに気付いていないので,ともかくFで指定した回数だけべきを繰り返すという作りになっているが,現行版ではkで指定した範囲のべきを生成して,その中の一周期分を取り出している.やはり,こちらの方が分かり易いと思う.新版では,nとkの範囲を指定して,n x k のテストを一括実行できるようになっている.一応ここまでできたので,バックアップを取っておこう.⇒失敗した.VSのフォルダで作業していた.開発用ドライブに移動する.

PrimeTest というのがあるが,少し大きそうなので,先にRepunitを見てみよう.これはどういう計算を行っているのだろう?たとえば,22 # 5 →  245411のような数が出力される.入力された b, psi という2つの値から,Σ b^i {i=0→psi-1}という計算をやっている.この値はnum0に入るが,剰余計算では除数(法)に当たる.Decimalというボタンがあって,このボタンを押すと,指定した基数Mで対象数のM進数表記を出力するようになっている.先にこちらを片付けよう.

この機能はアクションとするより,むしろ状態として扱った方がよいのではないか…つまり,たとえば,16進表示を指定すると,画面のすべての数字が16進になるというようなイメージだ.まぁ,そこまでやる必要があるのかないのかもわからないので,とりあえずは,動くようにするというところまでとしておこう.ここで,とりあえず,longを一括bignumberに変換しておこう.⇒BigNumberではなく,BigIntegerだった.⇒定数はBigIntegerにできない.整数除算の\もBigIntegerでは使えない.何を使えばよいのだろう?整数除算はBigInteger.Devide, 乗算はMultiply,BigInteger.Parseなどという関数もある.

quotient = BigInteger.DivRem(dividend, divisor, out remainder)

で,商と余りが同時に取り出せるようだ.^はPowを使わなくてはならない.PowerModという関数が入っているが,これはBigIntegerのModPowと同じものなのではないだろうか?いや,どうも様子が違う.奇数の場合には特殊な操作をしたり,平方してからmodを取ったり… この関数を呼び出しているのは,ModuloMultiとDivideRepunitだ.どりあえず,現行のままBigInteger対応修正だけ入れておこう.BigIntegerでは論理演算はできない.これらに関わる変数は暫定的にLongとしておいた.BigItegerではStrという関数も使えないようだ.⇒Decimalは通常10進と解釈されるので,Notationに改めた.Notationでは16進の場合などアルファベットを使うようにしたいのだが,先に進もう.

Divisionという機能は除算を実行して,商と余りを計算するだけなので,とりあえず現状のままとする.Totientというボタンではφ関数を計算しているが実行時エラーが起きる.Int(n/p)で割り切れているか否かを見ているためだ.この関数は丸ごと差し替えることにする.廃棄する前に比較して動作チェックしておこう.既存関数はLongで動かすようにした.⇒かなり悪い.どうも,PFactorという関数が間違っているようだ.⇒PrimeTableが初期化されていないのではないだろうか?これをやっているのは,Sieveという関数だ.ファイルをロードしたときに実行されている.このテーブルは再定義されるべきではない.Form_Loadイベントが掛かってこないため,sieveが実行されていない.⇒修正した.

MaxPrimeは10^9と定義されているが,実際はその平方根の範囲のテーブルしか作っていない.BigNumberはどこまで大きくなるか分からないので,あらかじめテーブルを作っておくというのは実際的ではない.基本的にPrimeTableを使っている関数は廃止すべきだろう.⇒とりあえず,いましばらく論理だけは置いておこう.⇒Factoringは取り敢えず問題なく動作しているようだ.PrimeTestSubを呼び出して,結果をパネルに出力する.素数の場合には何も出力せず,Factorにそのままの値を書き込む.この処理は取り敢えず不要な気がする.最終的な仕様としては,値を書き込んだ時点で自動実行するようにすべきだろう.

PrimeTestSubという関数は4箇所から呼び出されている.①FactoringClick,②PrimeTestClick,③SeedTestClickx2.Factoringで最後の値を出力しないのはやはり,まずいと思う.たとえば,246をFactoringすると,2,3が出力され,41がFactorに入るが混乱する.やはり,すべての素因数を列挙すべきだろう.となると,1も入れなくてはならない.⇒末尾に「,」が出ないようにする.⇒PrimeTestが動くようになった.verboseというグローバル変数で素因数分解の出力を抑制し,それ以外の付加情報を出力する.

GCMはGCMfuncという自前の関数を使っている.これはaとbのどちらか小さい方yが大きい方xを割り,その余りRを取って,y→x, R→yのように転換してRがゼロになるまでループするというロジックだ.おそらく,これは最速と思われるが,BigIntegerには,GreatestCommonDivisorという関数があるので,今後はこれを使うことにする.SeedTestが動作しないのは,リスト要素が明示的に追加されていないためと思われる.VB6ではこれで動いていたはずなのだが…⇒List1はSeedTestClickで参照されているだけで,内容はパネルに出力されるようになっているから,実質的には不要と思われるので,廃止することにする.

SeedTestClickは内部でPrimeTestSubを呼び出して,その結果を使っている.しかし,画面が乱れるので,PrimeTestSubでは出力させたくない.⇒大体動くようになったのではないかと思う.あとは,数値をチェックして動作を確認するだけだ.一度バックアップを取っておこう

もう一つ機能があった.Inverseというやつだ.これが分からない.⇒それでも一応動いているようだ.n=14のとき,

0, 10
8, 4
3, 4
n=12, K=0, ψ=1, R=0, φ=4, φφ=2

のようなダンプが出る.inverseというのは1/nのことを指している.そして,ここで問題にしているのは,有理数1/nの小数部における「周期列の長さ」である.周期列の長さとは,小数位の桁数のことであるから,その数字列の基数,つまり,x進数という表記形式が決まらなければ決定できない.ψ(b, n) のbはこの意味の基数である.ψ(b, n) はつねにn より小さい.the length y(b,n) of a recursion unit of 1/n is always smaller than n. fixed というパラメータが出てくるが,これは周期性のない固定部の長さのことだろう.この意味では Inverse では,まず,その進数表記に基づいたその数を表示すべきだろう.

Inverse で出てくる商と剰余のリストは何を示しているのだろう?確かにこれは1/nの計算ステップになっている.たとえば,128 base 10の場合は,0.0078125となるが,固定部の長さは7で,Qは{0, 0, 7, 8, 1, 2 5}だ.Rは{10, 100, 104, 16, 32, 64}となっているのだが… この関数の中では対数計算を行っている.pow = log(R) / log(b)という値を計算し,pow=b^powとしている.RTという配列を持っていて,そこにRという値を格納している.xの初期値は1dでそれをnで割る操作を反復しているのだが,x*bを計算して1桁上げてから整数除算を実行しているので,つねにその位の計算が実行されていることになる.

このアルゴリズムでは同じRが出現したときに周期列が完成したと判定し,そこで処理を打ち切ることになる.これはまったく正しいと思う.こういう式が出て来る.

n*U(b,n)=r*(by(b,n) -1)

U(b, n)は recursion unit と呼ばれる数で,rは最初の被除数かつ,最後に現れる剰余とされる.n=21, b=10 の場合,剰余数列は,{1, 10, 16, 13, 4, 19, 1}のようになり,ψ(10, 21)=6,U(10,21)=47619,r=1である.Inverseは大体動くようになったが,まだ動かしていなかったものがある.repunitだ.いや,もしかしたらやってたかな?設定値が欠けていると計算できなくなるようだ.⇒対処した.今度はFactoringが動かなくなっている.あれ,おかしい.動いた.どこを押してたのだろう?いや,やはり何か動作不良なところがある.SeedTestを実行するとおかしくなるような気がする.どこかでout.textを消去する余分な動作が入っているのではないだろうか?ともあれ,かなり整ってきた.

image