using System;
using System.IO;			// for StreamWriter I/O to a file
using System.Windows.Forms;	// for RichTextBox

namespace MyNamespace
{
	/// <summary>
	///		Extra precision Integer List algorithms
	///		Developed in TURBO Pascal 5.5 and 6.0, converted to Visual Basic 6
	///		and now in Visual C# .Net
	///
	/// ---------------- *** LEGAL NOTICE: *** ------------------
	///
	/// This program is free software; you can redistribute it and/or modify
	/// it under the terms of the GNU General Public License (GPL) as published
	/// by the Free Software Foundation. cf. the file COPYING.txt.
	///
	/// ------------ *** end of legal notice *** ------------------
	/// </summary>

	public class XICommon
	{
		public XICommon()
		{
			pTabFile = Global.pName + "PTab.txt";
			pTabBak = Global.pName + "PTab.Bak";
			nL = Environment.NewLine;
		}

		public static int CompN(int xI, int zI) // CompN = sign(zI - xI)
		{
			return MultiID.CompSI(Common.nList[xI], Common.nList[zI]); // CompSI = sign(dI - qI)
		}

		public static void ReSizeN(int min, MultiSI x, MultiSI z) // size z = size x
		// z may be left un-normalized
		{
			int zM;
			int xM = x.M;
			if (xM < min) xM = min;
			zM = z.M;
			if (xM == zM) return;
			Common.ReDimPreserve(ref z.V, xM + 1);
			z.M = xM;
			if (z.N > xM) z.N = xM;
		}

		public static void ReSizeN(int min, MultiSI x, int zI) // size z = size x
		// z may be left un-normalized
		{
			ReSizeN(min, x, Common.nList[zI]);
		}

		public static void ReSizeN(int min, int xI, int zI) // size z = size x
		// z may be left un-normalized
		{
			ReSizeN(min, Common.nList[xI], Common.nList[zI]);
		}

		public static void DigDN(MultiSI x, int zI) // z = number of decimal digits in x
		{
			int d;			// a decimal digit
			int sD;			// a super digit
			int num = 0;	// number of decimal digits
			int maxI = x.N - 1;	// max index
			num = MultiID.muDMax * maxI;
			sD = x.V[maxI];
			while (sD != 0)
			{
				sD = Math.DivRem(sD, 10, out d);
				num++;
			}
			MultiID.SetTo1SI(num, Common.nList[zI]);
			Calc.NormN(zI);
		} // DigDN

		public static void DigDN(int zI) // z = number of decimal digits in z
		{
			DigDN(Common.nList[zI], zI);
		} // DigDN

		public static void DigN(MultiSI x, MultiSI y, int zI) // z = number of digits in x, base y
		{
			if (y.N == 1)
			{
				int b = y.V[0];
				if (b < 2)
				{
					MultiID.WriteLn("SumD: Base changed from " + b + " to 10");
					b = 10;
				}
				if (b == 10)
				{
					DigDN(x, zI);
					return;
				}
			}
			int bI;
			int qI;
			Common.InitNAdd(y.N, "SumDN-bI", out bI);	// base
			Common.InitNAdd(x.N, "SumDN-qI", out qI);	// quotient
			Calc.SetToN(x, qI);
			Common.nList[qI].S = false;
			Calc.SetToN(y, bI);
			Common.nList[bI].S = false;
			Calc.ClearN(zI);
			int rI;
			Common.LFindAdd("Re", out rI);
			while (Common.nList[qI] != MultiID.sZero)
			{
				DivN(qI, bI, qI);
				MultiID.RAdd1SI(1, Common.nList[zI]);
			}
			Common.LDelete(qI);
			Common.LDelete(bI);
			Calc.NormN(zI);
		} // DigN

		public static void DigN(int yI, int zI) // z = number of digits in z, base y
		{
			DigN(Common.nList[zI], Common.nList[yI], zI);
		} // DigN

		public static void SumDDN(int zI) // z = sum of decimal digits in z
		{
			int d;			// a decimal digit
			int sD;			// a super digit
			int sum = 0;	// sum of decimal digits
			for (int i = 0; i < Common.nList[zI].N; i++)
			{
				sD = Common.nList[zI].V[i];
				while (sD != 0)
				{
					sD = Math.DivRem(sD, 10, out d);
					sum += d;
				}
			}
			MultiID.SetTo1SI(sum, Common.nList[zI]);
			Calc.NormN(zI);
		}

		public static void SumDN(MultiSI x, MultiSI y, int zI) // z = sum of digits in x, base y
		{
			if (y.N == 1)
			{
				int b = y.V[0];
				if (b < 2)
				{
					MultiID.WriteLn("SumD: Base changed from " + b + " to 10");
					b = 10;
				}
				if (b == 10)
				{
					Calc.SetToN(x, zI);
					SumDDN(zI);
					return;
				}
			}
			int bI;
			int qI;
			Common.InitNAdd(y.N, "SumDN-bI", out bI);	// base
			Common.InitNAdd(x.N, "SumDN-qI", out qI);	// quotient
			Calc.SetToN(x, qI);
			Common.nList[qI].S = false;
			Calc.SetToN(y, bI);
			Common.nList[bI].S = false;
			Calc.ClearN(zI);
			int rI;
			Common.LFindAdd("Re", out rI);
			while (Common.nList[qI] != MultiID.sZero)
			{
				DivN(qI, bI, qI);
				RAddN(rI, zI);
			}
			Common.LDelete(qI);
			Common.LDelete(bI);
			Calc.NormN(zI);
		} // SumDN

		public static void SumDN(int yI, int zI) // z = sum of digits in z, base y
		{
			SumDN(Common.nList[zI], Common.nList[yI], zI);
		} // SumDN

		public static void RevN(int xI, int yI, int zI) // z = reversed digits of x base y
		{
			MultiSI x = new MultiSI(Common.nList[xI].N);
			MultiSI y = new MultiSI(1);
			MultiSI q = new MultiSI(1);
			MultiSI d = new MultiSI(1);
			MultiID.SetToSI(Common.nList[xI], x);
			if (Common.nList[yI] > MultiID.sOne)
				MultiID.SetToSI(Common.nList[yI], y);
			else
				y.V[0] = 10;
			x.S = false;
			while (x != 0)
			{
				d &= x % y;
				q = q * y + d;
				x /= y;
			}
			q.S = Common.nList[xI].S;
			MultiID.SetToSI(q, Common.nList[zI]);
			MultiID.DoneSI(d);
			MultiID.DoneSI(q);
			MultiID.DoneSI(y);
			MultiID.DoneSI(x);
		} // RevN

		public static void DivN(int xI, int yI, int zI) // z = x / y, "Re" = Remainder
		// sets muErr true if overflow
		{
			int rI;
			Common.LFindAdd("Re", out rI);
			if (rI == zI || rI == Common.iTop)
			{
				MultiID.MuWriteErr(
					"Cannot set same location to both quotient and remainder, continuing...");
				return;
			}
			ReSizeN(4, yI, rI);
			int m = Common.nList[xI].N;
			int tI;
			Common.InitNAdd(m, "DivN-tI", out tI);
			MultiID.DivQRSI(Common.nList[xI], Common.nList[yI], Common.nList[rI], Common.nList[tI]);
			if (MultiID.muErr)
				Calc.SetToN(MultiID.sZero, rI);
			Calc.NormN(rI);
			Calc.SetToII(tI, zI);
			Common.LDelete(tI);
			Calc.NormN(zI);
		} // DivN

		public static void ShiftL(long iL, MultiSI z) // z = z, iL "digits" more
		// Sets muErr true if overflow
		{
			int i;
			if (iL == 0) return;
			if (iL < 0)
			{
				ShiftR(-iL, z);
				return;
			}
			if (iL > Int32.MaxValue) iL = Int32.MaxValue;
			if (iL < Int32.MinValue) iL = Int32.MinValue;
			int iLi = (int)iL;
			if (iLi > (z.M - z.N))
			{
				MultiID.MuWriteErr("Signed Integer shift left overflow, continuing...");
				MultiID.ClearSI(z);
				return;
			}
			for (i = (z.N - 1); i >= 0; i--)
			{
				z.V[i + iLi] = z.V[i];
			}
			for (i = 0; i < iLi; i++)
			{
				z.V[i] = 0;
			}
			z.N += iLi;
		} // ShiftL

		public static void ShiftR(long iR, MultiSI z) // z = z, iR "digits" less
		// Sets muErr true if overflow
		{
			int i;
			if (iR == 0) return;
			if (iR < 0)
			{
				ShiftL(-iR, z);
				return;
			}
			if (iR > Int32.MaxValue) iR = Int32.MaxValue;
			if (iR < Int32.MinValue) iR = Int32.MinValue;
			int iRi = (int)iR;
			if (iRi >= z.N)
			{
				MultiID.ClearSI(z);
				return;
			}
			for (i = 0; i < z.N - iRi; i++)
			{
				z.V[i] = z.V[i + iRi];
			}
			for (i = z.N - iRi; i < z.N; i++)
			{
				z.V[i] = 0;
			}
			z.N -= iRi;
		} // ShiftR

		public static void CubeRtSI(MultiSI x, MultiSI z) // z = CubeRt(x) = x^(1/3), sets muErr true if overflow
		{
			double db;
			double rt;
			bool sign = x.S;	// x and z may be the same object, so save sign of x
			MultiSI dblSI = new MultiSI(2);
			dblSI &= MultiID.dblMaxValue;
			if (MultiID.AbCompUI(dblSI, x) <= 0)
			{
				MultiID.GetDbSI(out db, x);
				db = Math.Abs(db);
				rt = Math.Ceiling(Math.Pow(db, 1.0 / 3.0)); // 64^(1/3) = 3.99999999999
				if (rt * rt * rt > db) rt--;
				z &= rt;
				z.S = sign;
				return;
			}
			int rem;
			int qu = Math.DivRem(x.N, 3, out rem);
			if (qu > 0)
			{
				rem += 3;
				qu--;
			}
			db = 0;
			for (int j = rem - 1; j >= 0; j--)
			{
				db = db * MultiID.baseM + x.V[j + 3 * qu];
			}
			rt = Math.Ceiling(Math.Pow(db + 1.0, 1.0 / 3.0));
			MultiSI g = new MultiSI(qu + 2);	// guess
			MultiSI t = new MultiSI(qu + 2);	// temp
			g &= rt;
			ShiftL(qu, g);
			x.S = false;
			bool done = false;
			do
			{
				t &= x / g;
				t /= g;				// t = x / g^2
				t += g;
				t += g;
				t /= MultiID.sThree;
				if (t >= g) done = true;
				else g &= t;
			}
			while (!done && !MultiID.muErr && !MultiID.muAbort);
			z &= g;
			x.S = sign;			// restore sign of x
			z.S = sign;			// set sign of z
			MultiID.DoneSI(t);
			MultiID.DoneSI(g);
			if (MultiID.muErr || MultiID.muAbort) z &= 0;
		} // CubeRtSI

		public static void CubeRtRemN(int xI, int zI) // z = CubeRt(x) = x^(1/3), "Re" = Remainder
		{
			int rI;
			Common.LFindAdd("Re", out rI);
			if (rI == zI || rI == Common.iTop)
			{
				MultiID.MuWriteErr("Cannot set same location to both cube root and remainder, continuing...");
				return;
			}
			MultiSI re = new MultiSI();
			CubeRtSIR(Common.nList[xI], Common.nList[zI], re);
			Calc.SetToN(re, rI);
		} // CubeRtRemN

		public static void CubeRtN(int xI, int zI) // z = CubeRt(x) = x^(1/3)
		{
			CubeRtSI(Common.nList[xI], Common.nList[zI]);
			Calc.NormN(zI);
		} // CubeRtN

		public static void CubeRtSIR(MultiSI x, MultiSI z, MultiSI r) // z = CubeRt(x) = x^(1/3), r = remainder
		{
			int n = x.N;
			MultiID.SetToSIN(x, r);	// save x, may be same object as z
			CubeRtSI(x, z);
			bool sign = x.S;
			z.S = false;
			r.S = false;
			r &= (r - z * z * z);
			MultiSI t = new MultiSI(n);	// temp
			t &= 3 * z * (z + 1);		// t = 3 * z * (z + 1) = max remainder
			if (r > t || r.S)
				MultiID.MuWriteErr("Unexpected error in Cube Root function");
			z.S = sign;								// make rI >= 0
			if (!MultiID.ZTestSI(r)) r.S = sign;
			if (r.S)
			{
				MultiID.RAdd1SI(-1, z);
				MultiID.RAddSI(t, r);
				MultiID.RAdd1SI(1, r);
			}
			MultiID.DoneSI(t);
			MultiID.NormSI(r);
			MultiID.NormSI(z);
		} // CubeRtSIR

		public static void SqRtRemN(MultiSI x, int zI) // z = SqRt(x), "Re" = Remainder
		// sets muErr true if overflow
		{
			int rI;
			Common.LFindAdd("Re", out rI);
			if (rI == zI || rI == Common.iTop)
			{
				MultiID.MuWriteErr("Cannot set same location to both square root and remainder, continuing...");
				return;
			}
			Calc.ClearN(rI);
			ReSizeN(4, x, rI);
			ReSizeN(4, x, zI);
			MultiID.SqRtRemSI(x, Common.nList[rI], Common.nList[zI]);
			Calc.NormN(rI);
			Calc.NormN(zI);
		} // SqRtNRem

		public static void SqRtRemN(int xI, int zI) // z = SqRt(x), "Re" = Remainder
		// sets muErr true if overflow
		{
			SqRtRemN(Common.nList[xI], zI);
		}

		public static void SqRtN(MultiSI x, int zI) // z = SqRt(x)
		// sets muErr true if overflow
		{
			ReSizeN(4, x, zI);
			MultiID.SqRootSI(x, Common.nList[zI]);
			Calc.NormN(zI);
		} // SqRtN

		public static void SqRtN(int xI, int zI) // z = SqRt(x)
		// sets muErr true if overflow
		{
			SqRtN(Common.nList[xI], zI);
		}

		public static void RAddSIN(MultiSI x, int zI) // z = z + x
		// sets muErr true if overflow
		{
			int m;
			int tI;
			int nX = x.N;
			int nZ = Common.nList[zI].N;
			if (nX > nZ) { m = nX; } else { m = nZ; }
			Common.InitNAdd(m + 1, "RAddSIN-tI", out tI);
			MultiID.AddSI(Common.nList[zI], x, Common.nList[tI]);
			Calc.SetToII(tI, zI);
			Common.LDelete(tI);
			Calc.NormN(zI);
		}

		public static void RAddN(int xI, int zI) // z = z + x
		// sets muErr true if overflow
		{
			int m;
			int tI;
			int nX = Common.nList[xI].N;
			int nZ = Common.nList[zI].N;
			if (nX > nZ) { m = nX; } else { m = nZ; }
			Common.InitNAdd(m + 1, "RAddN-tI", out tI);
			MultiID.AddSI(Common.nList[zI], Common.nList[xI], Common.nList[tI]);
			Calc.SetToII(tI, zI);
			Common.LDelete(tI);
			Calc.NormN(zI);
		}

		public static void RSubN(int xI, int zI) // z = z - x
		// sets muErr true if overflow
		{
			if (xI == zI)
			{
				MultiID.ClearSI(Common.nList[zI]);
				Calc.NormN(zI);
			}
			else
			{
				Common.nList[xI].S = !Common.nList[xI].S;
				RAddN(xI, zI);
				Common.nList[xI].S = !Common.nList[xI].S;
			}
		}

		public static void RMulN(int xI, int zI) // z = z * x
		// sets muErr true if overflow
		{
			MulN(xI, zI, zI);
		}

		public static void AddSIN(MultiSI x, MultiSI y, int zI) // z = x + y
		// sets muErr true if overflow
		{
			Calc.SetToN(x + y, zI);
			Calc.NormN(zI);
		}

		public static void SubSIN(MultiSI x, MultiSI y, int zI) // z = x - y
		// sets muErr true if overflow
		{
			Calc.SetToN(x - y, zI);
			Calc.NormN(zI);
		}

		public static void GenPrimeTable(int n) // generate prime table to file with n entries
		{
			int i;
			double pi = 0;		// count of the number of primes = Pi(p)
			double p = 0;		// final prime
			int nr;				// the current length of the internal tables returned
			StreamWriter outF = null;
			string savDir = Environment.CurrentDirectory.ToString();
			Directory.SetCurrentDirectory(Common.homeDir);
			try
			{
				FileInfo FIa = new FileInfo(pTabFile);
				FileInfo FIb = new FileInfo(pTabBak);
				if (FIa.Exists)
				{
					FIb.Delete();		 // delete the backup if any
					FIa.MoveTo(pTabBak); // save (rename) previous file as a backup
				}
			}
			catch (Exception ex)
			{
				// -------- Trap for rename error handling
				Common.ReportError("GenPrimeTable", ex.Message);
			}
			try
			{
				outF = new StreamWriter(pTabFile, false); // open the new file, append = false
				if (!Common.quiet)
				{
					MultiID.WriteDLn("File " + pTabFile + " opened for writing");
					Common.WCurDir(pTabFile);
					MultiID.WriteTLn2("Generating prime number table with " + n + " primes");
				}
				DateTimePicker dateTime = new DateTimePicker();
				string dateTimeString = dateTime.Value.ToString();
				outF.WriteLine(Global.pName + " - Prime Number Table - " + dateTimeString);
				outF.WriteLine("First column is prime index the rest are consecutive primes");
				int mC = GPrimes(n);
				pi = 0;
				do
				{
					for (i = 1; i <= mC; i++)
					{
						pi++;
						p = NPrimes.iP[i];
						if (pi == 1 || pi % 10 == 0)
						{
							outF.Write(nL + pi);
						}
						outF.Write(" " + p);
						if (pi >= n) break; // exit for
					}
					if (pi >= n) break; // exit do
					if (!Common.quiet) MultiID.WriteLn(pi + " " + p);
					MultiID.MuInterrupt();
					if (MultiID.muAbort) break; // exit do
					nr = NPrimes.NPrime(mC);		// generate mC more primes
				}
				while (true);
			}
			catch (Exception ex)
			{
				// -------- Trap for error handling
				Common.ReportError("GenPrimeTable", ex.Message);
			}
			finally
			{
				if (outF != null)
				{
					outF.WriteLine(nL + "End of file " + pTabFile);
					outF.Close();
				}
				if (!Common.quiet && !MultiID.muAbort) MultiID.WriteLn(pi + " " + p);
				Directory.SetCurrentDirectory(savDir);
				if (NPrimes.iP[1] != 2) NPrimes.NPrimeDone();
				MultiID.muErr = false; // because no value is returned to nList[nI]
			}
		} // GenPrimeTable

		public static void PrimePT(int nI)	// P(n) = The n'th prime (Called from calculator)
		{
			MultiID.ADDiag("P(n) = The n'th prime:");
			if (!PrimeFA.pTabFilled) PrimeFA.FillPTab();
			Common.nList[nI].S = false;
			PrimeP(nI);
			Calc.NormN(nI);
		} // PrimePT

		public static void MulN(int xI, int yI, int zI)	// z = x * y
		// sets muErr true if overflow
		{
			int nX;
			int nY;
			int m;
			int tI;
			int zX = 0;
			int zY = 0;
			if (Common.nList[xI] == MultiID.sZero || Common.nList[yI] == MultiID.sZero)
			{
				Calc.ClearN(zI);
				Calc.NormN(zI);
				return;
			}
			nX = Common.nList[xI].N;
			nY = Common.nList[yI].N;
			for (int i = 0; i < nX; i++)
			{
				if (Common.nList[xI].V[i] == 0)
					zX++;
				else
					i = nX;
			}
			ShiftR(zX, Common.nList[xI]);
			if (xI == yI)
				zY = zX;
			else
			{
				for (int i = 0; i < nY; i++)
				{
					if (Common.nList[yI].V[i] == 0)
						zY++;
					else
						i = nY;
				}
				ShiftR(zY, Common.nList[yI]);
			}
			m = nX + nY;
			Common.InitNAdd(m, "MulN-tI", out tI);
			MultiID.MulSI(Common.nList[xI], Common.nList[yI], Common.nList[tI]);
			ShiftL(zX + zY, Common.nList[tI]);
			Calc.SetToII(tI, zI);
			Common.LDelete(tI);
			Calc.NormN(zI);
		} // MulN

		public static int GPrimes(double n) // init for Generating n Primes, if need be, return mC
		{
			int nr;							// the current length of the internal tables returned
			int mC = NPrimes.mCMaxS;		// max value allowed for mC (mC = mCMax)
			int q = 547;					// 547 = 1 + Pi(SqRt(15,485,863))
			if (n > mC)						// 15,485,863 = P(1,000,000)
			{
				double x = mC * Math.Ceiling(n / mC);
				q = 1000 + (int)Math.Sqrt(x);	// overkill, I hope
				NPrimes.jLimM = 0;				// for safety
			}
			if (NPrimes.jLimM != mC)
			{
				if (!PrimeFA.pTabFilled) PrimeFA.FillPTab();
				new NPrimes(mC, q);			// init prime number generator, max prime = 15,485,863
				nr = NPrimes.NPrime(mC);	// generate mC primes
				int i = nr;					// needed so nr can be monitored
			}
			return mC;
		} // GPrimes

		public static void PrimeP(int nI)	// P(n) = The n'th prime
		{
			int i;
			int nr;			// the current length of the internal tables returned
			double n;		// n to search for
			double pi = 0;	// count of the number of primes = Pi(p)
			double p = 0;	// final prime
			int tot = 0;
			bool done = false;
			MultiID.GetDbSI(out n, Common.nList[nI]);
			int mC = GPrimes(n);
			do
			{
				if (n - pi <= mC)
				{
					i = (int)(n - pi);
					pi = n;
					p = NPrimes.iP[i];
					done = true;
				}
				else
				{
					nr = NPrimes.NPrime(mC);	// generate mC more primes
					pi += mC;
					MultiID.MuInterrupt();
					if (MultiID.statReq2)
					{
						p = NPrimes.iP[mC];
						MultiID.WriteT("P(" + n + "): P(" + (pi + mC) + ") = " + p, ref tot);
						MultiID.TimeDel(ref tot);
						RunForm.FocusBothUs();
						MultiID.statReq2 = false;
					}
				}
			}
			while (!done && !MultiID.muAbort);
			MultiID.ReSizeSI(4, Common.nList[nI]);
			MultiID.SetToDbSI(p, Common.nList[nI]);
			if (NPrimes.iP[1] != 2) NPrimes.NPrimeDone();
		} // PrimeP

		public static void PrimePiT(int nI)
		// prime counting function Pi(n) = number of primes <= n (Called from calculator)
		{
			MultiID.ADebug("Prime Pi Function:");
			if (!PrimeFA.pTabFilled) PrimeFA.FillPTab();
			Common.nList[nI].S = false;
			PrimePi(nI);
			Calc.NormN(nI);
		} // PrimePiT

		public static void PrimePi(int nI)
		// prime counting function Pi(n) = number of primes <= n
		{
			int nr;			// the current length of the internal tables returned
			double n;		// n to search for
			double pi = 0;	// count of the number of primes = Pi(p)
			MultiID.GetDbSI(out n, Common.nList[nI]);
			int mC = NPrimes.mCMaxS;			// max value allowed for mC (mC = mCMax)
			if (NPrimes.jLimM != mC)
			{
				if (!PrimeFA.pTabFilled) PrimeFA.FillPTab();
				new NPrimes(mC, 547);			// init prime number generator, max prime = 15,485,863
				nr = NPrimes.NPrime(mC);		// generate mC primes
			}
			if (NPrimes.iP[mC] < n)
			{
				PrimeFA.PrimePiL(nI);
				return;
			}
			int a = 1;							// binary search array of primes
			int b = mC;
			int c;
			while (true)
			{
				c = (a + b) / 2;
				if (c == a) break;
				if (NPrimes.iP[c] >= n)
					b = c;
				else
					a = c;
			}
			pi += c;
			if (NPrimes.iP[c] > n) pi--;
			else if (a < b && NPrimes.iP[b] == n) pi++;
			MultiID.SetToDbSI(pi, Common.nList[nI]);
		} // PrimePi

		public static void Primorial(int nI)
		// prime counting function Primo(n) = n# = product of all primes <= n
		{
			int i;
			int nr;			// the current length of the internal tables returned
			double n;		// n to search for
			double pi = 0;	// count of the number of primes = Pi(p)
			double p = 0;	// final prime
			bool done = false;
			int tot = 0;
			if (Common.nList[nI].S)
			{
				MultiID.MuWriteErr("Cannot take primorial of number < zero");
				Calc.ClearN(nI);
				return;
			}
			MultiID.ADDiag("Primorial Function:");
			MultiID.GetDbSI(out n, Common.nList[nI]);
			n = Math.Abs(n);
			int mC = GPrimes(n);
			int tI;
			Common.InitNAdd(2, "Primorial-tI", out tI);
			MultiID.SetTo1SI(1, Common.nList[nI]);
			do
			{
				for (i = 1; i <= mC; i++)
				{
					pi++;
					p = NPrimes.iP[i];
					MultiID.SetToDbSI(p, Common.nList[tI]);
					if (p >= n)
					{
						done = true;
						if (p > n)
							pi--;
						else
							MulN(tI, nI, nI);
						break; // exit for
					}
					else
					{
						MulN(tI, nI, nI);
						if (MultiID.statReq2)
						{
							MultiID.WriteT("Primo(" + n + "): P(" + pi + ") = " + p, ref tot);
							MultiID.TimeDel(ref tot);
							RunForm.FocusBothUs();
							MultiID.statReq2 = false;
						}
					}
				}
				if (!done) nr = NPrimes.NPrime(mC);		// generate mC more primes
			}
			while (!done && !MultiID.muAbort);
			Common.LDelete(tI);
			if (NPrimes.iP[1] != 2) NPrimes.NPrimeDone();
			Calc.NormN(nI);
		} // Primorial

		public static void PrimeFAB(int nI) // prime factor algorithm b
		{
			if (MultiID.muErr) return;
			int qI;
			int dI;
			int rI;
			int i;
			int tot = 0;
			double pi = 0;	// count of the number of primes = Pi(p)
			double p;		// final prime
			int nr;			// the current length of the internal tables returned
			int mC;			// max value allowed for mC (mC = mCMax)
			int sD;			// count of number of divides by same divisor
			bool started;
			bool done = false;
			PrimeFA.complete = false;
			MultiID.ADDiag("Prime factor algorithm b:");
			if (MultiID.EQ1UI(0, Common.nList[nI]))
			{
				MultiID.WriteDLn("0 = 0.");
				return;
			}
			if (MultiID.EQ1UI(1, Common.nList[nI]))
			{
				MultiID.WriteDLn("1 = 1.");
				return;
			}
			Common.nList[nI].S = false;
			Common.DoubleSpace();
			MultiID.WriteSI(Common.nList[nI], ref tot);
			MultiID.WriteT(" = ", ref tot);
			Common.InitNAdd(Common.nList[nI].N, "PrimeFAB-qI", out qI);
			Common.InitNAdd(4, "PrimeFAB-dI", out dI);
			Common.InitNAdd(4, "PrimeFAB-rI", out rI);
			mC = 10000;
			new NPrimes(mC, 200000);	// init prime number generator for about 3,96100,00000.0 primes <= 756,33745,25281
			started = false;
			do
			{
				nr = NPrimes.NPrime(mC);	// generate next mC primes
				for (i = 1; i <= mC; i++)
				{
					pi++;
					p = NPrimes.iP[i];
					MultiID.SetToDbSI(p, Common.nList[dI]);
					sD = 0;
					do
					{
						MultiID.DivQRSI(Common.nList[nI], Common.nList[dI], Common.nList[rI], Common.nList[qI]);
						if (MultiID.muAbort || MultiID.muErr) break; // exit do
						if (Common.ZTestN(rI))
						{
							Calc.SetToII(qI, nI);
							sD++;
						}
						else
						{
							if (sD != 0)
							{
								if (started) MultiID.WriteT(" * ", ref tot);
								MultiID.WriteSI(Common.nList[dI], ref tot, 0, false);
								if (sD != 1)
									MultiID.WriteT("^" + sD, ref tot);
								started = true;
								sD = 0;
							}
							if (CompN(qI, dI) > 0) // CompN = sign(dI - qI)
							{
								if (!MultiID.EQ1UI(1, Common.nList[nI]))
								{
									if (started) MultiID.WriteT(" * ", ref tot);
									MultiID.WriteSI(Common.nList[nI], ref tot, 0, false);
								}
								done = true;
								break; // exit for
							}
							break; // exit do
						}
					}
					while (true);
					if (MultiID.muAbort || MultiID.muErr || done) break; // exit for
				}
				if (done) break;
				MultiID.MuInterrupt();
				if (MultiID.muAbort) tot = 0;	// abort has done a MultiID.WriteLn
				if (MultiID.statReq2)
				{
					tot = 0;
					Common.SingleSpace();
					MultiID.WriteT("(Testing ", ref tot);
					MultiID.ShortWrSI(40, Common.nList[nI], ref tot);
					MultiID.WriteT(" / ", ref tot);
					MultiID.WriteSI(Common.nList[dI], ref tot);
					MultiID.WriteT(")", ref tot);
					MultiID.TimeDel(ref tot);
					RunForm.FocusBothUs();
					MultiID.statReq2 = false;
				}
			}
			while (!done && !MultiID.muAbort && !MultiID.muErr);
			if (done)
			{
				MultiID.WriteT(".", ref tot);
				MultiID.WriteLn2();
			}
			Common.LDelete(rI);
			Common.LDelete(dI);
			Common.LDelete(qI);
			NPrimes.NPrimeDone();
			MultiID.muErr = false; // because no value is returned to nList[nI]
		} // PrimeFAB

		public static void BinoS(MultiSI a, MultiSI b, MultiSI z)
		// z = Binomial coefficient (a, b) slow method
		// a, b are not modified unless they share memory with z
		// will write to standard output if diagOn is true
		{
			if (b.S)							// 1: (a, b) = 0 for all a if b < 0
			{
				MultiID.ClearSI(z);
				return;
			}
			MultiSI aL = new MultiSI(a.N);
			MultiID.SetToSI(a, aL);
			bool sign = false;
			if (aL.S)							// 2: if a < 0
			{
				aL &= (b - a - 1);				// (a, b) = (-1)^b * (b-a-1, b)
				sign = ((b.V[0] & 1) == 1);
			}
			if (MultiID.CompSI(aL, b) > 0)		// 3: b > a
			{
				MultiID.ClearSI(z);				// (a, b) = 0
				MultiID.DoneSI(aL);
				return;
			}
			MultiSI bL = new MultiSI(b.N);
			MultiID.SetToSI(b, bL);
			MultiSI v = new MultiSI(MultiID.mMax);
			v &= aL / 2;
			if (MultiID.CompSI(v, bL) > 0)		// 4: b > a / 2
			{
				bL &= aL - bL;					// b = a - b
			}
			if (MultiID.ZTestSI(bL))			// 5: (a, 0) = 1 for all a
			{
				MultiID.SetToSI(MultiID.sOne, z);
				z.S = sign;
				MultiID.DoneSI(v);
				MultiID.DoneSI(bL);
				MultiID.DoneSI(aL);
				return;
			}
			v &= Int32.MaxValue;
			if (MultiID.CompSI(v, bL) > 0)		// 6: b > 2^31 -1
			{
				MultiID.ClearSI(z);						// (a, b) = 0
				MultiID.MuWriteErr("Numbers too large for binomial coefficient");
			}
			else
			{
				MultiSI nf = new MultiSI(aL.N);	// 7: (a, b) = (a-b+1)* a-b+2) * ... * a
				MultiSI df = new MultiSI(bL.N);	//				/ 1 * 2 * ... * n
				nf &= aL - bL + 1;
				df &= 1;
				v &= nf;
				double bd;
				MultiID.GetDbSI(out bd, bL);
				int bi = (int)bd;
				for (int i = 1; i < bi; i++)
				{
					MultiID.MuInterrupt();
					if (MultiID.muAbort)
					{
						MultiID.ClearSI(v);
						sign = false;
						break;
					}
					nf &= nf + 1;
					df &= df + 1;
					v &= (v * nf / df);
					if (MultiID.statReq2)
					{
						MultiID.nDone = i;
						MultiID.nToGo = bi - i - 1;
						MultiID.WritenDone("Bino:");
					}
				}
				MultiID.SetToSI(v, z);
				z.S = sign;
				MultiID.DoneSI(df);
				MultiID.DoneSI(nf);
			}
			MultiID.DoneSI(v);
			MultiID.DoneSI(bL);
			MultiID.DoneSI(aL);
		} // BinoS

		public static void InvN(int xI, int nI, int zI) // z = Inverse of x mod n (x*z = 1 mod n)
		{
			MultiSI x = new MultiSI(1);
			MultiSI n = new MultiSI(1);
			MultiSI z = new MultiSI(1);
			n &= Common.nList[nI];
			n.S = false;
			x &= Common.nList[xI] % n;
			InvSI(x, n, z);
			Calc.SetToN(z, zI);
			MultiID.DoneSI(z);
			MultiID.DoneSI(n);
			MultiID.DoneSI(x);
			Calc.NormN(zI);
		} // InvN

		public static void InvSI(MultiSI x, MultiSI y, MultiSI z) // z = Inverse of x mod y (x*z = 1 mod y)
		// assumes that x >= 0, y >= 0. z will be >= 0.
		{
			MultiSI xL = new MultiSI(1);
			MultiSI yL = new MultiSI(1);
			yL &= y;
			yL.S = false;
			xL &= x % yL;
			MultiSI x1 = new MultiSI(1);
			MultiSI y1 = new MultiSI(1);
			MultiSI z1 = new MultiSI(1);
			XICommon.GCDeSI(xL, yL, x1, y1, z1);
			if (z1 != 1)
			{
				Common.SingleSpace();
				MultiID.WriteLn("Inverse: No inverse");
				MultiID.ClearSI(z);
			}
			else
				z &= x1 % yL;
			MultiID.DoneSI(z1);
			MultiID.DoneSI(y1);
			MultiID.DoneSI(x1);
			MultiID.DoneSI(yL);
			MultiID.DoneSI(xL);
		} // InvSI

		public static void GCDeN(int xI, int yI, int zI) // extended GCD
		// z = GCD(x, y) >= 0, also computes x1 and y1 such that x*x1 + y*y1 = GCD(x, y)
		// x and or y may be <= 0
		{
			int x1I;
			Common.LFindAdd("X1", out x1I);
			int y1I;
			Common.LFindAdd("Y1", out y1I);
			if (x1I == zI || y1I == zI)
			{
				MultiID.MuWriteErr("Cannot set same location to GCD and extended GCD, continuing...");
				return;
			}
			MultiSI x1 = new MultiSI(1);
			MultiSI y1 = new MultiSI(1);
			MultiSI z = new MultiSI(1);
			bool signX = Common.nList[xI].S;
			bool signY = Common.nList[yI].S;
			Common.nList[xI].S = false;
			Common.nList[yI].S = false;
			GCDeSI(Common.nList[xI], Common.nList[yI], x1, y1, z);
			if (signX && (x1 != 0)) x1.S = !x1.S;
			if (signY && (y1 != 0)) y1.S = !y1.S;
			Common.nList[xI].S = signX;
			Common.nList[yI].S = signY;
			Calc.SetToN(z, zI);
			MultiID.DoneSI(z);
			Calc.NormN(zI);
			Calc.SetToN(x1, x1I);
			MultiID.DoneSI(x1);
			Calc.NormN(x1I);
			Calc.SetToN(y1, y1I);
			MultiID.DoneSI(y1);
			Calc.NormN(y1I);
		} // GCDeN

		public static void GCDeSI(MultiSI x, MultiSI y, MultiSI x1, MultiSI y1, MultiSI z)
		// extended GCD, z = GCD(x, y), also computes x1 and x1 such that x*x1 + y*y1 = GCD(x, y)
		// assumes that x >= 0, y >= 0. z will be >= 0 but x1 or y1 may be <= 0.
		// assumes x, y, x1, y1, and z are distinct objects
		// non-recursive version, from Knuth ACP vol. 2, pg. 302 section 5.5.2 Algorithm X
		{
			MultiSI u1 = new MultiSI(1);
			MultiSI u2 = new MultiSI(1);
			MultiSI u3 = new MultiSI(1);
			MultiSI v1 = new MultiSI(1);
			MultiSI v2 = new MultiSI(1);
			MultiSI v3 = new MultiSI(1);
			MultiSI t1 = new MultiSI(1);
			MultiSI t2 = new MultiSI(1);
			MultiSI t3 = new MultiSI(1);
			MultiSI q = new MultiSI(1);
			u1 &= 1;
			u2 &= 0;
			u3 &= x;
			v1 &= 0;
			v2 &= 1;
			v3 &= y;
			while (v3 != 0)
			{
				q &= u3/v3;
				t1 &= u1 - q * v1;
				t2 &= u2 - q * v2;
				t3 &= u3 - q * v3;
				u1 &= v1;
				u2 &= v2;
				u3 &= v3;
				v1 &= t1;
				v2 &= t2;
				v3 &= t3;
			}
			x1 &= u1;
			y1 &= u2;
			z &= u3;
			MultiID.DoneSI(q);
			MultiID.DoneSI(t3);
			MultiID.DoneSI(t2);
			MultiID.DoneSI(t1);
			MultiID.DoneSI(v3);
			MultiID.DoneSI(v2);
			MultiID.DoneSI(v1);
			MultiID.DoneSI(u3);
			MultiID.DoneSI(u2);
			MultiID.DoneSI(u1);
		} // GCDeSI

		public static void Chin1N(int xI, int yI, int zI) // Initialize the Chinese remainder problem
		// z = X1 = x mod y, Y1 = |y|
		{
			int x1I;
			Common.LFindAdd("X1", out x1I);
			int y1I;
			Common.LFindAdd("Y1", out y1I);
			if (y1I == zI)
			{
				MultiID.MuWriteErr("Cannot set same location to Z and Y1, continuing...");
				return;
			}
			Common.nList[y1I] &= Common.nList[yI];						// y1 = |y| >= 0
			Common.nList[y1I].S = false;
			Calc.SetToN(Common.nList[xI] % Common.nList[y1I], x1I);	// x1 = x mod y1 >= 0
			Common.nList[zI] &= Common.nList[x1I];						// z = x1
			Calc.NormN(x1I);
			Calc.NormN(y1I);
			Calc.NormN(zI);
		} // Chin1N

		public static void ChinN(int xI, int yI, int zI) // add x mod y to the Chinese remainder problem
		// z = X1 = new x, Y1 = new y
		{
			int x1I;
			Common.LFindAdd("X1", out x1I);
			int y1I;
			Common.LFindAdd("Y1", out y1I);
			if (y1I == zI)
			{
				MultiID.MuWriteErr("Cannot set same location to Z and Y1, continuing...");
				return;
			}
			Common.nList[y1I].S = false;			// y1 = |y1| >= 0
			Calc.SetToN(Common.nList[x1I] % Common.nList[y1I], x1I);	// x1 = x1 mod y1 >= 0
			MultiSI x2 = new MultiSI(1);
			MultiSI y2 = new MultiSI(1);
			y2 &= Common.nList[yI];					// y2 = |y| >= 0
			y2.S = false;
			x2 &= Common.nList[xI] % y2;			// x2 = x mod y2 >= 0
			MultiSI x3 = new MultiSI(1);
			MultiSI y3 = new MultiSI(1);
			ChinSI(Common.nList[x1I], Common.nList[y1I], x2, y2, x3, y3);
			int tot = 0;
			Common.SingleSpace();
			MultiID.WriteT("CRT: ", ref tot);
			MultiID.WriteSI(x3, ref tot);
			MultiID.WriteT(", ", ref tot);
			MultiID.WriteSILn(y3, ref tot);
			Calc.SetToN(x3, zI);
			Calc.SetToN(x3, x1I);
			Calc.SetToN(y3, y1I);
			MultiID.DoneSI(y3);
			MultiID.DoneSI(x3);
			MultiID.DoneSI(y2);
			MultiID.DoneSI(x2);
			Calc.NormN(x1I);
			Calc.NormN(y1I);
			Calc.NormN(zI);
		} // ChinN

		public static void ChinSI(MultiSI x1, MultiSI y1, MultiSI x2, MultiSI y2, MultiSI x3, MultiSI y3)
		// solve the Chinese remainder problem x3 = x1 mod y1 = x2 mod y2, all x = x3 mod y3
		// assumes that x1, y1 ,x2, y2 >= 0. y3, z3 will be >= 0.
		// method lifted from GP/PARI CALCULATOR, GEN chinois(GEN x, GEN y) in src\basemath\arith1.c
		{
			MultiSI g = new MultiSI(1);
			MultiSI u = new MultiSI(1);
			MultiSI v = new MultiSI(1);
			GCDeSI(y1, y2, u, v, g);
			if ((x1 - x2) % g != 0)
			{
				x3 &= 0;		// no solution
				y3 &= 0;
			}
			else
			{
				MultiSI p1 = new MultiSI(1);
				MultiSI p2 = new MultiSI(1);
				p1 &= y1 / g;
				p2 &= x1 + (u * p1) * (x2 - x1);
				y3 &= p1 * y2;
				x3 &= p2 % y3;
				MultiID.DoneSI(p2);
				MultiID.DoneSI(p1);
			}
			MultiID.DoneSI(v);
			MultiID.DoneSI(u);
			MultiID.DoneSI(g);
		} // ChinSI

		public static void SolveN(MultiSI x, MultiSI y, MultiSI n, int zI) // Solve the modular linear equation x * z = y Mod n for z
		{
			MultiSI xL = new MultiSI(1);
			MultiSI yL = new MultiSI(1);
			MultiSI nL = new MultiSI(1);
			MultiSI zL = new MultiSI(1);
			nL &= n;
			nL.S = false;
			xL &= x % nL;
			yL &= y % nL;
			SolveSI(xL, yL, nL, zL);
			Calc.SetToN(zL, zI);
			MultiID.DoneSI(zL);
			MultiID.DoneSI(nL);
			MultiID.DoneSI(yL);
			MultiID.DoneSI(xL);
			Calc.NormN(zI);
		} // SolveN

		public static void SolveN(int xI, int yI, int nI, int zI) // Solve the modular linear equation x * z = y Mod n for z
		{
			SolveN(Common.nList[xI], Common.nList[yI], Common.nList[nI], zI);
		} // SolveN

		public static void SolveSI(MultiSI x, MultiSI y, MultiSI n, MultiSI z) // Solve the modular linear equation x * z = y Mod n for z
		// assumes that x >= 0, y >= 0. z will be >= 0.
		{
			MultiSI x1 = new MultiSI(1);
			MultiSI y1 = new MultiSI(1);
			MultiSI z1 = new MultiSI(1);
			GCDeSI(x, n, x1, y1, z1);
			if (y % z1 != 0)
			{
				Common.SingleSpace();
				MultiID.WriteLn("Solution: No solution");
				MultiID.ClearSI(z);
			}
			else
			{
				long d;
				MultiID.GetExSI(out d, z1);
				MultiSI x0 = new MultiSI(1);
				x0 &= x1*(y/z1) % n;
				for (long i = d-1; i >= 0; i--)
				{
					z &= (x0 + (int)i * (n / z1)) % n;
					if (d > 1)
					{
						int tot = 0;
						Common.SingleSpace();
						MultiID.WriteT("Solution " + (i+1) + ": ", ref tot);
						MultiID.WriteSILn(z, ref tot);
					}
					if (i == d-1)
						x1 &= z;
					else
						if (z < x1) x1 &= z;	// x1 = minimum solution
				}
				z &= x1;						// return minimum solution
				MultiID.DoneSI(x0);
			}
			MultiID.DoneSI(z1);
			MultiID.DoneSI(y1);
			MultiID.DoneSI(x1);
		} // SolveSI

		public static void MersennePG(int zI) // Mersenne Prime Generator MEq(MPP(z))
		{
			MersennePP(zI);
			if (MultiID.muErr) return;
			MersenneEq(zI);
		} // MersennePG

		public static void MersenneEq(int zI) // Mersenne equation z = 2^z - 1
		{
			MultiSI t = new MultiSI(MultiID.mMax);
			MultiID.PowSI(MultiID.sTwo, Common.nList[zI], t);
			t--;
			MultiID.SetToSIN(t, Common.nList[zI]);
			MultiID.DoneSI(t);
		} // MersenneEq

		public static void MersenneP(int zI) // is 2^z -1 a Mersenne prime?
		// this is the Lucas-Lehmer-Test
		{
			if (Common.nList[zI] == MultiID.sTwo)
			{
				Calc.SetToN(MultiID.sOne, zI);
				return;
			}
			if (Common.nList[zI] < MultiID.sTwo || PrimeFA.Prime(Common.nList[zI]) == 0)
			{
				Calc.ClearN(zI);
				return;
			}
			int z;
			MultiID.GetIntSI(out z, Common.nList[zI]);
			int saveFMC = Calc.fMC;
			int saveMMax = MultiID.mMax;
			Calc.fMC = 2 * (5 + (int)(z * Math.Log10(2.0) / 8.0));
			if (Calc.fMC > MultiID.muNMax)
				Calc.fMC = MultiID.muNMax;
			MultiID.mMax = Calc.fMC;
			int mI;
			Common.InitNAdd(1, "MersenneP-mI", out mI);
			Calc.SetToII(zI, mI);
			MersenneEq(mI);
			int uI;
			Common.InitNAdd(1, "MersenneP-uI", out uI);
			Calc.SetToN(MultiID.sFour, uI);
			for (int i = 3; i <= z; i++)
			{
				MulN(uI, uI, uI);
				MultiID.RSubSI(MultiID.sTwo, Common.nList[uI]);
				MultiID.RModSI(Common.nList[mI], Common.nList[uI]);
				if (MultiID.diagOn || MultiID.statReq2)
				{
					int tot = 0;
					MultiID.WriteT("MersenneP: u" + i + " = ", ref tot);
					Calc.WriteNumLn(Common.nList[uI], ref tot);
				}
				MultiID.MuInterrupt();
				if (MultiID.muAbort) break; // exit for
				if (MultiID.statReq2)
				{
					MultiID.nDone = i - 2;
					MultiID.nToGo = z - i;
					MultiID.WritenDone("MPrime:");
				}
			}
			if (Common.nList[uI] != MultiID.sZero || MultiID.muAbort)
				Calc.ClearN(zI);
			else
				Calc.SetToN(MultiID.sOne, zI);
			Common.LDelete(uI);
			Common.LDelete(mI);
			Calc.fMC = saveFMC;
			MultiID.mMax = saveMMax;
		} // MersenneP

		public static void MersennePP(int zI) // Mersenne Prime Power, MPP(1) = 2
		{
			MultiSI maxP = new MultiSI(1);
			maxP &= 46;
			int p;
			int i = 0;
			if (Common.nList[zI] >= MultiID.sOne && Common.nList[zI] <= maxP)
				MultiID.Get1SI(out i, Common.nList[zI]); 
			switch (i)
			{
				case 1: p = 2; break;
				case 2: p = 3; break;
				case 3: p = 5; break;
				case 4: p = 7; break;
				case 5: p = 13; break;
				case 6: p = 17; break;
				case 7: p = 19; break;
				case 8: p = 31; break;
				case 9: p = 61; break;
				case 10: p = 89; break;
				case 11: p = 107; break;
				case 12: p = 127; break;
				case 13: p = 521; break;
				case 14: p = 607; break;
				case 15: p = 1279; break;
				case 16: p = 2203; break;
				case 17: p = 2281; break;
				case 18: p = 3217; break;
				case 19: p = 4253; break;
				case 20: p = 4423; break;
				case 21: p = 9689; break;
				case 22: p = 9941; break;
				case 23: p = 11213; break;
				case 24: p = 19937; break;
				case 25: p = 21701; break;
				case 26: p = 23209; break;
				case 27: p = 44497; break;
				case 28: p = 86243; break;
				case 29: p = 110503; break;
				case 30: p = 132049; break;
				case 31: p = 216091; break;
				case 32: p = 756839; break;
				case 33: p = 859433; break;
				case 34: p = 1257787; break;
				case 35: p = 1398269; break;
				case 36: p = 2976221; break;
				case 37: p = 3021377; break;
				case 38: p = 6972593; break;
				case 39: p = 13466917; break;
				case 40: p = 20996011; break;
				case 41: p = 24036583; break;
				case 42: p = 25964951; break;
				case 43: p = 30402457; break;
				case 44: p = 32582657; break;
				case 45: p = 37156667; break;
				case 46: p = 43112609; break;
				default: p = 0; break;
			}
			if (p == 0)
				MultiID.MuWriteErr("Mersenne Prime index out of supported range [1, 46]");
			MultiID.SetTo1SI(p, Common.nList[zI]);
			MultiID.DoneSI(maxP);
			Calc.NormN(zI);
		} // MersennePP

		public static void PerfectNG(int zI) // Perfect Number Generator PEq(MPP(z))
		{
			MersennePP(zI);
			if (MultiID.muErr) return;
			PerfectEq(zI);
		} // PerfectNG

		public static void PerfectEq(int zI) // Perfect equation z = (2^z - 1) * 2^(z-1)
		// let M = 2^z -1 the PEq(z) = M * (M + 1)/2 = (M*M + M)/2
		{
			MersenneEq(zI);
			Calc.SetToN((Common.nList[zI] * Common.nList[zI] + Common.nList[zI]) / 2, zI);
		} // PerfectEq

		public static string nL;		// one Environment.NewLine \n or \r or \r\n
		public static string pTabBak;	// file name of prime table backup file
		public static string pTabFile;	// file name of prime table file
	}
}
