素数について:10桁程度のINTMAX位の範囲の最速素数判定法:javascript:アルゴリズム


はじめに
素数判定法はいろいろありますが
この方法が10桁程度のINTMAX位の範囲ならば
最も高速だと思います
2*10^10の素数判定においてシンプルな√nまでの奇数の割り切り素数判定法の
計算量は√(2*10^10)=√(2)*10^5*1回のループ?処理コード量
あるいは(√(2)/3)*10^5*1回のループ?処理コード量程度になります

それは最小の素数の組み合わせが
2と3なのでそのLCMの6の倍数の±1
であることが素数の条件だということです
6で割ったとき余りが1か5ならば素数の可能性があって
余りが3は3の倍数その他の余りは2の倍数だからです
これだけで2/6=1/3に篩にかけられます

素数6の倍数の列挙(120まで)
1 2 3 5 6 7 11 12 13 17 18 19 23 24 29 30 31
36 37 41 42 43 47 48 53 54 59 60 61 66 67 71 72 73
78 79 83 84 89 90 96 97 101 102 103
107 108 109 113 114 120

多分

6の倍数の±1であるかどうかを調べること


からさらに当該数/2(詳細は後述しますが説明のため)までの列挙済みの素数で
割り切れるか調べることが最速の素数判定法です
したがって1/6に篩にかけました
重複しますが2の倍数でないことで1/2
判定数の1/2まで調べればいいことから
もっと簡易的には1/4に篩にかけました
なので113ならば最大29個具体的には
5 7 11 13 17 19 23 25 29 31 35 37 41 43 47 49 53 55 57
19個の素数判定をすれば113の素数判定が可能です
もっと簡易的には
もちろんわざわざ丁寧にこの19個の素数判定をしなくても
そのまま割り切れるかどうかだけでも113の素数判定は可能です
その場合例えば99991の素数判定において最大16666回
割り切れるかどうか調べれば99991の素数判定が出来ます


計算例 113
・113%6=5であるので条件を満たす
・113/2=58までの列挙済み素数で割り切れるか判定
・113%5≠0 OK
・113%7≠0 OK
113%9≠0 OK
・113%11≠0 OK
・113%13≠0 OK
113%15≠0 OK
・113%17≠0 OK
・113%19≠0 OK
113%21≠0 OK
・113%23≠0 OK
113%25≠0 OK
113%27≠0 OK
・113%29≠0 OK
・113%31≠0 OK
113%33≠0 OK
113%35≠0 OK
・113%37≠0 OK
113%39≠0 OK
・113%41≠0 OK
・113%43≠0 OK
113%45≠0 OK
・113%47≠0 OK
113%49≠0 OK
113%51≠0 OK
・113%53≠0 OK
113%55≠0 OK
113%57≠0 OK
・113は素数である
赤字は素数列挙を用いないとき
緑字は6の余りを考えないとき

さらに素数の一般常識として
判定数がnの時n/2でもなく√nまで調べればよい
√n以上の数では絶対に割り切れない
ということがあるので
上記の議論の調べる最大値を√nとします
だからこれで(2/6)√n=(√n)/3に篩にかけたことになります
したがって10^10の素数判定の場合最大(10^5)/3回割り切れるか調べればいいことになります
で99991の素数判定は√99991=317あるいは317/3=105回割り切れるか調べればいいことになります
また高速化を意図して余計なことをすると残念ながら余計に遅くなるみたいです
だからエラトステネスの篩が速いなんてまんまと騙されていると思うのですがね
素数テーブルを用意して強引に照合しても遅いのですからね
基本的には素数列挙法はメモリを余計に食うし動作も遅いので
素直に√nまでの奇数で強引に割り切れるかどうかを調べた方が
メモリも食わないし動作も速いと思います

この議論をさらに進めて6ではなく2*3*5=30で割って
30までの2.3.5を除く素数の
1 7 11 13 17 19 23 29
に余りがなることが30以上の素数の条件なので
この場合8/30=4/15に篩にかけられるのですが
これは言うほどあまり効果がないのかもしれません
2*3*5*7とかでも43/210の篩等同様の議論ができます
確かに1/4.88に篩にかけられますが43回のif文照合があるので
凝りすぎて余計遅くなっては元も子もないので6で良いのではないでしょうか?

また
エラトステネスの篩を改良して

・n % 6 が1か5でなければ素数ではないで即終了
・2 から n までの自然数を並べる
・最小の 2 を残して 2 の倍数をすべて取り除く
・残った数の最小の 3 を残して 3 の倍数をすべて取り除く
・残った数の最小の 5 を残して 5 の倍数をすべて取り除く
・以下同様に まだ消えてない最小の数を残し その倍数をすべて取り除く
・残った数の最小が √n を超えたら残った数はすべて素数

が多分最速の素数判定アルゴリズムでしょう
と思ったんだけれどおらのエラトステネスの篩の実装方法がヘボくて余計遅かったにゃ
多分1回毎に処理をシステムに戻すせいにゃ
0.1Mまでの素数テーブルを使ってもガイドインデックスを使用しないとかの実装によっては余計遅いのかも
ガイドインデックスとは判定数までの素数の個数のおおよその数はlogなんとかで計算できるからそれを利用することでし
多分この実装だと余計なことをほとんどしていないCHECK PRIME(EASY)が最速素数判定アルゴリズム
var ONELOOPNUM = 1000;
また1回のループでフリーズ防止でシステムに制御を戻すために
計算を1000回に制限しているのでCPUの限界までは使っていません






注意:あんまり巨大な数を計算するとメモリ破壊で壊れます
100000くらいまでなら多分大丈夫
エラトステネスの篩は実装がヘボいのか大きい数は危険かも
推奨動作確認は99987(非素数) 99989(素数) 99991(素数) 99993(非素数)とかで動作確認してね
INTMAXと同じくらいの桁数の999999937(素数)の判定もCHECK PRIME(EASY)で可能です
それを他のでやると危なそうです
ちなみに999999937の素数判定は√999999937=31623あるいは31623/3=10541回の計算です


ソースコード

var TMan = new N6LTimerMan();  //タイマーマネージャー
TMan.add();


window.onload=function(){
  readCSV('./primelist100000.txt', 'analyzeCSV', 'readedCSV');
}

var PRMTABLE = [];
var READED = false;

function readedCSV(res) {
  if(res.length < 1) return;
  var i;
  for(i = 0; i < res.length; i++){
    PRMTABLE.push(parseInt(res[i]));
  }
  READED = true;
}

var PRM = [2, 3, 5];
var ONELOOPNUM = 1000;
var TMP = 7;
var NUM;
var MOD = true;
var USEMOD = 100;

function checkprime(num, max){
  if(max < PRM[PRM.length - 1]) return num;
  var i;
  var mod = num % 6;
  if((mod != 1)&&(mod != 5)) return -1;
  for(i = 2; i < PRM.length; i++){
    if(max < PRM[i]) return num;
    if(num % PRM[i] == 0) return -1;
  }
  return num;
}

function enumprime(num){
  PRM = [2, 3, 5];
  TMP = 7;
  function Loop(id){
    var cnt;
    for(cnt = 0; cnt < ONELOOPNUM; cnt++){
      if(num < TMP){
         if(checkprime(NUM, num) == NUM) {
           TXT_ANS.value = "Prime Number"
         }
         else{
          TXT_ANS.value = "Not Prime Number"
        }
        return;
      }
      var maxtmp = Math.ceil(Math.sqrt(TMP));
      if(checkprime(TMP, maxtmp) == TMP){
        PRM.push(TMP);
      }
      TMP += 2;
    }
    TMan.timer[id].setalerm(function() { Loop(id); }, 50);  //メインループ再セット
  }

  Loop(0);
}

//素数列挙あり
function oncheckprime(){
  TXT_ANS.value = "Calculating・・・"
  NUM = parseInt(TXT_NUM.value);
  var max = Math.ceil(Math.sqrt(NUM));
  if((NUM == 1)||(NUM == 2)){
    TXT_ANS.value = "Prime Number"
    return;
  }
  if((NUM <= 0)||(NUM % 2 == 0)){
    TXT_ANS.value = "Not Prime Number"
    return;
  }
  var mod = NUM % 6;
  if((NUM != 3)&&((mod != 1)&&(mod != 5))){
    TXT_ANS.value = "Not Prime Number"
    return;
  }
  enumprime(max);
}

//素数列挙なし
function oncheckprimeeasy(){
  TXT_ANS.value = "Calculating・・・"
  NUM = parseInt(TXT_NUM.value);
  MAX = Math.ceil(Math.sqrt(NUM));

  if((NUM == 1)||(NUM == 2)||(NUM == 3)){
    TXT_ANS.value = "Prime Number"
    return;
  }
  if((NUM <= 0)||(NUM % 2 == 0)){
    TXT_ANS.value = "Not Prime Number"
    return;
  }

  TMP = 5;

  var mod = NUM % 6;
  if((NUM != 3)&&((mod != 1)&&(mod != 5))){
    TXT_ANS.value = "Not Prime Number"
    return;
  }

  if(MAX <= TMP){
     TXT_ANS.value = "Prime Number"
     return;
  }

  function Loop2(id){
    var cnt;
    for(cnt = 0; cnt < ONELOOPNUM; cnt++){
//      if((MOD)||(USEMOD <= TMP)){
        mod = TMP % 6;
        if((mod != 1)&&(mod != 5)){
          TMP += 2;
          continue;
        }
//      }
      if(NUM % TMP == 0){
        TXT_ANS.value = "Not Prime Number"
        return;
      }

      TMP += 2;

      if(MAX <= TMP){
         TXT_ANS.value = "Prime Number"
         return;
      }
    }

    TMan.timer[id].setalerm(function() { Loop2(id); }, 50);  //メインループ再セット
  }

  Loop2(0);
}


function onEratosthenes(){
  TXT_ANS.value = "Calculating・・・"
  NUM = parseInt(TXT_NUM.value);
  MAX = Math.ceil(Math.sqrt(NUM));
  if(200000 <= NUM){
    TXT_ANS.value = "Do not number range!!!"
    return;
  }
  if((NUM == 1)||(NUM == 2)||(NUM == 3)){
    TXT_ANS.value = "Prime Number"
    return;
  }
  if((NUM <= 0)||(NUM % 2 == 0)){
    TXT_ANS.value = "Not Prime Number"
    return;
  }
  var mod = NUM % 6;
  if((NUM != 3)&&((mod != 1)&&(mod != 5))){
    TXT_ANS.value = "Not Prime Number"
    return;
  }

  var i;
  PRM = [2];
  for(i = 3; i <= NUM;){
    PRM.push(i);
    i += 2;
  }

  TMP = 1;
  function Loop3(id){
    var cnt;
    for(cnt = 0; cnt < ONELOOPPROC; cnt++){
      if(MAX <= PRM[TMP]){
        if(PRM[PRM.length - 1] == NUM){
          TXT_ANS.value = "Prime Number"
          return;
        }
        else{
          TXT_ANS.value = "Not Prime Number"
          return;
        }
        TMP++;
      }

      TXT_ANS.value = "Calculating・・・" + PRM[TMP];

      var tmp;
      var n;
      for(tmp = TMP; tmp < PRM.length; tmp++){
        var tprm = PRM.filter(n => ((n === PRM[tmp])||(n % PRM[tmp]) !== 0));
        PRM = [];
        PRM = [...tprm];
      }
    }

    TMan.timer[id].setalerm(function() { Loop3(id); }, 50);  //メインループ再セット
  }

  Loop3(0);

}

function onTable(){
  if(!READED) {
    TXT_ANS.value = "Do not read yet!!!"
    return;
  }
  TXT_ANS.value = "Calculating・・・"
  NUM = parseInt(TXT_NUM.value);
  MAX = Math.ceil(Math.sqrt(NUM));
  if(100000 <= NUM){
    TXT_ANS.value = "Do not number range!!!"
    return;
  }
  if((NUM == 1)||(NUM == 2)||(NUM == 3)){
    TXT_ANS.value = "Prime Number"
    return;
  }
  if((NUM <= 0)||(NUM % 2 == 0)){
    TXT_ANS.value = "Not Prime Number"
    return;
  }
  var mod = NUM % 6;
  if((NUM != 3)&&((mod != 1)&&(mod != 5))){
    TXT_ANS.value = "Not Prime Number"
    return;
  }

  TMP = 0;
  function Loop4(id){
    TXT_ANS.value = "Calculating・・・" + PRMTABLE[TMP];
    var i;
    for(i = 0; i < ONELOOPNUM; i++){
      if(NUM < PRMTABLE[TMP + i]){
        TXT_ANS.value = "Not Prime Number"
        return;
      }
      if(PRMTABLE[TMP + i] == NUM){
        TXT_ANS.value = "Prime Number"
        return;
      }
    }

    TMP = TMP + i + 1;

    TMan.timer[id].setalerm(function() { Loop4(id); }, 50);  //メインループ再セット
  }

  Loop4(0);
}

function onCHK(){
  MOD = CB_CHK.checked;
}



注意
判定する数があまり大きな数でないのならば
mod = TMP % 6;
if((mod != 1)&&(mod != 5)){
 TMP += 2;
 continue;
}
など6で割って余りが1か5の判定は
簡易判定の計算が余計になるので
あまり効果を発揮しません
例えば
99993%6=3
で1か5でないので素数ではない
と1回余りを求めてはじくときに効果を発揮します
ですので判定する数が大きな数でないと多分冗長でしょう
CHECK PRIME(EASY)でmod6を使うかどうか判定していますけれど
if文判定なんてしないで強制的に毎回使ったほうが多分速いです
だからコメントアウトしました


まとめ:最速素数判定アルゴリズム


・√nまでの3以上の奇数xでn mod x がゼロならば素数でないそしてすべてクリアしたらnは素数である
・また6以上のy mod 6が1か5ならばyが素数の可能性がある簡易判定法だからnやxが素数の可能性がないのならば計算を省略できる
・おまけにフリーズ対策である程度計算したらシステムに制御を戻すとプログラムとして素晴らしい





N6LIsPrime()使用法



CHECK PRIME(EASY)をNAS6LIBにカプセル化した以下使用方法

<script language="JavaScript" type="text/javascript" src="./javascripts/nas6lib/common.js"></script>
<script language="JavaScript" type="text/javascript" src="./javascripts/nas6lib/timer.js"></script>
<script language="JavaScript" type="text/javascript" src="./javascripts/nas6lib/prime.js"></script>
を宣言する

関数は
//入力////////////////////////////////////////////////
//id : TManのid
//num : 判定する数
//出力////////////////////////////////////////////////
//num : 素数である
//-1 : 素数でない
//0 : 計算継続中
//////////////////////////////////////////////////////
function N6LIsPrime(id, num);
となっています

注意
N6LIsPrime()が内部で使用するタイマーと
N6LISPRMRETの戻り値を監視するタイマーの
2つのタイマーが必要です


テストコード

var TMan = new N6LTimerMan();  //タイマーマネージャー
TMan.add();
TMan.add();

...省略...

function onN6LIsPrime(){
  TXT_ANS_T.value = "Calculating・・・"
  NUM = parseInt(TXT_NUM_T.value);
  var ret = N6LIsPrime(0, NUM);

  function Loop5(id){
    if(ret == NUM){
      TXT_ANS_T.value = "Prime Number"
      return;
    }
    else if(ret < 0){
      TXT_ANS_T.value = "Not Prime Number"
      return;
    }
    ret = N6LISPRMRET;
    TMan.timer[id].setalerm(function() { Loop5(id); }, 75);  //メインループ再セット
  }

  Loop5(1);
}
}







function IsPrime(num){
  if((num == 1)||(num == 2)||(num == 3)) return num;
///////////////////#1
  var mod = num % 6;
  if((mod != 1)&&(mod != 5)){
    return -1;
  }
///////////////////
  var max = Math.floor(Math.sqrt(num));
  var tmp;
  for(tmp = 5; max < tmp;){
///////////////////#2
    mod = tmp % 6;
    if((mod != 1)&&(mod != 5)){
      tmp += 2;
      continue;
    }
///////////////////
    if(num % tmp == 0){
      return -1;
    }
    tmp += 2;
  }
  return num;
}



numが与えられて素数判定(戻り値num:素数-1:非素数)をするプログラムで
#2は冗長かもしれませんが
#1はかなり有効な高速化だと思います


エラトステネスの篩javascript


function IsPrimeEratosthenes(num){
  if((num == 1)||(num == 2)||(num == 3)) return num;
  var mod = num % 6;
  if((mod != 1)&&(mod != 5)){
    return -1;
  }
  var max = Math.floor(Math.sqrt(num));
  var i;
  var PRM = [2];
  for(i = 3; i <= num;){
    PRM.push(i);
    i += 2;
  }
  var TMP;
  for(TMP = 1; PRM[TMP] <= max; TMP++){
    if(max < PRM[TMP]){
      if(PRM[PRM.length - 1] == num){
        return num;
      }
      else{
        return -1;
      }
    var tmp;
    var n;
    for(tmp = TMP; tmp < PRM.length; tmp++){
      var tprm = PRM.filter(n => ((n === PRM[tmp])||(n % PRM[tmp]) !== 0));
      PRM = [];
      PRM = [...tprm];
    }
  }
  return num;
}






任意の数

例えば989の素数判定を考えてみる
素数判定において根までを求めればいいことから

根は
√989=31.44837038

根近くの最大の約数の組み合わせは
31から始めて
989/31=31.903...割り切れない
2を引いた
31-2=29
989/29=34.103...割り切れない
更に2引いて
29-2=27
989/27=36.629...割り切れない
更に2引いて
27-2=25
989/25=39.56...割り切れない
更に2引いて
25-2=23
989/23=43...割り切れた
ので989の根近くの最大の約数の組み合わせは23と43と分かる



しかしこれだと差が大きい根近くの最大の約数の
組み合わせで低速となる為少し改良する
スレッドを2つ用意する

例えば991の素数判定を考えてみる
素数判定において根までを求めればいいことから

根までの最大の整数の奇数を求める
√991=31.4801524
だから31

根近くの最大の約数の組み合わせは



第1スレッド
31から始めて
991/31=31.967...割り切れない
そこから2ずつ引いていく

第2スレッド
3から始めて
991/3=330.333...割り切れない
そこから2ずつ足していく



第1スレッド
更に2を引いた
31-2=29
991/29=34.172...割り切れない

第2スレッド
更に2を足した
3+2=5
991/5=198.2...割り切れない




とこれを繰り返し 第2スレッドが第1スレッド以上の値になったら素数として終了
結果割り切れる値がなかったので
991は素数である

ま、なんてことはない
普通の割り切り法を3側と根側から行っただけの事




999999937(INTMAXに近い素数)近辺の奇数を調べて検証しました



function N6LIsPrimeMNRD(id, num){
  N6LISPRMRET = 0;

  N6LNUM = num;
  N6LMAX = Math.ceil(Math.sqrt(NUM));

  if((N6LNUM == 1)||(N6LNUM == 2)||(N6LNUM == 3)){
    N6LISPRMRET = N6LNUM;
    return N6LNUM;
  }
  if((N6LNUM <= 0)||(N6LNUM % 2 == 0)){
    N6LISPRMRET = -1;
    return -1;
  }

  N6LTMP0 = Math.ceil(N6LMAX / 2) * 2 + 1;
  N6LTMP1 = 5;

  var mod = N6LNUM % 6;
  if((N6LNUM != 3)&&((mod != 1)&&(mod != 5))){
    N6LISPRMRET = -1;
    return -1;
  }

  if(N6LTMP0 <= N6LTMP1){
    N6LISPRMRET = N6LNUM;
    return N6LNUM;
  }

  function LoopMNRD(id){
    var cnt;
    for(cnt = 0; cnt < N6LONELOOPNUM; cnt++){
      mod = N6LNUM % N6LTMP0;
      if(mod != 0){
        N6LTMP0 -= 2;
      }
      else{
        N6LISPRMRET = -1;
        return -1;
      }
      mod = N6LNUM % N6LTMP1;
      if(mod != 0){
        N6LTMP1 += 2;
      }
      else{
        N6LISPRMRET = -1;
        return -1;
      }

      if(N6LTMP0 <= N6LTMP1){
        N6LISPRMRET = N6LNUM;
        return N6LNUM;
      }
    }

    TMan.timer[id].setalerm(function() { LoopMNRD(id); }, 50);  //メインループ再セット
    N6LISPRMRET = 0;
    return 0;
  }

  N6LISPRMRET = LoopMNRD(id);
  return N6LISPRMRET;
}


function onN6LIsPrimeMNRD(){
  TXT_ANS_MNRD.value = "Calculating・・・"
  NUM = parseInt(TXT_NUM_MNRD.value);
  var ret = N6LIsPrimeMNRD(0, NUM);

  function Loop6(id){
    if(ret == NUM){
      TXT_ANS_MNRD.value = "Prime Number"
      return;
    }
    else if(ret < 0){
      TXT_ANS_MNRD.value = "Not Prime Number"
      return;
    }
    ret = N6LISPRMRET;
    TMan.timer[id].setalerm(function() { Loop6(id); }, 75);  //メインループ再セット
  }

  Loop6(1);
}



まとめ:最速素数判定アルゴリズム


任意の整数nの最速素数判定
・n mod 6 が1 or 5ならば素数の可能性あり そうでなければ素数でない
・ceil(√(n)/2)*2+1(根までの最大の整数の奇数)までの奇数xで
 n mod x がゼロならば素数でないそしてすべてクリアしたらnは素数である
・それを上と下から調べる
・おまけにフリーズ対策である程度計算したらシステムに制御を戻すとプログラムとして素晴らしい


おまけ;素数列挙表(331まで)(赤字が非素数)*1表

002,003

 ×3  000  001  002  003  004  005  006  007  008  009
 000  005  007  011  013  017  019  023  025  029  031
 010  035  037  041  043  047  049  053  055  059  061
 020  065  067  071  073  077  079  083  085  089  091
 030  095  097  101  103  107  109  113  115  119  121
 040  125  127  131  133  137  139  143  145  149  151
 050  155  157  161  163  167  169  173  175  179  181
 060  185  187  191  193  197  199  203  205  209  211
 070  215  217  221  223  227  229  233  235  239  241
 080  245  247  251  253  257  259  263  265  269  271
 090  275  277  281  283  287  289  293  295  299  301
 100  305  307  311  313  317  319  323  325  329  331

エラトステネスの篩的な解説

 Aの倍数 2A 2A(2/3) 2A(1/3)

 05   010   07   03
 07   014   09   05
 11   022   15   07
 13   026   17   09
 17   034   23   11
 19   038   25   13
 23   046   31   15
 25   050   33   17
 29   058   39   19
 31   062   41   21

 35   070   47   23
 37   074   49   25
 41   082   55   27
 43   086   57   29
 47   094   63   31
 49   098   65   33
 53   106   71   35
 55   110   73   37
 59   118   79   39
 61   122   81   41

以下同様

*1表において
Aの倍数が最初に出た後
さらに2A(2/3)進んでその倍数
さらに2A(1/3)進んでその倍数
さらに2A(2/3)進んでその倍数
さらに2A(1/3)進んでその倍数
以下同様

となっています
で素数であるには
その歯抜けが素数です


分かりやすく図示すると

7の倍数はこうなっている

また7の倍数は
3から始めて
2個進んだものなので
7±2=9,5
であるかな?

ためしに43は
3から始めて
14個進んだものなので
43±14=57,29
である


でも5は違うね 惜しい



任意の数nの*1表の行列αβを計算すると
0,1行目は
 ×3  000  001  002  003  004  005  006  007  008  009
 000  005  007  011  013  017  019  023  025  029  031
 010  035  037  041  043  047  049  053  055  059  061

行αは
(n - 5) / 30 = α

列β数列は
(0.0,0.2,0.6,0.8,1.2,1.4,1.8,2.0,2.4,2.6) * 10 + 5

列βは
(((n - 5) / 30) - parseInt((n - 5) / 30)) * 3 = 列β数列



例えば43を計算してみる

行αは
(43 - 5) / 30 = 1.266666(10)

列βは
0.266666 * 3 = 0.8

列β数列(0.0,1番目から始めて)
0.8は4番目

だから43は*1表の14番目



もう1つ
例えば239を計算してみる

行αは
(239 - 5) / 30 = 7.8(70)

列βは
0.8 * 3 = 2.4

列β数列(0.0,1番目から始めて)
2.4は9番目

だから239は*1表の79番目



もう1つ
例えば311を計算してみる

行αは
(311 - 5) / 30 = 10.2(100)

列βは
0.2 * 3 = 0.6

列β数列(0.0,1番目から始めて)
0.6は3番目

だから311は*1表の103番目


とこれで正しかろう


以上を踏まえて

287は何の倍数か?
普通に倍数で割り切れるか
調べれば良いだけの事を
解説のため冗長に説明しています

√287=16.94
MAX=15
一応念のため冗長に
MAX=17
としておく
287/3=95.666...割り切れない...続行

αは
(287 - 5) / 30 = 9.4(90)

βは
0.4 * 3 = 1.2

列β数列(0.0,1番目から始めて)
1.2は5番目

だから287は*1表の95番目

A=5(1番目)の倍数ならば
2A=10,2A(2/3)=7,2A(1/3)=3
だから任意の整数X
10X+1
10X+7+1
番目が5の倍数
95番目は条件を満たさないので
5の倍数ではない...続行

A=7(2番目)の倍数ならば
2A=14,2A(2/3)=9,2A(1/3)=5
だから任意の整数X
14X+2
14X+9+2
番目が7の倍数
95番目は条件を満たす(X=6)ので
7の倍数である...終了

287/7=41
287=7*41


以上のような計算は基数とかの加減乗除などの
自力実装方法の電卓プログラミングの応用です
だから値データを文字列データにして
無限桁数の筆記法(紙と鉛筆で計算する方法)の
電卓計算プログラミングもやろうと思えばできます
それは別ページだろうね





戻る