素数関連
素数
数の性質
複素数
直交と虚数の回転変換からくる関係
円周率
円の性質
無限対数軸
無限大の性質
筆記法
無限桁計算可能アプリの紹介
フェルマーの最終定理
n次の根からのアプローチ








Mathematician.zip
筆記法による数値表現サンプルソース


電卓サンプルイメージ


複素数電卓サンプルイメージ





Mathemtician.exe

インストール、実行方法:
zipのプロパティでセキュリティを許可してzipを解凍し
\\bin\\x86\\RealeaseフォルダでMathemtician.exe or Complex.exeを実行
アンインストール方法:レジストリ等はいじってないので
解凍したフォルダを削除

筆記法による電卓です
大きな数のときとかに使います
演算子のラジオボタンで演算子の計算を行います
数値表現は
iii.ddd#eee(nnn)でiiiが整数部、dddが小数部、eeeが指数部、nnnが基数です
Cardinal、基数は2~36に対応しています
fpは小数部の桁数です
また、fpがすなわち計算の有効桁数となります
Maclaurinはマクローリン計算の精度です
Copy1で上のテキストボックスに
Copy2で下のテキストボックスに
コピーします
Memは結果をその場所に記憶します
Tableで関数テーブルを3つ親のフォルダにファイル出力します
Tableでは上のテキストボックスが増加分の数値、角度で
下のテキストボックスが繰り返し回数です
実数=0でデフォルトが入ります
素数テーブルは上のテキストボックスがその数までの素数列挙で
下のテキストボックスがその数の次の最初の奇数から列挙を開始します

基数はオマケみたいなもので、内部で10進数に変換して演算して
求める基数に変換していますので、特に小数点以下が近似値となります





Complex.exe

複素数電卓です
Phasorで、直交形式、極形式の入力切替です
TableでA^Bテーブルを3つ親のフォルダにファイル出力します Tableでは上のテキストボックスがAの複素数で
下のテキストボックスがBの複素数です
またmem1の上のテキストボックスがBに掛ける数値で
下のテキストボックスが繰り返し回数です
複素数=0、や、実数=0でデフォルトが入ります





サンプルプロジェクトは、VisualStudio for Desktop用です
計算処理をDLL化していますので、その説明です
DLLヘッダのコピーはWritingNumber.txtにありますので、クラス構成はそれで確認してください


準備:
このDLLを使いたいプロジェクトのプロパティから参照から
WritingNumber.dllを追加します

用法:C++

名前空間を最初に追加します
using namespace WritingNumber;

マネージコードなので、ハンドルでインスタンスを保持します
WNum^ wn=gcnew WNum;//実数クラス
WCmp^ wc=gcnew WCmp;//複素数クラス

コンストラクタは
WNum::WNum(WNum% obj);
WNum::WNum(WNum^ obj);
WNum::WNum();
WNum::WNum(int n);
//n:基数,str:String数値,fp:少数点精度
//str format:["+/-"]"X..."[".Y..."]"[#["+/-"]"E..."]"
//+/-:符号,X...:整数部,.Y...:小数部,E...:指数部
WNum::WNum(int n,String^ str,int fp);
//str:String数値
//str format:["+/-"]"X..."[".Y..."]"[#["+/-"]"E..."]""(Z)"
//+/-:符号,X...:整数部,.Y...:小数部(これでm_fp決定),E...:指数部,(Z):基数
WNum::WNum(String^ str);
//str:String数値,fp:少数点精度,bbb:自動拡張fp
//str format:["+/-"]"X..."[".Y..."]"[#["+/-"]"E..."]""(Z)"
//+/-:符号,X...:整数部,.Y...:小数部,E...:指数部,(Z):基数
WNum::WNum(String^ str,int fp,bool bbb);

WCmp::WCmp(WCmp% obj);
WCmp::WCmp(WCmp^ obj);
WCmp::WCmp();
WCmp::WCmp(int n);
//rlobj:実部、絶対値,imobj:虚部、角度,b:極形式フラグ
WCmp::WCmp(WNum% rlobj,WNum% imobj);
WCmp::WCmp(WNum^ rlobj,WNum^ imobj);
WCmp::WCmp(WNum% rlobj,WNum% imobj,bool b);
WCmp::WCmp(WNum^ rlobj,WNum^ imobj,bool b);

と定義されています

-12.345、10進数、少数点精度3ならば、
WNum^ wn=gcnew WNum(10,L"-12.345",3);
あるいは
WNum^ wn=gcnew WNum(10,L"-1.2345#1",3);
もしくは
WNum^ wn=gcnew WNum(L"-12.345(10)");
さもなくば
WNum^ wn=gcnew WNum(L"-12.345(10)",3,true);//true/false:自動拡張fpOn/Off
などとします

ABC.XYZ、36進数、少数点精度3ならば、
WNum^ wn=gcnew WNum(36,L"ABC.XYZ",3);
あるいは
WNum^ wn=gcnew WNum(36,L"A.BCXYZ#2",3);
もしくは
WNum^ wn=gcnew WNum(L"ABC.XYZ(36)");
さもなくば
WNum^ wn=gcnew WNum(L"ABC.XYZ(36)",3,true);//true/false:自動拡張fpOn/Off
などとします

直交形式-12.345+789iならば、
WCmp^ wc=gcnew WCmp(gcnew WNum(10,L"-12.345",3),gcnew WNum(10,L"789",3),false);
とします

極形式(1,-2)ならば、
WCmp^ wc=gcnew WCmp(gcnew WNum(10,L"1",3),gcnew WNum(10,L"-2",3),true);
とします

そして、オペレータで演算します
戻り値retのメンバm_efがエラーフラグで、bit立て
0x0  :正常
0x1  :エラー
0x100 :虚数解
となっています

他のヘルパー関数は、WritingNumber.txtを確認してください





対数Log e X の高速化
・Xのe(底)の桁合わせをする

a=1/e;
b=-1;
if(a<x){
 while(a<x){a=a*e;b=b+1;}
}
else{
 a=1;
 while(x<a){a=a/e;b=b+1;}
 b=-b-1;
}
y=a/x;

これで、yのマクローリン展開(ans)をして
ret=b-ans;

とすれば、かなりの高速化になる


指数e^x の高速化
・Xの桁合わせをする

a=floor(x);//小数点以下切捨て関数(整数取得)
b=power(e,a);//実数の整数乗関数
y=x-a;//小数点取得

これで、yのマクローリン展開(ans)をして
ret=b*ans;

とすれば、かなりの高速化になる





Func(X)=a/b→0、になるような時、逆関数で
Func^-1(Func(X))=Xの再現率が悪い





素因数分解の高速化
・素数か否か単純判別をして、試し割りの方向を考える

素数ってエラストテネスの篩とか考えると
2×3=6でふるって
7以上の素数って6で割った余りは1、5が素数の必要条件で
2×3×5=30でふるって
31以上の素数って30で割った余りは1、7、11、13、17、19、23、29が素数の必要条件
6の場合、はじけないのは2/6、30の場合、はじけないのは8/30、210の場合、はじけないのは43/210
になるから、その素数単純判定法がめちゃくちゃ計算量が少ないんじゃないかなぁ・・・
同様に2×3×5×7=210でも2×3×5×7×11=2310でも
素数列を順番に掛け合わせれば出来るけど、コーディングのデータ入力が面倒くさいです
その場合は素数データファイルを作ってそれでやらせて、1以外の掛け合わした素数以外の素数がその必要条件
掛け合わす素数が大きくなるほど、よくはじきます

この単純判別で、素数かもしれなかったら√xから5まで試し割り
そうでなかったら5から√xまで試し割り

と思ったら、素数かもしれなくても5からやったほうが速いから
素因数分解の高速化には使えなくて、素数判定の高速化にだけに使えた

はじけない確率P、ガウスの素数確率G
G=1/ln6=0.55811
P=2/6=0.3333333

G=1/ln30=0.2940141
P=8/30=0.266666667

G=1/ln210=0.187017
P=43/210=0.2047619

テスト中
ああ、6、30、はよくて、210はうまくいかないで、2310はいい感じかも
どんな数でふるうかの法則がまだよく分からないな
6、30、しかだめかも・・・
P=8/30=0.266666667
で偶数ははじけるとしてP'=0.53333だから奇数の半分くらいをはじく感じかな・・・
2310もアウト

で、素数かもしれない判定は
if((X mod 6)==(1 or 5))
if((X mod 30)==(1 or 7 or 11 or 13 or 17 or 19 or 23 or 29))
こんな感じでできる
これでふるわれたら合成数確定
エラストテネスの篩のようなはじきかたです





大分古いもので恐縮です

設計思想まとめ


数値表現は
iii.ddd#eee(nnn)でiiiが整数部、dddが小数部、eeeが指数部、nnnが基数です
Cardinal、基数は2~36に対応しています
fpは小数部の桁数です
また、fpがすなわち計算の有効桁数となります
Maclaurinはマクローリン計算の精度です

X進数のNという数のK桁目の数情報は
floor((N%X^K)/X^(K-1))
具体例N=ABCD X=16進数 K=2桁目
N%16^2=CD
CD/16^1=12.8125→C

10進数の1234という数
1*10^3+2*10^2+3*10^1+4*10^0

無限桁の計算を実現するため
数字の書式文字列(基数指定)→1文字ずつ桁毎に10進数化→桁毎の各種計算→数字の書式文字列(基数指定)

計算の簡単のために10進変換してから桁毎の数情報を記憶して
計算の具体化は紙と鉛筆の1桁毎の筆算を真面目にコーディングして

四則演算

足し算
99+11=?
1桁目9+1=10→0とキャリー1
2桁目9+1+キャリー1=11→1とキャリー1
3桁目キャリー1
よって99+11=110

引き算は足し算のマイナス

掛け算
55*22=?
1桁目55*2=110→0とキャリー11
2桁目55*2+キャリー11=121→1とキャリー12
よって55*22=1210だけどこれだとメモリオーバフローするからさらに分解して
1桁目55*2だと55がメモリオーバフローするかもしれないから
さらに分解して
1桁目5*2=10→0キャリー1
2桁目5*2+キャリー1=11→1キャリー1
で始めの1桁目55*2=110が出るん

割り算は上位桁から評価
364/11=?
上1桁目36/11=3...3
上2桁目34/11=3...1
よって364/11=33...1
まだ1桁ずつの評価じゃないからこれをさらに分解
上1桁目36/11=3...3 これをさらに36と11を分解
上1-1桁目3/1=3→3
上1-2桁目1*3=3
剰余計算→36-33=3
で上1桁目36/11=3...3

出力は最上位桁を1桁目にして
後は小数点以下の表現にして基数の指数の表現で
桁合わせすれば筆記法の浮動小数点表現の完成です
ex>1234.0→1.234*10^3

また他の三角関数などの多様な関数の計算はマクローリンやテイラー
フーリエなどを参考にすればいいですね

P≠NP予想の多項式時間とか指数関数時間とかの考え方で
このリンクの設計思想は?
リンクは多項式データで通常の数値データの
指数関数データではない

8ビット数値データ
255
1   1   1   1    1   1   1   1
2^7 2^6 2^5 2^4 2^3 2^2 2^1 2^0

書式文字列数値データ
"255#0(10)"
"2" "5" "5" "#" "0" "(" "1" "0" ")"

書式文字列数値データはnビット数値データに比べて
巨大数になればなるほど効率的になります

8ビット数値データ
255
書式文字列数値データ
"255#0(10)"
3+6=9文字
32ビット数値データ
4294967295
書式文字列数値データ
"4294967295#0(10)"
10+6=16文字
64ビット数値データ
18446744073709551615
書式文字列数値データ
"18446744073709551615#0(10)"
20+6=26文字
以上ような感じで
128ビット数値データ
書式文字列数値データ40+6=46文字
256ビット数値データ
書式文字列数値データ78+6=84文字
512ビット数値データ
書式文字列数値データ155桁+6書式=161文字

512ビットくらいの数で512回繰り返すよりも
155桁繰り返したほうが効率的な気がするん
気のせいかな?

カラツバ法
人間の行う筆算とはb=10つまり10進法の多重カラツバ法であるから
計算の高速化を求めるならば例えば基数をb=1M=1000000等にして
その多重カラツバ法つまり1M進数の筆算を行えばさらに高速化できる気がします

100進数の四則演算

足し算
999999+111111=?
1桁目99+11=110→10とキャリー1
2桁目99+11+キャリー1=111→11とキャリー1
3桁目99+11+キャリー1=111→11とキャリー1
4桁目キャリー1
よって999999+111111="1" "11" "11" "10" →1111110

引き算は足し算のマイナス

掛け算
555555*2222=?
1桁目555555*22=12222210→"10"とキャリー"122222"
1-1桁目55*22=1210→10とキャリー12
1-2桁目55*22+キャリー12=1222→22とキャリー12
1-3桁目55*22+キャリー12=1222→22とキャリー12
→12 22 22 10
2桁目555555*22+キャリー122222=12344432→"32"とキャリー"123444"
2-1桁目55*22+キャリー22=1232→32とキャリー#12
2-2桁目55*22+キャリー22+キャリー#12=1244→44とキャリー##12
2-3桁目55*22+キャリー12+キャリー##12=1234→34とキャリー12
→12 34 44 32
よって555555*2222="123444" "32" "10"→12344443210

割り算は上位桁から評価
339967/1122=?
上1-1桁目33/11="03"...33-11*3="00"
上1-2桁目...99-22*3="33"
→"03"..."33"
→3367/1122=?
上2-1桁目33/11="03"...33-11*3="00"
上2-2桁目...67-22*3="01"
→"03"..."01"
よって339967/1122="03" "03" ... "01"→303...1

364/11=?
上1-1桁目3/0="---"...3-0="03"
上2-1桁目(300+64)/11="33"...364-11*33="01"
364/11=33...1

このような感じで四則演算の進数は拡張できる


少し脱線うんちく話

四則演算について筆算は上記のように行うのですが
もう少し深く突っ込んで考えてみましょう

関数F(y)がある時xをF(y)で変換した答えzは
逆関数F(y)^-1としてzはF(y)^-1で変換した答えxに復元する

足し算について
A.Add(B)→C
A+B=C
引き算は足し算の逆関数として
C.Add(B)^-1→C.Sub(B)→A
C-B=A

掛け算について
A.Mul(B)→C
A*B=C
割り算は掛け算の逆関数として
C.Mul(B)^-1→C.Div(B)→A
C/B=A
ここでB=0つまりゼロ除算を考えると
C/0=A←→A*0=C
Aは任意でC=0になり1対1変換が崩れてしまい
ゼロ乗算はゼロとなり1つの解になりますが
ゼロ除算は多数の解となり未定義あるいは解不可となります





戻る