//■ Big Number と Big Number を分母・分子にもつ分数による // ネピア数e(自然対数の底)と円周率πの計算 // // Form1_Clickイベントハンドラで再実行するようにしていま // すので、コピー&ペースした後、Form1でイベントハンドラ // を指定する状態にして(Form1を選択状態にしてプロパティ // ウィンドウでイベントアイコンを選択)し、Clickイベント // でForm1_Clickを選択してください。 // // (精度の良さを確かめましょう) // using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace BigNumberFraction { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { test(); } public void test() { Fract Pi = Fract.compPi(40); BigNumber F, B, R; Fract f; string strF; MessageBox.Show("double to BigNumber " + new BigNumber(1234567.98765).ToString()); MessageBox.Show("double to Fract " + new Fract(1213.732).ToString(30)); MessageBox.Show("double to Fract " + new Fract(1213.732,10000).ToString(30)); MessageBox.Show("double to Fract " + ((new Fract(1213.732, 10000)).ToDouble()).ToString()); MessageBox.Show("log(10) " + Fract.Log(new Fract(10)).ToString(30)); MessageBox.Show("exp(4) " + Fract.Exp(new Fract(4)).ToString(30) +"\n System exp(4)=" + Math.Exp(4)); MessageBox.Show("tan(1/2) " + (Fract.Tan(new Fract(1, 2)).ToString(30) + "\n System Sin(1/2)=" + Math.Tan(0.5))); MessageBox.Show("sin(1/2) " + (Fract.Sin(new Fract(1, 2))).ToString(30) + "\n System Sin(1/2)=" + Math.Sin(0.5)); MessageBox.Show("cos(1/2) " + (Fract.Cos(new Fract(1, 2))).ToString(30) + "\n System Cos(1/2)=" + Math.Cos(0.5)); MessageBox.Show("Atan(1/2) " + (Fract.Atan(new Fract(1, 2))).ToString(30) + "\n System Sin(1/2)=" + Math.Atan(0.5)); F = new BigNumber("1234567890123"); B = new BigNumber("12345678"); MessageBox.Show("除算 " + (F / B).ToString()); MessageBox.Show("剰余 " + (F % B).ToString()); MessageBox.Show("log2 " + Fract.Log2().ToString(30)); string S = ""; for (int i = 1; i < 11; i++) { string Sdt = Fract.sqrt(new Fract(i)).ToString(30); S=S+"\n"+ i.ToString("00")+" " + Sdt.Substring(0,6)+" "+ BigNumber.sepStr(false, false, Sdt.Substring(6,24),5,24); } MessageBox.Show(S,"分数によるsqrt"); F = BigNumber.compE(510); strF = F.ToString(); MessageBox.Show(BigNumber.sepStr(strF, 500), "BigNumberによるネピア数 e\n"); F = BigNumber.compPi(510); strF = F.ToString(); MessageBox.Show(BigNumber.sepStr(strF, 500), "BigNumberによる円周率 π\n"); f = Fract.compE(80); MessageBox.Show(f.ToString(100), "BigNumber分数によるネピア数 e"); MessageBox.Show(f.ToString(-5), "BigNumber分数によるネピア数 e(分数表現)"); f = Fract.compPi(80); MessageBox.Show(f.ToString(100), "BigNumber分数による円周率 π"); MessageBox.Show(f.ToString(-5), "BigNumber分数による円周率 π(分数表現)"); f = Fract.MachinPi(40); MessageBox.Show(f.ToString(100), "マチンの公式による分数での円周率 π"); MessageBox.Show(f.ToString(-5), "マチンの公式による分数での円周率 π(分数表現)"); } private void Form1_Click(object sender, EventArgs e) { test(); } } //================================================================================= // BigNumberを分母・分子にもつ分数(Fractクラス) //================================================================================= public class Fract { public bool sign; // 正負(負のときTrue) public BigNumber nume, deno; // 分子(nume), 分母(deno) //------ コンストラクタ ------------------------------------------------------- public Fract(bool Sign, int Nume, int Deno)// 整数を符号付き分数に変換 { sign = Sign; nume = new BigNumber(Math.Abs(Nume)); if (Nume == 0) deno = new BigNumber(1); else deno = new BigNumber(Math.Abs(Deno)); } public Fract(int Nume, int Deno)// 整数を分数に変換(符号は分子・分母の符号による) { sign = ((long)Nume * (long)Deno < 0); nume = new BigNumber(Math.Abs(Nume)); if (Nume == 0) deno = new BigNumber(1); else deno = new BigNumber(Math.Abs(Deno)); } public Fract(int Nume)// 整数を分数に変換(分母=1) {  sign = (Nume < 0);nume = new BigNumber(Math.Abs(Nume)); deno = new BigNumber(1); } public Fract(bool Sign, BigNumber Nume, BigNumber Deno)// 分子,分母にBigNumber { sign = Sign; nume = Nume; nume.sign = false; // を指定して分数に変換 deno = BigNumber.eq0(Nume)? new BigNumber(1):deno = Deno; deno.sign = false; } public Fract(BigNumber Nume, BigNumber Deno) // 分子,分母にBigNumberを指定して { sign = (Nume.sign != Deno.sign); // 分数に変換 nume = Nume; nume.sign = false; // (符号は分子,分母の符号で設定) deno = BigNumber.eq0(Nume) ? new BigNumber(1) : Deno; deno.sign = false; } public Fract(BigNumber Nume) // 分子のみのBigNumberを分数に変換(分母=1) { sign = Nume.sign; nume = Nume; nume.sign = false; deno = new BigNumber(1); } public Fract(double D)// doubleをBigNumberに変換(機械エプシロンを利用) { double DD = D; sign = false; if (D < 0) { DD = -DD; sign = true; } double DE=1; for (double E = 1; (E + 1) > 1; DD = DD * 2, DE = DE * 2, E /= 2) ; deno = new BigNumber(DE); nume = new BigNumber(DD); } public Fract(double D, int DE)// doubleをFractに変換(int分母指定) { double DD = D; sign = false; if (D < 0) { DD = -DD; sign = true; } deno = new BigNumber(DE); nume = new BigNumber(DD*(double)(DE)); } public Fract(double D, double DE)// doubleをFractに変換(double分母指定) { double DD = D; sign = false; if (D < 0) { DD = -DD; sign = true; } deno = new BigNumber(DE); nume = new BigNumber(DD * DE); } //====== 共通処理 =============================================================== public Fract commonDeno()// 約分(最大公約数で分母・分子を除す) { bool S; BigNumber D, N; if (BigNumber.eq0(nume)) return new Fract(false, 0, 1); S = sign; BigNumber T = GCD(nume, deno); N = nume / T; D = deno / T; return new Fract(S, N, D); } public static BigNumber GCD(BigNumber X, BigNumber Y)// ユークリッドの互除法による { // 最大公約数 BigNumber T, XX, YY; XX = X; YY = Y; if ( X > Y) { XX = X; YY = Y; } else { XX = Y; YY = X; } while (!BigNumber.eq0(YY)) { T = XX % YY; XX = YY; YY = T; } return XX; } public Fract addAbsFract(BigNumber Nume, BigNumber Deno)//分数絶対値の加算 { return (new Fract(nume * Deno + Nume * deno, deno * Deno)).commonDeno();} public Fract addAbsFract(Fract A){ return addAbsFract(A.nume, A.deno); } public Fract subAbsFract(BigNumber Nume, BigNumber Deno)//分数絶対値の減算 {  BigNumber D = deno * Deno, N = nume * Deno - Nume * deno; bool S = false; if (N.sign == true) { S = true; N.sign = false; } return (new Fract(S, N, D)).commonDeno(); } public Fract subAbsFract(BigNumber Nume) { return subAbsFract(Nume, new BigNumber(1)); } public Fract subAbsFract(Fract A) { return subAbsFract(A.nume, A.deno); } public Fract multAbsFract(BigNumber Nume, BigNumber Deno)//分数絶対値の乗算 { return (new Fract(nume * Nume, deno * Deno)).commonDeno(); } public Fract multAbsFract(BigNumber Nume) { return (new Fract(nume*Nume, deno)).commonDeno();} public Fract multAbsFract(Fract A) { return multAbsFract(A.nume, A.deno); } public Fract divAbsFract(BigNumber Nume, BigNumber Deno) //分数絶対値の除算 {  return (new Fract(nume * Deno, deno * Nume)).commonDeno();} public Fract divAbsFract(BigNumber Nume) { return (new Fract(nume, deno * Nume)).commonDeno(); } public Fract divAbsFract(int Nume) // 除す値は1〜99 { return (new Fract(nume, deno.multMini((short)Nume))).commonDeno();} public Fract divAbsFract(Fract A) { return divAbsFract(A.nume, A.deno); } public static Fract reverseFract(Fract A)//逆数 { return new Fract(A.sign, A.deno, A.nume);} public static Fract reverseFract(BigNumber A) { return new Fract(A.sign, new BigNumber(1),A);} public override string ToString() // 分数を文字列に変換 { string S = ""; if (sign && nume.number.Length>0) S = "-"; return S + nume.ToString() + " / " + deno.ToString(); } public string numeDeno(string S, int N)// 文字分割処理 { return BigNumber.sepStr(false, false, S, N, S.Length); } public string ToString(int N)// 分数を10進数の小数に変換(桁数を指定)。 { string S = ""; // (分桁数が負のとき分数表現) if (sign && nume.number.Length > 0) S = "-"; string strN=nume.ToString(), strD=deno.ToString(); if (N < 0) S += numeDeno(strN, -N) + " / " + numeDeno(strD, -N); else { Fract X = new Fract(false, nume, deno); //整数部変換 BigNumber F = X.nume / X.deno; //小数部に10を乗じた際,整数に S += F.ToString() + "."; X -= F; //なった値をその桁の値とする。 for (int i = 0; i < N; i++){ X *= 10; F = X.nume / X.deno; S += F.ToString(); X -= F; } } return S; } public Fract Abs(){return new Fract(false, nume,deno);} public static Fract Abs(Fract A) {return new Fract(false, A.nume, A.deno);} public double ToDouble()// 分数を10進数の小数に変換(桁数を指定)。 { Fract X = new Fract(false, nume, deno); //整数部変換 BigNumber F = X.nume / X.deno; //小数部に10を乗じた際,整数に double S = F.ToDouble(); X -=F; double T=1; for (int i = 0; i < 30; i++){ T/=10; X *= 10; F = X.nume / X.deno; S += F.ToDouble() * T; X -= F; } return S; } //----- 符号付き分数の加算 ----------------------------------------------------- public static Fract addFr(Fract A, Fract B) {  //同符号→加算,異符号→減算 Fract C; if (A.sign == B.sign) { C = A.addAbsFract(B); C.sign = A.sign; } else { C = A.subAbsFract(B); C.sign = (C.sign != A.sign); } if (BigNumber.eq0(C.nume)) C.sign = false; return C; } public static Fract addFr(Fract A, BigNumber B) { return addFr(A, new Fract(B)); } public static Fract addFr(BigNumber A, Fract B) { return addFr(new Fract(A), B); } public static Fract addFr(Fract A, int B) { return addFr(A, new Fract(B)); } public static Fract addFr(int A, Fract B) { return addFr(new Fract(A), B); } //----- 符号付き分数の減算 ----------------------------------------------------- public static Fract subFr(Fract A, Fract B) { //同符号→減算,異符号→加算 Fract C; if (A.sign != B.sign) { C = A.addAbsFract(B); C.sign = A.sign; } else { C = A.subAbsFract(B); C.sign = (C.sign != A.sign); } if (BigNumber.eq0(C.nume)) C.sign = false; return C; } public static Fract minusFrac(Fract A) { //符号反転 return new Fract(!A.sign,A.nume,A.deno); } public static Fract subFr(Fract A, BigNumber B) { return subFr(A, new Fract(B)); } public static Fract subFr(BigNumber A, Fract B) { return subFr(new Fract(A), B); } public static Fract subFr(Fract A, int B) { return subFr(A, new Fract(B)); } public static Fract subFr(int A, Fract B) { return subFr(new Fract(A), B); } //----- 符号付き分数の乗算 ----------------------------------------------------- public static Fract mltFr(Fract A, Fract B) { //同符号→正,異符号→負 Fract C = A.multAbsFract(B); C.sign = BigNumber.eq0(C.nume) ? false : (A.sign != B.sign); return C; } public static Fract mltFr(Fract A, BigNumber B) { return mltFr(A, new Fract(B)); } public static Fract mltFr(BigNumber A, Fract B) { return mltFr(new Fract(A), B);} public static Fract mltFr(Fract A, int B) { return mltFr(A, new Fract(B)); } public static Fract mltFr(int A, Fract B) { return mltFr(new Fract(A), B); } //----- 符号付き分数の除算(分母・分子を逆転して乗算)-------------------------- public static Fract divFr(Fract A, Fract B) {  //同符号→正,異符号→負 Fract C = A.divAbsFract(B); C.sign = BigNumber.eq0(C.nume) ? false : (A.sign != B.sign); return C; } public static Fract divFr(Fract A, BigNumber B) { return divFr(A, new Fract(B)); } public static Fract divFr(BigNumber A, Fract B) { return divFr(new Fract(A), B); } public static Fract divFr(Fract A, int B) { return divFr(A, new Fract(B)); } public static Fract divFr(int A, Fract B) { return divFr(new Fract(A), B); } //----- 比較 ------------------------------------------------------------------ public static int cmpFr(Fract A, Fract B) { Fract C = A - B; if (C.nume.number.Length == 0) return 0; else if (C.sign) return -1; else return 1; } public static int cmpFr(Fract A, BigNumber B) { return cmpFr(A, new Fract(B)); } public static int cmpFr(BigNumber A, Fract B) { return cmpFr(new Fract(A), B); } public static int cmpFr(Fract A, int B) { return cmpFr(A, new Fract(B)); } public static int cmpFr(int A, Fract B) { return cmpFr(new Fract(A), B); } //======= 演算子(operator)定義 =============================================== // インクリメントとデクリメント public static Fract operator ++(Fract A) { return addFr(A, 1); } public static Fract operator --(Fract A) { return subFr(A, 1); } // 加算 public static Fract operator +(Fract A, Fract B) { return addFr(A, B); } public static Fract operator +(Fract A, BigNumber B) { return addFr(A, B); } public static Fract operator +(BigNumber A, Fract B) { return addFr(A,B);} public static Fract operator +(Fract A, int B) { return addFr(A, B); } public static Fract operator +(int A, Fract B) { return addFr(A, B); } public static Fract operator +(Fract A) { return A; } // 減算 public static Fract operator -(Fract A, Fract B) { return subFr(A, B); } public static Fract operator -(Fract A, BigNumber B) { return subFr(A, B); } public static Fract operator -(BigNumber A, Fract B) { return subFr(A, B); } public static Fract operator -(Fract A, int B) { return subFr(A, B); } public static Fract operator -(int A, Fract B) { return subFr(A, B); } public static Fract operator -(Fract A) { return minusFrac(A); } // 乗算 public static Fract operator *(Fract A, Fract B) { return mltFr(A, B); } public static Fract operator *(Fract A, BigNumber B) { return mltFr(A, B); } public static Fract operator *(BigNumber A, Fract B) { return mltFr(A, B); } public static Fract operator *(Fract A, int B) { return mltFr(A, B); } public static Fract operator *(int A, Fract B) { return mltFr(A, B); } // 除算 public static Fract operator /(Fract A, Fract B) { return divFr(A, B); } public static Fract operator /(Fract A, BigNumber B) { return divFr(A, B); } public static Fract operator /(BigNumber A, Fract B) { return divFr(A, B); } public static Fract operator /(Fract A, int B) { return divFr(A, B); } public static Fract operator /(int A, Fract B) { return divFr(A, B); } // 比較 public static bool operator ==(Fract A, Fract B) { return cmpFr(A, B) == 0; } public static bool operator ==(Fract A, BigNumber B) { return cmpFr(A, B) == 0; } public static bool operator ==(BigNumber A, Fract B) { return cmpFr(A, B) == 0; } public static bool operator ==(Fract A, int B) { return cmpFr(A, B) == 0; } public static bool operator ==(int A, Fract B) { return cmpFr(A, B) == 0; } public static bool operator !=(Fract A, Fract B) { return cmpFr(A, B) != 0; } public static bool operator !=(Fract A, BigNumber B) { return cmpFr(A, B) != 0; } public static bool operator !=(BigNumber A, Fract B) { return cmpFr(A, B) != 0; } public static bool operator !=(Fract A, int B) { return cmpFr(A, B) != 0; } public static bool operator !=(int A, Fract B) { return cmpFr(A, B) != 0; } public static bool operator >(Fract A, Fract B) { return cmpFr(A, B) > 0; } public static bool operator >(Fract A, BigNumber B) { return cmpFr(A, B) > 0; } public static bool operator >(BigNumber A, Fract B) { return cmpFr(A, B) > 0; } public static bool operator >(Fract A, int B) { return cmpFr(A, B) > 0; } public static bool operator >(int A, Fract B) { return cmpFr(A, B) > 0; } public static bool operator <(Fract A, Fract B) { return cmpFr(A, B) < 0; } public static bool operator <(Fract A, BigNumber B) { return cmpFr(A, B) < 0; } public static bool operator <(BigNumber A, Fract B) { return cmpFr(A, B) < 0; } public static bool operator <(Fract A, int B) { return cmpFr(A, B) < 0; } public static bool operator <(int A, Fract B) { return cmpFr(A, B) < 0; } public static bool operator >=(Fract A, Fract B) { return cmpFr(A, B) >= 0; } public static bool operator >=(Fract A, BigNumber B) { return cmpFr(A, B) >= 0; } public static bool operator >=(BigNumber A, Fract B) { return cmpFr(A, B) >= 0; } public static bool operator >=(Fract A, int B) { return cmpFr(A, B) >= 0; } public static bool operator >=(int A, Fract B) { return cmpFr(A, B) >= 0; } public static bool operator <=(Fract A, Fract B) { return cmpFr(A, B) <= 0; } public static bool operator <=(Fract A, BigNumber B) { return cmpFr(A, B) <= 0; } public static bool operator <=(BigNumber A, Fract B) { return cmpFr(A, B) <= 0; } public static bool operator <=(Fract A, int B) { return cmpFr(A, B) <= 0; } public static bool operator <=(int A, Fract B) { return cmpFr(A, B) <= 0; } //====== EqualsとGetHashのoverride(これを入れないと警告エラーとなる)=============== public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } //====== 関数例 ================================================================= public static Fract compE(int NumberOfLoop) // 分数版(引数は繰返し回数) { // マクローリン展開によるネイピア数(自然対数の底)の計算 Fract E = new Fract(0); BigNumber A = new BigNumber(1), B1 = new BigNumber(1); for (int i = 1; i < NumberOfLoop; i++) { E = E.addAbsFract(reverseFract(A)); A = A.multMini((short)i); } return E; } public static Fract compPi(int NumberOfLoop)// 分数版(引数は繰返し回数) { // 連分数によるPiの計算 Fract p = new Fract(NumberOfLoop * 2 - 1); for (int i = NumberOfLoop; i >= 1; i--) p = (new Fract(2 * i - 1)) + (new Fract(i * i)) / p; return (new Fract(4)) / p; } public static Fract MachinPi(int NumberOfLoop)// 分数版(引数は繰返し回数) { // Machinの公式によるPiの計算 Fract P = new Fract(0), K = new Fract(1), T = new Fract(16, 5), D = new Fract(-25); for (int i = 0; i < NumberOfLoop;T /= D, K += 2, i++) P += T / K; K = new Fract(1); T=new Fract(4,239); D=new Fract(-239*239); for (int i = 0; i < NumberOfLoop;T /= D, K += 2, i++) P -= T / K; return P; } public static Fract sqrt(Fract X) { // 連分数による平方根の計算 Fract DX, DN, DM, Z, N, NN, XX = X;int i; XX.sign = false; if (XX == 0) return new Fract(0); Boolean less1 = false; if (XX < 1) { XX = 1 / XX; less1 = true; } for(N=new Fract(1), NN=new Fract(1); NN 0; i--) { Fract ii = new Fract(i); A = ii / (2 + ii / (2 * ii + 1 + A));} return 1 / (1 + A); } public static Fract Log(Fract X) {  // 連分数によるLog(X) int N = 40; Fract XX = X.Abs(); if (XX == 0) { MessageBox.Show("Logの引数に0が指定されました"); return new Fract(0);} Fract ln2 = Log2(), L; for(L=new Fract(0);XX >= 2; XX/=2, L += ln2); for(; XX <1; XX *= 2, L -= ln2); XX=XX-1; Fract A = new Fract(0); for (int i = N; i > 0; i--) { Fract ii = new Fract(i); A = ii * XX / (2 + ii * XX / (2 * ii + 1 + A)); } return L+XX / (1 + A); } public static Fract Exp(Fract X) { //マクローリン展開によるExp int Loop=40; Fract XX = X.Abs(); BigNumber K = XX.nume / XX.deno; XX -= K; Fract E = new Fract(1), AX = new Fract(1); for(int N=0; N 0; K = K / 2, A = A * A) if (K.odd()) E = E * A; if (X < 0) E = -E; return E; } public static Fract Sin(Fract X) { // マクローリン展開によるSin int Loop = 30, i; Fract HalfPi = compPi(Loop) / 2; Fract XH = X / HalfPi; BigNumber K = XH.nume / XH.deno; X -= K * HalfPi; Fract A = -X * X; i = 1; if (K.odd()){i = 0; X = new Fract(1); } if (K < 0) K--; if ((K/2).odd()) X = -X; Fract S = X; for(i += 2; i < Loop; S += X, i += 2) X *= A / ((i - 1) * i); return S; } public static Fract Cos(Fract X) { // マクローリン展開によるCos int Loop = 30, i; Fract HalfPi = compPi(Loop) / 2; Fract XH = X / HalfPi; BigNumber K = XH.nume / XH.deno; X -= K * HalfPi; Fract A = -X * X; i = 1; if (K.odd()) X = -X; else { i = 0; X = new Fract(1); } if (K < 0) K--; if ((K / 2).odd()) X = -X; Fract C = X; for (i += 2; i < Loop;C += X, i+=2) X *= A/((i-1)*i); return C; } public static Fract Tan(Fract X) { // 連分数によるTan int N = 35, Loop = 30; Fract HalfPi = compPi(Loop) / 2; Fract XH = X / HalfPi; BigNumber K = XH.nume / XH.deno; X -= K * HalfPi; Fract X2 = X * X, T = new Fract(0); for (int i = N; i > 1; i -= 2) T = X2 / (i - T); if (K.odd()) return (T - 1) / X; return X / (1 - T); } public static Fract Atan(Fract X) { // 連分数によるATan int N = 35, Loop = 30; Fract Pi = compPi(Loop) ; Fract T; if(Abs(X)<=1) T=X; else T=1/X; Fract A=new Fract(0); for(int i=N;i>=1;i--) A= (i*i)*(T*T)/(2*i+1+A); if(X>1) return Pi/2-T/(1+A); else if(X<-1) return - Pi/2-T/(1+A); else return T/(1+A); } } //================================================================================= // BigNumberクラス //================================================================================= public class BigNumber { public Boolean sign; public short[] number; //------ コンストラクタ ------------------------------------------------------- public BigNumber(int V)//整数値をBigNumberに変換 { sign = false; int LL = V; if (LL == 0) number = new short[0]; else { if (LL < 0) { sign = true; LL = -LL; } int K = ((int)Math.Log(LL, 100)) + 1; number = new short[K]; for (int i = 0; i < K; i++, LL /= 100) number[i] = (short)(LL % 100); } } public BigNumber(double V)//double の整数部分をBigNumberに変換 { sign = false; double LL = Math.Abs(V); if (LL < 1) number = new short[0]; else { if(V <0) sign=true; int K = ((int)Math.Log(LL, 100)) + 1; number = new short[K]; for (int i = 0; i < K; i++, LL /= 100) number[i] = (short)(LL-(Math.Floor(LL / 100))*100); } } public BigNumber(bool s, short[] num, int N)//配列値をBigNumberとする { sign = s; number = new short[N]; setShort(N, num, number); } public BigNumber(bool s, short[] num)//配列値をBigNumberとする { int N = num.Length; sign = s; number = new short[N]; setShort(N, num, number); } public BigNumber(bool s, int len, short v)//最高桁に値Vを設定する { sign = s; number = new short[len]; for (int i = 0; i < len - 1; i++) number[i] = 0; number[len - 1] = v; } public BigNumber(string str)//文字列をBigNumberに変換 { string numStr = "0123456789", s = ""; BigNumber X = new BigNumber(0); for (int i = 0; i < str.Length; i++) { string c = str.Substring(i, 1); if (c == "+") sign = false; else if (c == "-") sign = true; else { short D = (short)numStr.IndexOf((string)c); if (D >= 0) s = c + s;} } int len = (s.Length + 1) / 2; short[] num = new short[len]; for (int i = 0; i < s.Length; i += 2) { string c = s.Substring(i, 1); if ((i + 2) <= s.Length) c = s.Substring(i + 1, 1) + c; num[i / 2] = short.Parse(c); } int k; for (k = len - 1; k >= 0; k--) if (num[k] != 0) break; number = new short[k + 1]; for (int i = 0; i <= k; i++) number[i] = num[i]; } //====== 共通処理 ====================================================================== public override string ToString()//BigNumberを文字列に変換 { int Len = number.Length; if (Len == 0) return "0"; string S = ""; if (sign) S = "-"; S += number[Len - 1].ToString(); for (int i = Len - 2; i >= 0; i--) S += number[i].ToString("00"); return S; } public static string sepStr(string S, int Loop) //文字列を空白で区切る { return sepStr(true, true, S, 10,Loop); } public static string sepStr(bool Flag, bool cr, string S, int NN, int Loop) { string R = ""; for (int i = 0, k = 1; i < Loop; i += NN, k++) { if (Flag && ((k - 1) % 5) == 0) R += "(" + i.ToString("0000") + ") : "; int N = NN; if ((S.Length - i) < N) N = S.Length - i; R += S.Substring(i, N) + " "; if (cr && (k % 5) == 0) R += "\r\n"; } return R; } public double ToDouble()// BigNumberをdoubleに変換 { double S=0; int Len = number.Length; if (Len == 0) return 0.0; for (int i = Len - 1; i >= 0; i--) S = S * 100 + number[i]; if (sign) S = -S; return S; } public Boolean odd() // 奇数のチェック {  if (number.Length <= 0) return false; return ((number[0] & 1) != 0); } public static Boolean odd(BigNumber A) { if (A.number.Length <= 0) return false; return ((A.number[0] & 1) != 0); } public Boolean even()// 偶数のチェック { if (number.Length <= 0) return true; return ((number[0] & 1) == 0); } public static Boolean even(BigNumber A) { if (A.number.Length <= 0) return true; return ((A.number[0] & 1) == 0); } public void setShort(int N, short[]num, short[]number) { for (int i = 0; i < N; i++) number[i] = num[i]; } public BigNumber omit()//上位の0を省略する。 { int N = number.Length; if (N == 0) return new BigNumber(0); for (int i = N - 1; i >= 0; i--) if (number[i] != 0) return new BigNumber(sign, number, i + 1); return new BigNumber(0); } public BigNumber addMini(short dt) //0〜99を加算 { int N = number.Length; if (N == 0) return new BigNumber((int)dt); short[] num = new short[N + 1]; short dt2 = (short)(number[0] + dt); num[0] = (short)(dt2 % 100); for (int i = 1; i < N; i++) { dt2 /= 100; dt2 += number[i]; num[i] = (short)(dt2 % 100);} num[N] = (short)(dt2 / 100); if (num[N] != 0) N = N + 1; return new BigNumber(sign, num, N); } public BigNumber addAbs(BigNumber dt) //絶対値の加算 { int N1 = number.Length ; if (N1 == 0) return dt; int N2 = dt.number.Length; if (N2 == 0) return new BigNumber(sign, number, N1); int N = N1; if (N < N2) N = N2; short[] num = new short[N + 1]; short dt2 = (short)(number[0] + dt.number[0]); num[0] = (short)(dt2 % 100); for (int i = 1; i < N; num[i] = (short)(dt2 % 100), i++) { dt2 /= 100; if (i < N1) dt2 += number[i]; if (i < N2) dt2 += dt.number[i]; } num[N] = (short)(dt2 / 100); if (num[N] != 0) N = N + 1; return new BigNumber(sign, num, N); } public BigNumber subAbs(BigNumber dt) // (絶対値の減算提 { // (注)引かれる値の方が大きいことを前提 int N1 = number.Length; int N2 = dt.number.Length; if (N1 == 0) return new BigNumber(!dt.sign, dt.number); if (N2 == 0) return new BigNumber(sign, number, N1); int N = N1; short[] num = new short[N]; short T = 0; for (int i = 0; i < N2; i++) { if ((T = (short)(number[i] - dt.number[i] - T)) >= 0) { num[i] = T; T = 0; } else { num[i] = (short)(T + 100); T = 1; } } for (int i = N2; i < N1; i++) { if ((T = (short)(number[i] - T))>= 0) { num[i] = T; T = 0; } else { num[i] = (short)(T + 100); T = 1; } } BigNumber C = new BigNumber(sign, num, N); return C.omit(); } public int compareAbs(BigNumber dt) //絶対値の大きさ比較 { int N1 = number.Length; int N2 = dt.number.Length; if (N1 == 0 && N2 == 0) return 0; if (N1 > N2) return 1; else if (N1 < N2) return -1; for (int i = N1 - 1; i >= 0; i--) if (number[i] > dt.number[i]) return 1; else if (number[i] < dt.number[i]) return -1; return 0; } public BigNumber multMini(short dt) // 0〜99を乗算 { int N = number.Length; if (N == 0 || dt == 0) return new BigNumber(0); short[] num = new short[N + 1]; int T0 = 0; for (int i = 0; i < N; i++, T0 /= 100) { T0 += number[i] * dt ; num[i] = (short)(T0 % 100);} num[N] = (short)T0; if (num[N] != 0) N = N + 1; return new BigNumber(sign, num, N); } public static void clearArray(short[] A)//配列のクリア { for (int i = 0; i < A.Length; i++) A[i] = 0; } public BigNumber multAbs(BigNumber dt) //BigNumber同士の乗算 { int i, j, U, N1 = number.Length, N2 = dt.number.Length; if (N1 == 0 || N2 == 0) return new BigNumber(0); int N = N1 + N2; short[] num = new short[N + 1]; clearArray(num); for (j = 0; j < N2; j++) { if ((U = dt.number[j]) != 0) { int T0 = 0; for (i = 0; i < N1; num[i + j] = (short)(T0 % 100), i++, T0 /= 100) T0 += num[i + j] + number[i] * U; for (i = N1 + j, T0 = num[i] + T0; T0 >= 100; i++, T0 = num[i] + 1) num[i] = (short)(T0 - 100); num[i] = (short)T0; } } BigNumber X = new BigNumber(sign, num, N); return X.omit(); } //---------------------------------------------------------------------- 1〜99で除算 public int divMiniProc(int N, short[] num, short dt)//除算基本処理 { int T0 = 0; for (int i = N - 1; i >= 0;num[i] = (short)(T0 / dt), T0 -= (num[i] * dt), i--) T0 = T0 * 100 + number[i]; return T0; } public short modMini(short dt) // 剰余を返す { if (dt == 0) MessageBox.Show("0で除算しました"); int N = number.Length; if (N == 0 || dt == 0) return 0; short[] num = new short[N]; int T0 = divMiniProc(N, num, dt); return (short)T0; } public BigNumber divMini(short dt)// 商を返す { if (dt == 0) MessageBox.Show("0で除算しました"); int N = number.Length; if (N == 0 || dt == 0) return new BigNumber(0); short[] num = new short[N]; int T0 = divMiniProc(N, num, dt); return (new BigNumber(sign, num, N)).omit(); } //----------------------------------------------------------------- BigNumberで除算 public int quot(int V, BigNumber dt, short[] C, short[] R, int j) { // 商×除数 ≦ 被除数となるよう商の値を調整する. int i, k, T, N2 = dt.number.Length, Q1 = V / dt.number[N2 - 1]+1; bool lessThan = true; do { Q1--; clearArray(C); T = 0; // 乗算 dt * Q1 → C for (i = 0; i < N2; T /= 100, i++) { T += dt.number[i] * Q1; C[i] = (short)(T % 100); } C[N2] = (short)T; k = j + N2; lessThan = false; // CとRのN2桁分の大小比較 for (i = N2; i >= 0; i--, k--) if (R[k] > C[i]) return Q1; else if (R[k] < C[i]) { lessThan = true; break; } } while (lessThan); return Q1; } public void divProc(int N, int N2, BigNumber dt, short[] R, short[] Q) { // 除算の基本処理 int Q1, T, k = N2, jk = N - 1, V = 0; short[] C = new short[N2 + 1]; for (int j = N - N2; j >= 0; j--) { // Vは前回の計算での残った桁の値 int N3 = N2 + j - 1; V = V * 100 + R[N3]; if (V >= dt.number[N2 - 1]) { Q1 = quot(V, dt, C, R, j); T = 0; k = j; for (int i = 0; i <= N2; i++, k++) // Q1を乗じた分(C)をRから差し引く { T = (short)(R[k] - C[i] - T); if (T >= 0) { R[k] = (short)T; T = 0; } else { R[k] = (short)(T + 100); T = 1; } } V = 0; for (int i = N; i >= N3; i--) V = V * 100 + R[i]; Q[j] = (short)Q1; } } } public void moveShort(int N, short[] R)//配列の移動 { for (int i = 0; i < N; i++) R[i] = number[i]; } public BigNumber divAbs(BigNumber dt)//除算の商 { int N = number.Length; int N2 = dt.number.Length; if (N2 == 0) MessageBox.Show("0で除算しました"); if (N == 0 || N2 == 0) return new BigNumber(0); if (N2 == 1) return divMini(dt.number[0]); int flag = compareAbs(dt); if (flag == 0) return new BigNumber(1); else if (flag < 0) return new BigNumber(0); short[] R = new short[N + 1]; moveShort(N, R); R[N] = 0; int NR = N - N2 + 1; short[] Q = new short[NR]; divProc(N, N2, dt, R, Q); return new BigNumber(false, Q, NR).omit(); } public BigNumber modAbs(BigNumber dt)//除算の剰余 { int N = number.Length; int N2 = dt.number.Length; if (N2 == 0) MessageBox.Show("0で除算しました"); if (N == 0 || N2 == 0) return new BigNumber(0); if (N2 == 1) return new BigNumber(modMini(dt.number[0])); int flag = compareAbs(dt); if (flag == 0) return new BigNumber(0); else if (flag < 0) return dt; short[] R = new short[N + 1]; moveShort(N, R); R[N] = 0; int NR = N - N2 + 1; short[] Q = new short[NR]; divProc(N, N2, dt, R, Q); return (new BigNumber(false, R, N)).omit(); } public BigNumber Abs(){ return new BigNumber(false, number);} public static BigNumber Abs(BigNumber A) { return new BigNumber(false, A.number); } //------ 符号付き加算 -------------------------------------------------------------- public static BigNumber addB(BigNumber A, BigNumber B)// A + B { // 同一符号のとき絶対値加算。異符号のとき絶対値減算 BigNumber C; int check; if (A.sign == B.sign) { C = A.addAbs(B); C.sign = A.sign; } else if ((check = A.compareAbs(B)) == 0) C = new BigNumber(0); else if (check > 0) { C = A.subAbs(B); C.sign = A.sign; } else { C = B.subAbs(A); C.sign = B.sign; } return C; } public static BigNumber addB(int A, BigNumber B){return addB(new BigNumber(A),B);} public static BigNumber addB(BigNumber A, int B){return addB(A,new BigNumber(B));} //------ 符号付き減算 -------------------------------------------------------------- public static BigNumber subB(BigNumber A, BigNumber B)// A - B { // 同一符号のとき絶対値加算。異符号のとき絶対値減算 BigNumber C; int check; if (A.sign != B.sign){ C = A.addAbs(B); C.sign = A.sign; } else if ((check = A.compareAbs(B)) == 0) C = new BigNumber(0); else if (check > 0) { C = A.subAbs(B); C.sign = A.sign; } else { C = B.subAbs(A); C.sign = !A.sign; } return C; } public static BigNumber minusB(BigNumber A) {  if (A.number.Length == 0) return new BigNumber(0); return new BigNumber(!A.sign, A.number); } public static BigNumber subB(int A, BigNumber B){ return subB(new BigNumber(A), B);} public static BigNumber subB(BigNumber A, int B){ return subB(A, new BigNumber(B));} //------ 符号付き乗算 -------------------------------------------------------------- public static BigNumber mltB(BigNumber A, BigNumber B)// A * B { BigNumber C; if (A.compareAbs(B) >= 0) C = A.multAbs(B); else C = B.multAbs(A); C.sign = !(A.sign == B.sign); return C; } public static BigNumber mltB(int A, BigNumber B) {return mltB(new BigNumber(A), B);} public static BigNumber mltB(BigNumber A, int B) {return mltB(A, new BigNumber(B));} //------ 符号付き除算 -------------------------------------------------------------- public static BigNumber divB(BigNumber A, BigNumber B)// A / B { BigNumber QR = A.divAbs(B); QR.sign = !(A.sign == B.sign); return QR; } public static BigNumber divB(int A, BigNumber B) {return divB(new BigNumber(A), B); } public static BigNumber divB(BigNumber A, int B) {return divB(A, new BigNumber(B)); } //------ 符号付き剰余 -------------------------------------------------------------- public static BigNumber modB(BigNumber A, BigNumber B) // A % B { BigNumber QR = A.modAbs(B); QR.sign = !(A.sign == B.sign); return QR; } public static BigNumber modB(int A, BigNumber B) {return modB(new BigNumber(A), B);} public static BigNumber modB(BigNumber A, int B) {return modB(A, new BigNumber(B));} //------ 符号付き比較(equal) ------------------------------------------------------ public static bool eq0(BigNumber X)//BigNumberが0かどうかの判定 { return X.omit().number.Length == 0; } public static bool eqB(BigNumber A, BigNumber B)// 等しい(equal) { if (A.number.Length == 0) return (B.number.Length == 0); else if ((B.number.Length == 0) || (A.sign != B.sign)) return false; return A.compareAbs(B) == 0; } public static bool eqB(int A, BigNumber B) { return eqB(new BigNumber(A), B); } public static bool eqB(BigNumber A, int B) { return eqB(A, new BigNumber(B)); } //------ 符号付き比較(greater than) ------------------------------------------------- public static bool gtB(BigNumber A, BigNumber B) { if (A.number.Length == 0 && B.number.Length == 0) return false; else if (A.number.Length == 0) return B.sign; // A = 0 のとき B が負ならばtrue else if (B.number.Length == 0) return !A.sign; // B = 0 のとき A が正ならばtrue else if (A.sign && B.sign) return (A.compareAbs(B) < 0);// 両方が負ならば絶対値小が大 else if (A.sign) return false; else return ((B.sign) || (A.compareAbs(B) > 0));// 両方が正のとき絶対値大が大 } public static bool gtB(int A, BigNumber B) { return gtB(new BigNumber(A), B); } public static bool gtB(BigNumber A, int B) { return gtB(A, new BigNumber(B)); } //------ 符号付き比較(less than) ---------------------------------------------------- public static bool ltB(BigNumber A, BigNumber B) { if (A.number.Length == 0) return !((B.number.Length == 0) || B.sign); else if (B.number.Length == 0) return A.sign;     // B=0,A<0のとき else if (A.sign && B.sign) return (A.compareAbs(B) > 0);// ABともに負のとき else if (A.sign) return true; // A<0 & B>0 else if (B.sign) return false; // A>0 & B<0 else return (A.compareAbs(B) < 0); // ABともに正 } public static bool ltB(int A, BigNumber B) { return ltB(new BigNumber(A), B); } public static bool ltB(BigNumber A, int B) { return ltB(A, new BigNumber(B)); } //====== 演算子(operator)定義 ===================================================== public static BigNumber operator ++(BigNumber A) { return addB(A, 1); } public static BigNumber operator --(BigNumber A) { return subB(A, 1); } public static BigNumber operator +(BigNumber A, BigNumber B) { return addB(A, B); } public static BigNumber operator +(int A, BigNumber B) { return addB(A, B); } public static BigNumber operator +(BigNumber A, int B) { return addB(A, B); } public static BigNumber operator +(BigNumber A) { return A ; } public static BigNumber operator -(BigNumber A, BigNumber B) { return subB(A, B); } public static BigNumber operator -(int A, BigNumber B) { return subB(A, B); } public static BigNumber operator -(BigNumber A, int B) { return subB(A, B); } public static BigNumber operator -(BigNumber A) { return minusB(A) ; } public static BigNumber operator *(BigNumber A, BigNumber B) { return mltB(A, B); } public static BigNumber operator *(int A, BigNumber B) { return mltB(A, B); } public static BigNumber operator *(BigNumber A, int B) { return mltB(A, B); } public static BigNumber operator /(BigNumber A, BigNumber B) { return divB(A ,B); } public static BigNumber operator /(int A, BigNumber B) { return divB(A, B); } public static BigNumber operator /(BigNumber A, int B) { return divB(A, B); } public static BigNumber operator %(BigNumber A, BigNumber B) { return modB(A, B); } public static BigNumber operator %(int A, BigNumber B) { return modB(A, B); } public static BigNumber operator %(BigNumber A, int B) { return modB(A, B); } public static bool operator ==(BigNumber A, BigNumber B) { return eqB(A ,B); } public static bool operator ==(int A, BigNumber B) { return eqB(A, B); } public static bool operator ==(BigNumber A, int B) { return eqB(A, B); } public static bool operator !=(BigNumber A, BigNumber B) { return !(A == B); } public static bool operator !=(int A, BigNumber B) { return !(A == B); } public static bool operator !=(BigNumber A, int B) { return !(A == B); } public static bool operator >(BigNumber A, BigNumber B) { return gtB(A, B); } public static bool operator >(int A, BigNumber B) { return gtB(A, B); } public static bool operator >(BigNumber A, int B) { return gtB(A, B); } public static bool operator <(BigNumber A, BigNumber B) { return ltB(A, B); } public static bool operator <(int A, BigNumber B) { return ltB(A, B); } public static bool operator <(BigNumber A, int B) { return ltB(A, B); } public static bool operator >=(BigNumber A, BigNumber B) { return !(A < B) ; } public static bool operator >=(int A, BigNumber B) { return !(A < B) ; } public static bool operator >=(BigNumber A, int B) { return !(A < B) ; } public static bool operator <=(BigNumber A, BigNumber B) { return !(A > B) ; } public static bool operator <=(int A, BigNumber B) { return !(A > B) ; } public static bool operator <=(BigNumber A, int B) { return !(A > B) ; } //====== マチンの公式による円周率πの計算(整数部を最高桁位置とする) =============== public static BigNumber compPi(int MX)//円周率πの計算 { int MXX = MX + 1; BigNumber Pi = new BigNumber(0), T = new BigNumber(false, MXX, 16); T = T.divMini(5); BigNumber K = new BigNumber(1), U = T; do { Pi = Pi.addAbs(U); T = T.divMini(25); K = K.addMini(2); U = T.divAbs(K); Pi = Pi.subAbs(U); T = T.divMini(25); K = K.addMini(2); U = T.divAbs(K); } while (U.number.Length != 0); T = new BigNumber(false, MXX, 4); BigNumber N239 = new BigNumber(239), N239sq = N239.multAbs(N239); T = T.divAbs(N239); K = new BigNumber(1); U = T; do { Pi = Pi.subAbs(U); T = T.divAbs(N239sq); K = K.addMini(2); U = T.divAbs(K); Pi = Pi.addAbs(U); T = T.divAbs(N239sq); K = K.addMini(2); U = T.divAbs(K); } while (U.number.Length != 0); return Pi; } //====== マクローリン級数でネイピア数 e(自然対数の底)を求める ===================== public static BigNumber compE(int MX)//ネイピア数e(自然対数の底)計算 { BigNumber E = new BigNumber(false, MX + 1, 1), K = new BigNumber(1), T = E; do { E = E.addAbs(T); K = K.addMini(1); T = T.divAbs(K); } while (T.number.Length != 0); return E; } //====== EqualsとGetHashのoverride(これを入れないと警告エラーとなる)=============== public override bool Equals(object obj) { return base.Equals(obj); } public override int GetHashCode() { return base.GetHashCode(); } } }