using System;
using System.IO;			// for StreamReader I/O from a file
using System.Windows.Forms;	// for RichTextBox

namespace MyNamespace
{
	/// <summary>
	///		XICalc - Extra Precision Integer Calculator
	///		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>

	// ------- A multiple-precision named signed integer
	public class MultiN : MultiSI
	{
		public string Nm;			// name

		public MultiN()				// initialize with M = 0 and no name
			: base()				// calls MultiSI()
		{
			Nm = "";	// constructor logic
		}

		public MultiN(int nMaxI, string nm)		// initialize with M = nMaxI and new name
			: base(nMaxI)						// calls MultiSI(i)
		{
			Nm = nm;
		}

//		public static void operator = (MultiN left, MultiSI right)		// not allowed to overload =
//		{
//			Calc.SetToNM(right, left);
//		}

		public static MultiN operator & (MultiN left, MultiSI right)	// use &= for = assignment
		{
			Calc.SetToNM(right, left);
			return left;
		}
	}

	public class Calc
	{
		public Calc(int iMaxDigits)	// constructor logic
		{
			if (iMaxDigits < 49) iMaxDigits = 49;					// size for >= 49 decimal digits
			int iNMax = 1 + (iMaxDigits - 1) / MultiID.muDMax;		// convert from digits to super digits
			Common.nMax = Math.Min(iNMax, MultiID.muNMax);			// fMC <= mMax <= nMax <= muNMax
			new Calc();
		}

		public Calc()	// constructor logic
		// initialize Multi-precision Named signed Integer package
		// input: nMax muDMax
		{
			MultiID.intCalc = true;
			Common.quiet = true;
			new MultiID();				// initialize class MultiID
			Common.delim = ",;<=>+-!|*/&:()^@#%\\'\"";		// @ needed for Batch commands	// ,;<=>+-!|*/&:()^@#%\'"
			MultiID.mMax = Common.nMax;						// fMC <= mMax <= nMax <= muNMax
			fMC = Common.nMax;
			MultiID.muDpG = 5;
			MultiID.maxDis = Math.Min(200, MultiID.mMax * MultiID.muDMax); // set max digits to display
			CheckNMax();
			Common.mList = 1000;
			Common.nList = new MultiN[Common.mList+1];		// create the list of named numbers
			Common.InitN(1, "", 0);							// change unused name at [0] from null to ""
			Common.InitN(1, "X", 1);						// now create and add a named numbers to the list
			Common.cList = 1;								// x=0 on top of list
			Common.iTop = 1;
			Common.lastTop = 0;
			Common.comI = 0;
			xICIn = 0;
			xILOut = 0;
			xINIn = 0;
			xINOut = 0;
			Common.lrnL = 0;
			MultiID.debug = false;
			MultiID.diagOn = false;
			MultiID.timeIt = false;
			Common.autoD = true;
			Common.echoB = true;
			Common.exX = 0;
			Common.prSt = "";
			Common.oldField = "";
			Common.noChange = false;
			Common.saveTop = true;
			MultiID.softAbort = false;
			MultiID.baseI = 10;
			MultiID.baseO = 10;
			MultiID.allowFHT = true;	// allow FHT
			MultiID.forceFHT = false;	// but don't force it
			new Common();		// initialize class Common
			new FHTMult();		// initialize class FHTMult
			new XIMult();		// initialize class XIMult
			new NPrimes();		// initialize class NPrimes
			new PrimeFA();		// initialize class PrimeFA
			new XICommon();		// initialize class XICommon
			Common.running = true;
			Common.quiet = false;
			CalReadCode("AutoExec.XIC");
			Common.quiet = true;
		} // Calc

		public static void CalSave() // save all values on list to disk files and make
									 // file Restore.XIC for restoring them
		{
			StreamWriter outF; // text file, for Restore.XIC
			int current;
			string fName;
			int n;
			string st;
			string savDir = Environment.CurrentDirectory.ToString();
			Directory.SetCurrentDirectory(Common.homeDir);
			if (Common.ChkWrite(out outF, "Restore.XIC", ""))
			{
				MultiID.WriteLn(null, outF, "@Echo Off");
				MultiID.WriteLn(null, outF, "Rem  Start of file Restore.XIC");
				current = Common.cList;
				n = 10000;
				while (current != 0)
				{
					fName = n.ToString();
					fName = "Save" + fName.Substring(1, 4) + ".XIN";
					MultiID.WriteLn(null, outF, "ReadN(\"" + fName + "\")");
					current--;
					n++;
				}
				MultiID.WriteLn(null, outF, Common.nList[Common.iTop].Nm + "=");
				MultiID.WriteLn(null, outF, "Rem  End of file Restore.XIC");
				if (Common.echoB) { st = "On"; } else { st = "Off"; }
				MultiID.WriteLn(null, outF, "Echo " + st);
				outF.Close();
				if (!Common.quiet) MultiID.WriteLn("File Restore.XIC closed");
				current = Common.cList;
				while (current != 0)
				{
					n--;
					fName = n.ToString();
					fName = "Save" + fName.Substring(1, 4) + ".XIN";
					CalWriteN(fName, current);
					current--;
				}
			}
			Directory.SetCurrentDirectory(savDir);
		}

		public static void ChkResSav(int resSav, string fName)
		// check for Restore, Save, or Run procedure
		{
			if (resSav == 1) // restore
			{
				CalReadConfig();
				Common.RestoreHist();
				bool saveSaveTop = Common.saveTop; // don't change LastTop after it is read back in
				Common.saveTop = false;
				CalReadCode("Restore.XIC");
				Common.saveTop = saveSaveTop;
			}
			else if (resSav == 2) // save
			{
				CalWriteConfig();
				Common.SaveHist();
				CalSave();
			}
			else if (resSav == 3) // run
			{
				CalReadCode(fName);
			}
		}

		public static void ClearN(int nI) // set value = 0
		{
			MultiID.ClearSI(Common.nList[nI]);
			NormN(nI);
		}

		public static void SetToN(MultiSI x, int zI) // z = x, resized
		// copy everything but .Nm name
		{
			SetToNM(x, Common.nList[zI]);
		}

		public static void SetToII(int xI, int zI) // z = x
		// copy everything but .Nm name
		{
			SetToNM(Common.nList[xI], Common.nList[zI]);
		}

		public static void SetToNM(MultiSI x, MultiSI z) // z = x, resized
		// copy everything but .Nm name
		{
			int m = x.N;
			if (m != z.M)
			{
				z.V = new int[m+1]; // resize V
				z.M = m;
			}
			MultiID.SetToSI(x, z);
		}

		public static void NormN(int nI) // normalize number indexed by nI on the list
		{
			int n = Common.nList[nI].N;
			if (n > fMC)
			{
				MultiID.WriteDLn("Most significant digits discarded in " + Common.nList[nI].Nm);
			}
			NormNM(Common.nList[nI]);
		}

		public static void NormNM(MultiSI x) // normalize x with M = N, release unused memory
		{
			int m = x.M;
			int n = x.N;
			if (n > fMC)
			{
				n = fMC;
				x.N = n;
				MultiID.NormSI(x);			// get rid of any new leading zero super digits
			}
			if (n == 1 && x.V[0] == 0) x.S = false; // prevent -0
			if (m == n) return;
			Common.ReDimPreserve(ref x.V, n+1);
			x.V[n] = 0;						// be neat
			x.M = n;
		}

		public static void ValueN10(string st, out int i, int zI)
		// convert a base 10 String to z, returns i = # of character used
		// allows st to be a literal, muErr set true if overflow
		{
			int saveBaseI = MultiID.baseI;
			MultiID.baseI = 10;
			ValueN(st, out i, zI);
			MultiID.baseI = saveBaseI;
		}

		public static void ValueN(string st, out int i, int zI)
		// convert String to z, returns i = number of character used
		// allows st to be a literal, muErr set true if overflow
		{
			int m;
			m = (int)(5 + st.Length * Math.Log10(MultiID.baseI) / MultiID.muDMax);
			if (m > Common.nMax) m = Common.nMax;
			MultiSI t = new MultiSI(m);
			MultiID.ValueSI(st, out i, t);
			m = t.N;
			Common.nList[zI].V = new int[m+1];
			Common.nList[zI].M = m;
			MultiID.SetToSI(t, Common.nList[zI]);
			MultiID.DoneSI(t);
		}

		public static void WriteNV(RichTextBox outB, StreamWriter outF, MultiN x, ref int tot, int width)
		// output x name + V and a new line. x not modified
		{
			MultiID.WriteT(outB, outF, x.Nm + " =", ref tot, width);
			if (outB == null)
				MultiID.WriteTLn2(outB, outF, "", ref tot, width);
			else
				MultiID.WriteT(outB, outF, " ", ref tot, width);
			MultiID.WriteSI(outB, outF, x, ref tot, width, true);
		}

		public static void WriteNumLn(MultiN x, ref int tot)
		// output x value and a new line. x not modified
		{
			MultiID.WriteSILn(x, ref tot);
		}

		public static void CheckNMax() // fMC <= mMax <= nMax <= muNMax
		// fMC = mMax // for the Integer Calculator
		{
			int fMCL;
			fMCL = fMC;
			int min = 1 + (34 / MultiID.muDMax); // min of 35 decimal digits
			MultiID.mMax = Math.Max(MultiID.mMax, min);
			MultiID.mMax = Math.Min(MultiID.mMax, Common.nMax);
			fMC = MultiID.mMax;
			if (fMC < fMCL) ListSetM();
		}

		public static void CalSMan(int nI)
		// set current number of digits in a result
		{
			double db;
			MultiID.GetDbInSI(out db, 0, Int32.MaxValue, Common.nList[nI]);
			db = 1 + (db - 1) / MultiID.muDMax; // set for at least x decimal digits
			fMC = (int)db;
			MultiID.mMax = fMC; // for the Integer Calculator
			CheckNMax();
			ListSetM();
		}

		public static void ListSetM() // for all items, reduce M to fMC if greater than fMC
		{
			for (int cI = 1; cI <= Common.cList; cI++)
			{
				if (Common.nList[cI].N > fMC)
				{
					NormN(cI); // re-dimension the .V vector
				}
			}
		}

		public static bool GetFName(ref string st)
		// get file name from command line
		// if first parm ends in .XIC, it is changed to Run("... .XIC")
		// if first parm ends in .XIN, it is changed to ReadN("... .XIN")
		{
			bool bGetFName = false;
			int i = st.Length;
			if (i > 4)
			{
				string ext = st.Substring(i - 4, 4);
				ext = ext.ToUpper();
				if (ext == ".XIC")
				{
					st = "Run(\"" + st + "\")";
					bGetFName = true;
				}
				else if (ext == ".XIN")
				{
					st = "ReadN(\"" + st + "\")";
					bGetFName = true;
				}
			}
			if (!bGetFName) st = "";
			return bGetFName;
		}

		public static void TestExpanded() { return; } // noOp for XICalc

		public static bool UnsignedConst(ref string st, int nI)
		// do an Unsigned Constant, Must input number like F... as 0F...
		{
			char ch;
			ch = st[0];
			if (ch >= '0' && ch <= '9')
			{
				Common.EnterN(ref st, nI);
				return true;
			}
			return false;
		}

		public static bool Constant(ref string st, int nI)
		// do a constant, Input number like F... as 0F...
		{
			char ch;
			int i = 0;
			string maxD = MultiID.MaxDig(MultiID.baseI);	// max Input digit "1" to "Z"
			if ( st != "" && (st[0] == '+' || st[0] == '-') ) i++;
			if (i >= st.Length) return false;
			ch = st[i];
			if (ch >= '0' && ch <= '9' && ch <= maxD[0])
			{
				Common.EnterN(ref st, nI);
				return true;
			}
			return false;
		}

		public static bool AFunction(ref string st, int nI) // do a Function
		{
			int tI;			// temp for the 1st argument of a function
			int t2I;		// temp for the 2nd argument of a function
			int t3I;		// temp for the 3rd argument of a function
			int fMBI;
			int args = 1;
			string name = Common.GetField(ref st);
			int i = name.Length;
			if (i == 0 || i == st.Length || st[i] != '(') return false;
			Common.DelNPBls(ref st, 1 + i);
			Common.InitNAdd(fMC, "AFunction-tI", out tI);
			Common.InitNAdd(fMC, "AFunction-t2I", out t2I);
			Common.InitNAdd(fMC, "AFunction-t3I", out t3I);
			if (!Expression(ref st, tI))
			{
				Common.ReportSin("Error in function's argument: " + name + "(|", ref st);
				args = 0;
			}
			else
			{
				if (st != "" && (st[0] == '\'' || st[0] == ','))
				{
					Common.DelNPBls(ref st, 1);
					args = 2;
					if (!Expression(ref st, t2I))
					{
						Common.ReportSin("Error in function's 2nd argument: " + name + "(..., |", ref st);
						ClearN(t2I);
						args = 1;
					}
					else
					{
						if (st != "" && (st[0] == '\'' || st[0] == ','))
						{
							Common.DelNPBls(ref st, 1);
							args = 3;
							if (!Expression(ref st, t3I))
							{
								Common.ReportSin("Error in function's 3rd argument: " + name + "(..., |", ref st);
								ClearN(t3I);
								args = 2;
							}
						}
					}
				}
				SetToII(tI, nI);
				ClearN(tI);		// to release memory
				if (st != "" && st[0] == ')') Common.DelNPBls(ref st, 1);
				if (MultiID.muErr)
					args = 0;
				else if (name == "ABS")
					Common.nList[nI].S = false;
				else if (name == "BERND")
					BernD(Common.nList[nI], Common.nList[nI]);
				else if (name == "BERNN")
					BernN(Common.nList[nI], Common.nList[nI]);
				else if (name == "BINO")
				{
					Bino(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "BINOS")
				{
					XICommon.BinoS(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "CHIN")
					XICommon.ChinN(nI, t2I, nI);
				else if (name == "CHIN1")
					XICommon.Chin1N(nI, t2I, nI);
				else if (name == "CURT")
					XICommon.CubeRtRemN(nI, nI);
				else if (name == "DIG")
					XICommon.DigN(t2I, nI);
				else if (name == "DIGD")
					XICommon.DigDN(nI);
				else if (name == "DIVINT")
					DivIntN(nI, t2I, nI);
				else if (name == "DIVREM")
					DivRemN(nI, t2I, nI);
				else if (name == "EULER" || name == "EULERN")
					Euler(Common.nList[nI], Common.nList[nI]);
				else if (name == "FAC")
					FacBiN(nI, nI);
				else if (name == "FAC2")
					Fac2(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
				else if (name == "FACM")
				{
					if (Common.FMBIok(nI, out fMBI))
						FacMBiN(nI, nI);
				}
				else if (name == "FACM2")
				{
					if (Common.FMBIok(nI, out fMBI))
						FacM2(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
				}
				else if (name == "FACMS")
				{
					if (Common.FMBIok(nI, out fMBI))
						FacMBN(nI, nI);
				}
				else if (name == "FACS")
					FacN(nI, nI);
				else if (name == "FIB")
					FibN(nI, nI);
				else if (name == "GAM")
					GamN(nI, nI);
				else if (name == "GCD")
				{
					MultiID.GCDSI(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "GCDE")
					XICommon.GCDeN(nI, t2I, nI);
				else if (name == "INV")
					XICommon.InvN(nI, t2I, nI);
				else if (name == "ISSQ")
				{
					if (Common.nList[nI].S)
						SetToN(MultiID.sZero, nI);
					else
						PrimeFA.IsSq(nI);
				}
				else if (name == "KRON")
				{
					PrimeFA.KronSI(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "LCM")
				{
					MultiID.LCMSI(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "MAG")
					MagN(Common.nList[nI], Common.nList[t2I], nI);
				else if (name == "MAX")
					MaxN(Common.nList[nI], Common.nList[t2I], nI);
				else if (name == "MEQ")
					XICommon.MersenneEq(nI);
				else if (name == "MIN")
					MinN(Common.nList[nI], Common.nList[t2I], nI);
				else if (name == "MOD")
				{
					MultiID.RModSI(Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "MORD")
				{
					PrimeFA.MorderSI(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "MPG")
					XICommon.MersennePG(nI);
				else if (name == "MPP")
					XICommon.MersennePP(nI);
				else if (name == "MPRIME")
					XICommon.MersenneP(nI);
				else if (name == "MU")
					PrimeFA.MoebiusMu(nI);
				else if (name == "P")
					XICommon.PrimePT(nI);
				else if (name == "PEQ")
					XICommon.PerfectEq(nI);
				else if (name == "PGT")
				{
					PrimeFA.findUp = true;
					PrimeFA.PrimeSearch(nI);
				}
				else if (name == "PHI")
					PrimeFA.PrimePhi(nI);
				else if (name == "PHIL")
					PrimeFA.PhiLN(nI, t2I, nI);
				else if (name == "PI")
					XICommon.PrimePiT(nI);
				else if (name == "PIL")
					PrimeFA.PrimePiLT(nI);
				else if (name == "PIL1")
					PrimeFA.PrimePiL1(nI);
				else if (name == "PIM")
					PrimeFA.PrimePiM(nI);
				else if (name == "PLT")
				{
					PrimeFA.findUp = false;
					PrimeFA.PrimeSearch(nI);
				}
				else if (name == "PNG")
					XICommon.PerfectNG(nI);
				else if (name == "POW")
				{
					MultiID.ClearSI(MultiID.fMB);
					MultiID.ReSizeSI(fMC, Common.nList[tI]);
					MultiID.PowMBSI(Common.nList[nI], Common.nList[t2I], Common.nList[tI]);
					SetToII(tI, nI);
					NormN(nI);
				}
				else if (name == "POWM")
				{
					Common.LFindAdd("FMB", out fMBI);
					if (fMBI == nI)
					{
						MultiID.WriteTDLn("Cannot set Top to PowM(X, Y), FMB cleared");
						ClearN(nI);
					}
					else
					{
						SetFMB();
						MultiID.ReSizeSI(fMC, Common.nList[tI]);
						MultiID.PowMBSI(Common.nList[nI], Common.nList[t2I], Common.nList[tI]);
						SetToII(tI, nI);
						NormN(nI);
					}
				}
				else if (name == "PRIME")
					PrimeFA.Prime(nI);
				else if (name == "PRIMO")
					XICommon.Primorial(nI);
				else if (name == "PRIMR")
					PrimeFA.PrimR(nI, false);
				else if (name == "PRIMRP")
					PrimeFA.PrimR(nI, true);
				else if (name == "PRIMRQ")
					PrimeFA.PrimRQ(nI, t2I, nI);
				else if (name == "REV")
					XICommon.RevN(nI, t2I, nI);
				else if (name == "RINT")
					RRIntN(t2I, nI);
				else if (name == "RN")
					RRanN(nI);
				else if (name == "SIG")
					PrimeFA.PrimeSig(nI);
				else if (name == "SIG0")
					PrimeFA.PrimeSig0(nI);
				else if (name == "SIGN")
				{
					int sign = MultiID.SignSI(Common.nList[nI]);
					MultiID.SetTo1SI(sign, Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "SOLVE")
					XICommon.SolveN(nI, t2I, t3I, nI);
				else if (name == "SORD")
				{
					PrimeFA.SorderSI(Common.nList[nI], Common.nList[t2I], Common.nList[nI]);
					NormN(nI);
				}
				else if (name == "SQ")
					XICommon.MulN(nI, nI, nI);
				else if (name == "SQFREE")
					PrimeFA.SqFree(nI);
				else if (name == "SQRT")
					XICommon.SqRtRemN(nI, nI);
				else if (name == "SUMD")
					XICommon.SumDN(t2I, nI);
				else if (name == "SUMDD")
					XICommon.SumDDN(nI);
				else if (name == "TAU")
					PrimeFA.PrimeTau(nI);
				else
				{
					Common.ReportSin("Unknown function: |" + name + "(", ref st);
					args = 0;
				}
			}
			Common.LDelete(t3I); // delete in reverse order of creation
			Common.LDelete(t2I);
			Common.LDelete(tI);
			if (name == "SOLVE")
			{
				if (args == 1)
						MultiID.WriteDLn(name + ": 2nd and 3rd argument assumed = 0");
				if (args == 2)
						MultiID.WriteDLn(name + ": 3rd argument assumed = 0");
			}
			else if (name == "BINO" || name == "BINOS" || name == "CHIN" ||
				name == "CHIN1" || name == "DIG" || name == "DIVINT" || name == "DIVREM" ||
				name == "FAC2" || name == "FACM2" || name == "GCD" || name == "GCDE" ||
				name == "INV" || name == "KRON" || name == "LCM" || name == "MAG" ||
				name == "MAX" || name == "MIN" || name == "MOD" || name == "MORD" ||
				name == "PHIL" || name == "POW" || name == "POWM" || name == "PRIMRQ" ||
				name == "REV" || name == "RINT" || name == "SORD" || name == "SUMD")
			{
				if (args == 1 && name != "REV")
					MultiID.WriteDLn(name + ": Second argument assumed = 0");
				if (args > 2)
					MultiID.WriteDLn(name + ": Only two arguments used");
			}
			else
			{
				if (args > 1)
					MultiID.WriteDLn(name + ": Second argument ignored");
			}
			return true;
		} // AFunction

		public static bool Factor(ref string st, int nI) // do a Factor
		{
			int tI;
			bool zip;
			if (st == "") return false;
			if (UnsignedConst(ref st, nI)) return true;
			if (AFunction(ref st, nI)) return true;
			if (Variable(ref st, out tI))
			{
				SetToII(tI, nI);
				return true;
			}
			if (st != "" && st[0] == '(')
			{
				Common.DelNPBls(ref st, 1);
				if (Expression(ref st, nI))
				{
					if (st != "" && st[0] == ')') Common.DelNPBls(ref st, 1);
					return true;
				}
				else
				{
					Common.ReportSin("Expression expected: (|", ref st);
					return true;
				}
			}
			if (st != "" && st[0] == '!')
			{
				Common.DelNPBls(ref st, 1);
				if (Factor(ref st, nI))
				{
					zip = Common.ZTestN(nI);
					ClearN(nI);
					if (zip) Common.nList[nI].V[0] = 1;
					return true;
				}
				else
				{
					Common.ReportSin("Factor expected: !|", ref st);
					return true;
				}
			}
			return false;
		} // Factor

		public static bool Power(ref string st, int nI) // do a Power
		{
			string sign;
			string op;
			int tI;
			int t2I;
			if (!Factor(ref st, nI)) return false;
			while (true)
			{
				if (st == "") return true;
				op = st.Substring(0, 1);
				if (op != "^") return true;
				Common.DelNPBls(ref st, 1);
				if (st == "") return true;
				sign = st.Substring(0, 1);
				if (sign == "+" || sign == "-")
				{
					Common.DelNPBls(ref st, 1);
					if (st == "") return true;
				}
				else
				{
					sign = "";
				}
				Common.InitNAdd(fMC, "Power-tI", out tI);
				// 3^3^3 gave (3^3)^3 = 19683, should give 3^(3^3) = 762,55974,84987, fixed
				// by changing Factor to Power on next line 2003-11-22 HJS
				if (Power(ref st, tI))
				{
					if (sign == "-") Common.ChSN(tI);
					Common.InitNAdd(fMC, "Power-t2I", out t2I);
					if (op == "^")
					{
						MultiID.ClearSI(MultiID.fMB);
						MultiID.PowMBSI(Common.nList[nI], Common.nList[tI], Common.nList[t2I]);
					}
					SetToII(t2I, nI);
					Common.LDelete(t2I);
					NormN(nI);
				}
				else
				{
					Common.ReportSin("Exponent expected:" + "^" + sign + "|", ref st);
				}
				Common.LDelete(tI);
			}
		} // Power

		public static bool Term(ref string st, int nI) // do a Term
		{
			char op;
			int tI;
			int t2I;
			if (!Power(ref st, nI)) return false;
			while (true)
			{
				if (st == "") return true;
				op = st[0];
				if ( (op != '*') && (op != '/') && (op != '&') &&
					 (op != '%') && (op != '\\') && (op != '#') ) return true;
				Common.DelNPBls(ref st, 1);
				Common.InitNAdd(fMC, "Term-tI", out tI);
				if (!Power(ref st, tI))
				{
					Common.ReportSin("Factor expected: " + op + "|", ref st);
				}
				else
				{
					Common.InitNAdd(fMC, "Term-t2I", out t2I);
					if (op == '*')
						XICommon.MulN(nI, tI, t2I);
					else if (op == '/')
						XICommon.DivN(nI, tI, t2I);
					else if (op == '#')
						MagN(Common.nList[nI], Common.nList[tI], t2I);
					else if (op == '%')
						MultiID.ModSI(Common.nList[nI], Common.nList[tI], Common.nList[t2I]);
					else if (op == '\\')
						MultiID.GCDSI(Common.nList[nI], Common.nList[tI], Common.nList[t2I]);
					else if (op == '&')
					{
						if (!Common.ZTestN(nI) && !Common.ZTestN(tI))
						{
							Common.nList[t2I].V[0] = 1;
						}
					}
					SetToII(t2I, nI);
					Common.LDelete(t2I);
					NormN(nI);
				}
				Common.LDelete(tI);
			}
		} // Term

		public static bool SimpExpr(ref string st, int nI)
		// do a Simple Expression
		{
			char sign = ' ';
			bool met;
			string op;
			string op2;
			int tI;
			if (st != "") sign = st[0];
			if (sign == '+' || sign == '-')
			{
				Common.DelNPBls(ref st, 1);
			}
			else
			{
				sign = ' ';
			}
			if (!Term(ref st, nI))
			{
				if (sign == ' ') return false;
				Common.ReportSin("Term expected: " + sign + "|", ref st);
				return true;
			}
			if (sign == '-') Common.ChSN(nI);
			while (true)
			{
				if (st == "") return true;
				op = st.Substring(0, 1);
				op2 = "";
				if (st.Length > 1) op2 = st.Substring(0, 2);
				if ( (op != "+") && (op != "-") && (op != "|") && (op2 != "--") )
					return true;
				if (op2 == "--")
				{
					Common.DelNPBls(ref st, 2);
					op = op2;
				}
				else
				{
					Common.DelNPBls(ref st, 1);
				}
				Common.InitNAdd(fMC, "SimpExpr-tI", out tI);
				if (!Term(ref st, tI))
				{
					Common.ReportSin("Term expected: " + op + "|", ref st);
				}
				else
				{
					if (op == "+") XICommon.RAddN(tI, nI);
					else if (op == "-") XICommon.RSubN(tI, nI);
					else if (op == "|")
					{
						met = !Common.ZTestN(nI) || !Common.ZTestN(tI);
						ClearN(nI);
						if (met) Common.nList[nI].V[0] = 1;
					}
					else if (op == "--")
					{
						RepUnitN(tI);
						XICommon.RMulN(tI, nI);
					}
				}
				Common.LDelete(tI);
			}
		} // SimpExpr

		public static bool Variable(ref string st, out int zI) // do a Variable
		// passed By Value is default, st is input and output, zI is output, points to Variable on the list
		{
			bool state;
			int i;
			int iL;
			char ch = ' ';
			string name;
			state = false;
			zI = 0;							// zI = 0 for returns of false
			name = Common.GetField(ref st);
			iL = name.Length;
			if (iL > 0) ch = name[0];
			if (ch >= 'A' && ch <= 'Z')		// first ch is a letter
			{
				i = 0;
				state = true;
				while (i < iL-1)
				{
					i++;
					ch = name[i];
					if ( (ch >= 'A' && ch <= 'Z') ||
						(ch >= '0' && ch <= '9') )		// and all ch are numbers or letters
					{
						; // noOp
					}
					else
					{
						state = false;		// not a Variable name
						i = iL;				// exit while
					}
				}
			}
			if (state)
			{
				name = st.Substring(0, iL); // get original lower case letters
				Common.DelNPBls(ref st, iL);
				Common.LFindAdd(name, out zI);		// add it to the list if not there and point to it
			}
			return state;
		} // Variable

		public static void RepUnitN(int zI) // z = 111...111, 1 repeated z times in baseO
			// R2, R19, R23, R317, and R1031 are the only known repunit primes in base 10
			// the next one is larger than R20000 (1993)
			// Repunit n = (base^n - 1)/(base-1), The Output base is used for this
		{
			double r;	// Rep number
			MultiID.GetDbSI(out r, Common.nList[zI]);
			if (r < 1)
			{
				ClearN(zI);
				return;
			}
			MultiSI b = new MultiSI(1);
			MultiID.SetTo1SI(MultiID.baseO, b); // base
			MultiSI t = new MultiSI(2 + (int)(r * Math.Log10(MultiID.baseI) / MultiID.muDMax));
			MultiID.ClearSI(MultiID.fMB);
			MultiID.PowMBSI(b, Common.nList[zI], t);
			MultiID.RAdd1SI(-1, t);
			MultiID.RDiv1SI(MultiID.baseO - 1, t);
			MultiID.SetToSI(t, Common.nList[zI]);
			MultiID.DoneSI(t);
			MultiID.DoneSI(b);
			NormN(zI);
		} // RepUnitN

		public static void RRanN(int zI) // z = random number from seed z
		{
			int rNA;
			int rNC;	// constants for the random number generator
			int i;
			int saveFMC;
			int aN = (34 / MultiID.muDMax) + 1;		// Super digits in rNA
			Common.LFind("RNA", out rNA);
			if (rNA > 0)
			{
				if (Common.nList[rNA].N < aN)
					rNA = 0;
			}
			Common.LFind("RNC", out rNC);
			if (rNC > 0)
			{
				if (Common.nList[rNC].N < aN)
					rNC = 0;
			}
			if (rNA == 0)
			{
				Common.LFindAdd("RNA", out rNA);
				ValueN10("1843624,8305725,0753463,7429192,0765341", out i, rNA);
			}
			if (rNC == 0)
			{
				Common.LFindAdd("RNC", out rNC);
				ValueN10("8634647,9732047,9456723,8254463,9625443", out i, rNC);
			}
			saveFMC = fMC;
			fMC = 2 * aN;
			MultiID.mMax = fMC;
			int e = Common.nList[zI].N - aN;
			if (e > 0)
				for (i = 0; i < aN; i++)
					Common.nList[zI].V[i] = Common.nList[zI].V[i + e];
			Common.nList[zI].N = Math.Min(Common.nList[zI].N, aN);
			XICommon.MulN(rNA, zI, zI);	// z = (rNA * z + rNC) % (base^aN)
			XICommon.RAddN(rNC, zI);		// only tested for muDMax = 4, 5, 7, and 8
			if (MultiID.muDMax == 8 && Common.nList[zI].N > 4)
				Common.nList[zI].V[4] %= 1000;
			else if (MultiID.muDMax == 4 && Common.nList[zI].N > 8)
				Common.nList[zI].V[8] %= 1000;
			Common.nList[zI].N = aN;
			Common.nList[zI].S = false;
			MultiID.NormSI(Common.nList[zI]);
			fMC = saveFMC;
			MultiID.mMax = fMC;
			NormN(zI);
			int rNI;						// update seed for the N command
			Common.LFindAdd("RN", out rNI);
			if (rNI != zI) SetToN(Common.nList[zI], rNI);
		} // RRanN

		public static void RanN(int zI) // z = random number from seed RN
		{
			int rNI;		// random number
			Common.LFindAdd("RN", out rNI);
			RRanN(rNI);		// rN = (rNA * rN + rNC) % (10^35)
			SetToII(rNI, zI);
		}

		public static void Ran() // Top = random number from random seed
		{
			int rNI;		// random number
			Common.LFindAdd("RN", out rNI);
			DateTimePicker dateTime = new DateTimePicker();
			string timeSt = dateTime.Value.ToString();
			string st = "";
			double t = MultiID.TimerF();
			timeSt += t.ToString();
			int i;
			for (i = 0; i < timeSt.Length; i++)
			{
				if ('0' <= timeSt[i] && timeSt[i] <= '9')
					st += timeSt[i];
			}
			ValueN10("1" + st + st, out i, rNI);
			XICommon.MulN(rNI, rNI, rNI);
			RRanN(rNI);		// rN = (rNA * rN + rNC) % (10^35)
			SetToII(rNI, Common.iTop);
		} // Ran

		public static void RRIntN(int yI, int zI) // z = Random Integer between y and z inclusive
		{
			int yLI;		// y local
			int zLI;		// z local
			int rNI;		// random number
			int rLI;		// random number local
			int i;
			Common.InitNAdd(Common.nList[yI].N, "RRIntN-yLI", out yLI);
			Common.InitNAdd(Common.nList[zI].N, "RRIntN-zLI", out zLI);
			Common.nList[yLI] &= Common.nList[yI];
			Common.nList[zLI] &= Common.nList[zI];
			if (Common.nList[yI] < Common.nList[zI])
			{
				int tmp = yLI;
				yLI = zLI;
				zLI = tmp;
			}
			Common.LFindAdd("RN", out rNI);
			RRanN(rNI);		// rN = (rNA * rN + rNC) % (10^35)
			Common.InitNAdd(Common.nList[rNI].N, "RRIntN-rLI", out rLI);
			Common.nList[rLI] &= Common.nList[rNI];
			if (rNI == zI || rNI == Common.iTop)
				MultiID.WriteLn("RInt: Warning, changing RN by RInt(X, Y), continuing...");
			XICommon.RSubN(zLI, yLI);
			MultiID.Add1SI(Common.nList[yLI], 1, Common.nList[zI]);
			XICommon.RMulN(rLI, zI);
			ValueN10("1,0000000,0000000,0000000,0000000,0000000", out i, yLI);
			XICommon.DivN(zI, yLI, zI);
			XICommon.RAddN(zLI, zI);		// z = (RN * (y - z + 1) / 10^35) + z, y >= z
			Common.LDelete(rLI);
			if (zLI > yLI)
			{
				Common.LDelete(zLI);
				Common.LDelete(yLI);
			}
			else
			{
				Common.LDelete(yLI);
				Common.LDelete(zLI);
			}
			NormN(zI);
		} // RRIntN

		public static bool Expression(ref string st, int nI) // do an Expression
		{
			string op;
			string op2;
			int tI;
			int sign;
			bool met;
			if (!SimpExpr(ref st, nI)) return false;
			if (st == "") return true;
			op = st.Substring(0, 1);
			op2 = "";
			if (st.Length > 1) op2 = st.Substring(0, 2);
			if (op != "<" && op != "!" && op != "=" && op != ">")
				return true;
			if (op2 == "==" || op2 == "<=" || op2 == "<>" || op2 == "!=" || op2 == ">=")
			{
				Common.DelNPBls(ref st, 2);
			}
			else
			{
				if (op == "!") return true;
				Common.DelNPBls(ref st, 1);
			}
			Common.InitNAdd(fMC, "Expression-tI", out tI);
			if (!SimpExpr(ref st, tI))
			{
				Common.ReportSin("Simple Expression expected: " + op2 + "|", ref st);
			}
			else
			{
				sign = MultiID.CompSI(Common.nList[tI], Common.nList[nI]);
				if (op2 == "<=")
					met = (sign <= 0);
				else if (op2 == "<>" || op2 == "!=")
					met = (sign != 0);
				else if (op2 == ">=")
					met = (sign >= 0);
				else if (op2 == "==")
					met = (sign == 0);
				else if (op == "<")
					met = (sign < 0);
				else if (op == "=")
					met = (sign == 0);
				else if (op == ">")
					met = (sign > 0);
				else
					met = false;	// should not get here
				ClearN(nI);
				if (met) Common.nList[nI].V[0] = 1;	// n is initially zero
			}
			Common.LDelete(tI);
			return true;
		} // Expression

		public static void ReadFNmB(StreamReader inF, out bool oK, int zI, ref string fName, string st)
		// input st is a possible initial input line
		// read in z (baseI) from a file, oK = true; if no I/O errors
		{
			int i;
			char ch;
			bool fini = false;
			string stN = "";
			string st2 = "";
			string maxD = MultiID.MaxDig(MultiID.baseI);
			oK = true;
			try
			{
				do
				{
					if (st == "") st = inF.ReadLine();	// get next line of input
					if (st == null) break;				// null => EOF
					for (i = 1; i <= st.Length; i++)
					{
						ch = st[i-1];
						if (ch >= '0' && ch <= maxD[0] && (ch <= '9' || ch >= 'A')) // get value
						{
							st2 += ch;
							if (st2.Length >= 100)
							{
								stN += st2;
								st2 = "";
							}
						}
						else if (ch != ',')
						{
							if (ch != ' ')
							{
								fini = true;
								break;				// stop if garbage after number
							}
						}
					}
					st = "";
					MultiID.MuInterrupt();
				}
				while (!fini && !MultiID.muAbort);	// not fini ...
				stN += st2;
				ValueN(stN, out i, zI);
			}
			catch (Exception ex)
			{
				// trap read error
				MultiID.WriteLn(" Read error file \"" + fName + '"');
				Common.WCurDir(fName);
				Common.ReportError("ReadFNmB", ex.Message);
				oK = false;
			}
		} // ReadFNmB

		public static void ReadFNm10(StreamReader inF, ref bool oK, int zI, ref string fName, string st)
		// read in z (base 10) from an already opened file, oK = true if no I/O errors
		{
			int i;
			int j = 0;
			int k = 0;
			string ch;
			string stN = "";
			bool fini = false;
			int sD;				// Super digit
			try
			{
				do
				{
					if (st == "") st = inF.ReadLine();			// get next line of input
					if (st == null) break;						// null => EOF
					for (i = 1; i <= st.Length; i++)
					{
						ch = st.Substring(i-1, 1);
						if ('0' <= ch[0] && ch[0] <= '9')	// get value
						{
							j++;
							stN += ch;
							if (j == MultiID.muDMax)
							{
								sD = System.Int32.Parse(stN);
								stN = "";
								j = 0;
								Common.nList[zI].V[k] = sD;
								k++;
							}
						}
						else if (ch != ",")
						{
							if (ch != " ")
							{
								fini = true;
								break;		// stop if garbage after number
							}
						}
					}
					st = "";
					MultiID.MuInterrupt();
				}
				while (!fini && !MultiID.muAbort);
				for (i = 0; i < k / 2; i++)
				{
					sD = Common.nList[zI].V[i];
					Common.nList[zI].V[i] = Common.nList[zI].V[k - 1 - i];
					Common.nList[zI].V[k - 1 - i] = sD;
				}
				if (k > 0) Common.nList[zI].N = k;
				if (j > 0)
				{
					sD = (int)Math.Pow(10, j);
					MultiID.RMul1SI(sD, Common.nList[zI]);
					sD = System.Int32.Parse(stN);
					Common.nList[zI].V[0] += sD;
				}
			}
			catch (Exception ex)
			{
				// trap read error
				MultiID.WriteLn(" Read error file \"" + fName + '"');
				Common.WCurDir(fName);
				Common.ReportError("ReadFNm10", ex.Message);
				oK = false;
			}
		} // ReadFNm10

		public static void ReadFNm(StreamReader inF, out string name, out bool oK, int zI, ref string fName)
		// read in z from an already opened file
		// get its name and base from file, oK = true; if no i/O errors
		{
			char ch;
			string st;
			int i;
			int j = 0;
			int baseIS;
			int baseIL = 0;
			string maxD = "9";
			string stN = "";
			bool fini = false;
			bool vStarted = false;	// false if still looking for first digit
			bool sFound = false;	// false if still looking for a sign
			bool sign = false;
			oK = false;
			name = "";
			MultiID.ReSizeSI(fMC, Common.nList[zI]);	// z = 0, don't change name
			try
			{
				do
				{
					st = inF.ReadLine();	// get next line of input
					if (st == null) break;	// null => EOF
					if (baseIL == 0)
					{
						j = st.ToUpper().IndexOf("BASE("); // look for base(xx
						if (j >= 0)
						{
							stN = st.Substring(j + 5, 2);
							if (stN[1] < '0' || stN[1] > '9')
							{
								stN = stN.Substring(0, 1);
								j--;
							}
							if (stN[0] < '0' || stN[0] > '9')
							{
								baseIL = 10;
								st = "";
							}
							else
							{
								baseIL = System.Int32.Parse(stN);
								if (baseIL < 2 || baseIL > 36) baseIL = 10;
								if (st[j+7] == ')') j++;
								MultiID.Delete(ref st, 0, j + 7);
							}
							maxD = MultiID.MaxDig(baseIL);
						}
					}
					if (name == "" && !vStarted) // no name in file, no problem
					{
						i = st.IndexOf("=");
						if (i > 0)
						{
							name = st.Substring(0, i).Trim(' '); // get name from file just before "="
							MultiID.Delete(ref st, 0, i+1);
						}
					}
					for (i = 1; i <= st.Length; i++)
					{
						ch = st[i-1];
						if (!vStarted) // get sign
						{
							if (!sFound)
							{
								if (ch == '+' || ch == '-')
								{
									sFound = true;
									if (ch == '-') sign = true;
									Common.ReplaceAt(ref st, i-1, ",");
								}
							}
						}
						if (ch >= '0' && ch <= maxD[0] &&
										(ch <= '9' || ch >= 'A')) // get value
						{
							if (i > 1) MultiID.Delete(ref st, 0, i - 1);
							if (baseIL == 0) baseIL = 10;
							oK = true;
							if (baseIL == 10)
							{
								ReadFNm10(inF, ref oK, zI, ref fName, st); // read in base 10
							}
							else
							{
								baseIS = MultiID.baseI;
								MultiID.baseI = baseIL;
								if (!Common.quiet) MultiID.Write("Base " + MultiID.baseI + " ");
								ReadFNmB(inF, out oK, zI, ref fName, st); // read in base baseI from file
								MultiID.baseI = baseIS;
							}
							fini = true;
							break; // exit for
						}
					}
				}
				while (!fini);
				if (!oK) MultiID.WriteLn(" No named number found");
				Common.nList[zI].S = sign;
				NormN(zI);
			}
			catch (Exception ex)
			{
				// trap read error
				MultiID.WriteLn(" Read error file \"" + fName + '"');
				Common.WCurDir(fName);
				Common.ReportError("ReadFNm", ex.Message);
				oK = false;
			}
		} // ReadFNm

		public static bool ReadFile(string fName, int xI)
		// read in a number from a file after opening it
		{
			StreamReader inF;		// file number to read from
			bool oK;
			string name;
			int tI;
			int t2I;
			string dir;
			if (fName == "") fName = "NoName.XIN";
			if (!Common.OpenRead(out inF, fName, out dir)) return false;
			if (!Common.quiet) MultiID.WriteLn("Reading number file \"" + fName + "\" ");
			if (xI != 0)
			{
				ReadFNm(inF, out name, out oK, xI, ref fName); // I Primitive op code
			}
			else
			{
				Common.InitNAdd(1, "ReadFile-tI", out tI);
				ReadFNm(inF, out name, out oK, tI, ref fName); // readN Procedure
				if (oK)
				{
					if (name != "")
					{
						Common.LFindAdd(name, out t2I);
						SetToII(tI, t2I);
					}
					else
					{
						SetToII(tI, Common.iTop);
					}
				}
				Common.LDelete(tI);
			}
			inF.Close();
			if (!Common.quiet)
			{
				if (name != "" && oK) MultiID.Write("containing " + name);
				MultiID.WriteLn();
				MultiID.WriteLn("File \"" + fName + "\" closed");
			}
			return true;
		} // ReadFile

		public static void CalRead(string fName, int xI)
		// determine name and read in a number from a file
		{
			if (fName == "" && xINIn != 0)
				fName = Common.nList[xINIn].Nm.Substring(7);		// remove "XINIn: "
			if (fName == "" && Common.comI != 0)
				fName = Common.nList[Common.comI].Nm.Substring(6);	// remove "File: "
			if (fName == "") fName = "NoName.XIN";
			Common.FixFName(ref fName, "XIN");
			Common.CalReadN(fName, xI);
		}

		public static void CalWriteN(string fName, int xI)
		// output a number on the list to a file with name fName
		{
			StreamWriter outF; // text file output for Number
			string st;
			int tot = 0;
			st = " with " + Common.nList[xI].Nm;
			if (fName == "") fName = "NoName.XIN";
			if (!Common.ChkWrite(out outF, fName, st)) return;			// open file, exit if not opened
			MultiID.WriteLn(null, outF); // one blank line
			if (MultiID.baseO != 10)
				MultiID.WriteLn2(null, outF, "Base(" + MultiID.baseO.ToString() + ")");
			MultiID.WriteLn2(null, outF, Common.nList[xI].Nm + " =");	// output name to file #outF
			MultiID.WriteSILn(null, outF, Common.nList[xI], ref tot);	// output x to file #outF
			outF.Close();												// close the file
			// output status to the screen
			if (!Common.quiet) MultiID.WriteLn("File \"" + fName + "\" closed");
		}

		public static void CalWrite(string fName, int xI)
		// output a number on the list to a file after checking its name
		{
			if (fName == "" && xINOut != 0)
				fName = Common.nList[xINOut].Nm.Substring(8);		// remove "XINOut: "
			if (fName == "" && Common.comI != 0)
				fName = Common.nList[Common.comI].Nm.Substring(6);	// remove "File: "
			if (fName == "") fName = "NoName.XIN";
			Common.FixFName(ref fName, "XIN");
			CalWriteN(fName, xI);
		}

		public static void CalLFile(ref string fName) // establish log file name
		{
			if (fName == "" && xILOut != 0)
				fName = Common.nList[xILOut].Nm.Substring(8);		// remove "XILOut: "
			if (fName == "" && Common.comI != 0)
				fName = Common.nList[Common.comI].Nm.Substring(6);	// remove "File: "
			if (fName == "") fName = "NoName.XIL";
			Common.FixFName(ref fName, "XIL");
		}

		public static void CalFileNm(string stNm, ref string st, ref int nI)
		// get File name from command line in st and put it on the list in nI
		{
			string stF = Common.FileNm(ref st);
			string stL = stNm + ": " + stF;
			if (nI == 0)
				Common.InitNAdd(1, stL, out nI);
			else
				Common.nList[nI].Nm = stL;
			if (!Common.quiet)
			{
				MultiID.WriteDLn(Common.nList[nI].Nm);
			}
		}

		public static void CalReadConfig() // read and execute file Config.XIC
		{
			CalReadCode("Config.XIC");
		}

		public static void CalWriteConfig() // write file Config.XIC
		{
			StreamWriter outF; // text file: configuration output
			string st;
			int fMBI;
			string savDir = Environment.CurrentDirectory.ToString();
			Directory.SetCurrentDirectory(Common.homeDir);
			if (Common.ChkWrite(out outF, "Config.XIC", ""))
			{
				MultiID.WriteLn(null, outF, "@Echo Off");
				MultiID.WriteLn(null, outF, "Rem  Start of file Config.XIC");
				MultiID.WriteLn(null, outF, "BaseI(0)");
				MultiID.WriteLn(null, outF, "SetMax(" + MultiID.mMax * MultiID.muDMax + ")");
				MultiID.Write(null, outF, "LastTop=;  ");
				MultiID.Write(null, outF, fMC * MultiID.muDMax + " M;  ");
				MultiID.WriteLn(null, outF, MultiID.muDpG + " G;");
				MultiID.WriteLn(null, outF, "SetC(" + Common.mComs + ")");
				MultiID.WriteLn(null, outF, "SetD(" + MultiID.maxDis + ")");
				if (Common.saveTop) { st = "1"; } else { st = "0"; };
				MultiID.WriteLn(null, outF, "SaveTop(" + st + ")");
				if (MultiID.allowFHT) { st = "1"; } else { st = "0"; };
				MultiID.WriteLn(null, outF, "AllowFHT(" + st + ")");
				if (MultiID.forceFHT) { st = "1"; } else { st = "0"; };
				MultiID.WriteLn(null, outF, "ForceFHT(" + st + ")");
				if (MultiID.diagOn) { st = "1"; } else { st = "0"; };
				if (MultiID.debug) st = "-1";
				MultiID.WriteLn(null, outF, "Diag(" + st + ")");
				if (MultiID.timeIt && !MultiID.diagOn)
					MultiID.WriteLn(null, outF, "Time");
				if (Common.autoD) { st = "1"; } else { st = "0";};
				MultiID.WriteLn(null, outF, "AutoDisplay(" + st + ")");
				MultiID.WriteLn(null, outF, "ChDir(\"" + savDir + "\")");
				Common.LFind("FMB", out fMBI);
				if (fMBI != 0)
				{
					CalWriteN("FMB.XIN", fMBI);
					MultiID.WriteLn(null, outF, "ReadN(\"FMB.XIN\")");
				}
				if (xICIn != 0)
				{
					st = Common.nList[xICIn].Nm.Substring(7);	// remove "XICIn: "
					MultiID.WriteLn(null, outF, "XICIn(\"" + st + "\")");
				}
				if (xILOut != 0)
				{
					st = Common.nList[xILOut].Nm.Substring(8);	// remove "XILOut: "
					MultiID.WriteLn(null, outF, "XILOut(\"" + st + "\")");
				}
				if (xINIn != 0)
				{
					st = Common.nList[xINIn].Nm.Substring(7);	// remove "XINIn: "
					MultiID.WriteLn(null, outF, "XINIn(\"" + st + "\")");
				}
				if (xINOut != 0)
				{
					st = Common.nList[xINOut].Nm.Substring(8);	// remove "XINOut: "
					MultiID.WriteLn(null, outF, "XINOut(\"" + st + "\")");
				}
				if (Common.comI != 0)
				{
					st = Common.nList[Common.comI].Nm.Substring(6);	// remove "File: "
					MultiID.WriteLn(null, outF, "\"" + st + "\"");
				}
				if (Common.lrnL != 0)
				{
					st = Common.nList[Common.lrnL].Nm.Substring(5); // remove "Lrn: "
					MultiID.WriteLn(null, outF, "X " + st);
				}
				if (MultiID.logg) { st = "1"; } else { st = "0"; }
				MultiID.WriteLn(null, outF, "LogScreen(" + st + ")");
				MultiID.WriteLn(null, outF, "BaseO(" + MultiID.baseO + ")");
				MultiID.WriteLn(null, outF, "BaseI(" + MultiID.baseI + ")");
				MultiID.WriteLn(null, outF, Common.nList[Common.iTop].Nm + "=");
				if (Common.quiet) { st = "1"; } else { st = "0"; }
				MultiID.WriteLn(null, outF, "Quiet(" + st + ")");
				MultiID.WriteLn(null, outF, "Pri(" + Common.pri + ")");
				MultiID.WriteLn(null, outF, "Rem  End of file Config.XIC");
				if (Common.echoB) { st = "On"; } else { st = "Off"; }
				MultiID.WriteLn(null, outF, "Echo " + st);
				outF.Close();
				if (!Common.quiet) MultiID.WriteLn("File Config.XIC closed");
			}
			Directory.SetCurrentDirectory(savDir);
		} // CalWriteConfig

		public static bool AProcedure(ref string st, ref int resSav, ref string fName) // do a procedure
		{
			int po;
			int tot;
			string stL;
			int tI;
			double db;
			string name = Common.GetField(ref st);
			int i = name.Length;
			resSav = 0;
			fName = "";
			if (i == 0 || MultiID.muErr) return false;
			if (st.Length > i && st[i] == '=') return false; // if name= assignment
			if (name != "ALLD" &&
				name != "ALLOWFHT" &&
				name != "AUTODISPLAY" &&
				name != "BASE" &&
				name != "BASEI" &&
				name != "BASEO" &&
				name != "BERNM" &&
				name != "CHDIR" &&
				name != "CLEARBERN" &&
				name != "CLEAREULER" &&
				name != "CLEARHIST" &&
				name != "CLEARLOG" &&
				name != "D1LINE" &&
				name != "DBOOL" &&
				name != "DDIG" &&
				name != "DIAG" &&
				name != "ECHOSCREEN" &&	// same as LogScreen
				name != "EULERM" &&
				name != "EXIT" &&
				name != "FORCEFHT" &&
				name != "GENBERN" &&
				name != "GENEULER" &&
				name != "HISTH" &&
				name != "HISTW" &&
				name != "HELPH" &&
				name != "HELPW" &&
				name != "LOGSCREEN" &&
				name != "LT" &&
				name != "LX" &&
				name != "NEXT" &&		// "PAUSE" is in batch processing
				name != "PFA" &&
				name != "PFB" &&
				name != "PFE" &&
				name != "PTAB" &&
				name != "PRI" &&
				name != "QUIET" &&
				name != "RAN" &&
				name != "READN" &&
				name != "RESTORE" &&
				name != "RUN" &&
				name != "RUNH" &&
				name != "RUNW" &&
				name != "SAVE" &&
				name != "SAVETOP" &&
				name != "SETC" &&
				name != "SETD" &&
				name != "SETM" &&
				name != "SETMAX" &&
				name != "TIME" &&
				name != "WRITE" &&
				name != "WRITELN" &&
				name != "WRITEN" &&
				name != "XICIN" &&
				name != "XILOUT" &&
				name != "XININ" &&
				name != "XINOUT")
			{
				return false;
			}
			Common.DelNPBls(ref st, i);		// if name never uses ()
			if (name == "BERNM" || name == "CLEARBERN" || name == "CLEAREULER" ||
				name == "CLEARHIST" || 	name == "CLEARLOG" || name == "EULERM" ||
				name == "EXIT" || name == "LT" || name == "LX" ||
				name == "NEXT" || name == "RAN" || name == "RESTORE" ||
				name == "SAVE" || name == "TIME")
			{
				if (st != "" && st[0] == '(') // allow use of ( or () but not (x)
				{
					Common.DelNPBls(ref st, 1);
					if (st != "" && st[0] == ')') Common.DelNPBls(ref st, 1);
				}
			}
			if (name == "BERNM")	// return x = index of max Bernoulli number in storage
			{
				MultiID.SetTo1SI(2 * Common.nBern, Common.nList[Common.iTop]);
				NormN(Common.iTop);
				return true;
			}
			if (name == "CLEARBERN")
			{
				Common.nBern = -1; // force message output
				Common.ClearBern();
				return true;
			}
			if (name == "CLEAREULER")
			{
				Common.nEuler = -1; // force message output
				Common.ClearEuler();
				return true;
			}
			if (name == "CLEARHIST")
			{
				Common.ClearHist();
				return true;
			}
			if (name == "CLEARLOG")
			{
				Common.ClearLog();
				return true;
			}
			if (name == "EULERM")	// return x = index of max Euler number in storage
			{
				MultiID.SetTo1SI(2 * Common.nEuler, Common.nList[Common.iTop]);
				NormN(Common.iTop);
				return true;
			}
			if (name == "EXIT")	// totally quit and exit the program
			{
				MultiID.muAbort = true;
				Common.tQuitReq = true;
				Common.tExitFlag = true;
				return true;
			}
			if (name == "LX" || name == "LT")
			{
				Common.LFindAdd("LastTop", out Common.lastTop);
				SetToII(Common.lastTop, Common.iTop);
				return true;
			}
			if (name == "NEXT")
			{
				Common.iTop--;
				if (Common.iTop < 1) Common.iTop = Common.cList;
				return true;
			}
			if (name == "RAN")
			{
				Ran();
				return true;
			}
			if (name == "RESTORE")
			{
				resSav = 1;
				return true;
			}
			if (name == "SAVE")
			{
				resSav = 2;
				return true;
			}
			if ( (name == "XICIN") || (name == "XILOUT") || (name == "CHDIR") ||
				 (name == "XININ") || (name == "XINOUT") ||
				 (name == "READN") || (name == "WRITEN") || (name == "RUN") )
			{
				tI = 0;
				if (st != "" && st[0] == '(')
				{
					Common.DelNPBls(ref st, 1);
					if (st != "" && st[0] == ')')
						Common.DelNPBls(ref st, 1);
					else if (st != "" && st[0] != '\"')
					{
						if (name == "CHDIR")
							Common.ReportSin("Directory name expected: " + name + "(|", ref st);
						else
							Common.ReportSin("File name expected: " + name + "(|", ref st);
						return true;
					}
					else
					{
						if (name == "CHDIR") Common.ChangeDir(ref st);
						if (name == "XICIN") CalFileNm("XICIn", ref st, ref xICIn);
						if (name == "XILOUT") CalFileNm("XILOut", ref st, ref xILOut);
						if (name == "XININ") CalFileNm("XINIn", ref st, ref xINIn);
						if (name == "XINOUT") CalFileNm("XINOut", ref st, ref xINOut);
						if (name == "READN") CalRead(Common.FileNm(ref st), tI); // tI is nil
						if (name == "WRITEN") CalWrite(Common.FileNm(ref st), Common.iTop);
						if (name == "RUN")
						{
							fName = Common.FileNm(ref st);
							resSav = 3;
						}
						Common.DelNPBls(ref st, 1);
						if (st != "" && st[0] == ')') Common.DelNPBls(ref st, 1);
						return true;
					}
				}
				if (Common.comI == 0) stL = "\"";
				else stL = "\"" + Common.nList[Common.comI].Nm.Substring(5) + "\"";
				if (name == "CHDIR") Common.ChangeDir(ref stL);
				if (name == "XICIN") CalFileNm("XICIn", ref stL, ref xICIn);
				if (name == "XILOUT") CalFileNm("XILOut", ref stL, ref xILOut);
				if (name == "XININ") CalFileNm("XINIn", ref stL, ref xINIn);
				if (name == "XINOUT") CalFileNm("XINOut", ref stL, ref xINOut);
				if (name == "READN") CalRead(Common.FileNm(ref stL), tI);
				if (name == "WRITEN") CalWrite(Common.FileNm(ref stL), Common.iTop);
				if (name == "RUN")
				{
					fName = Common.FileNm(ref stL);
					resSav = 3;
				}
				return true;
			}
			if (name != "WRITE" && name != "WRITELN")
			{
				if (st == "" || st[0] != '(')
				{
					if (name == "DIAG")
					{
						if (!MultiID.timeIt) Common.DoubleSpace();
						MultiID.debug = false;
						MultiID.diagOn = true;
						MultiID.timeIt = true;
					}
					else if (name == "TIME")
					{
						if (!MultiID.timeIt) Common.DoubleSpace();
						MultiID.debug = false;
						MultiID.diagOn = false;
						MultiID.timeIt = true;
					}
					else if (name == "PRI")
						Common.DisplayPriority(); // display priority status
					else if (name == "QUIET")
						Common.quiet = true;
					else
						Common.ReportSin("( expected: " + name + "|", ref st);
					return true;
				}
				else
				{
					Common.DelNPBls(ref st, 1);
					Common.InitNAdd(fMC, "AProcedure-tI-1", out tI);
					if (!Expression(ref st, tI))
					{
						Common.LDelete(tI);
						Common.ReportSin("Expression expected: " + name + "(|", ref st);
						return true;
					}
					if (st != "" && st[0] == ')') Common.DelNPBls(ref st, 1);
					if (MultiID.muErr)
					{
						Common.LDelete(tI);
						return true;
					}
					if (name == "ALLD")
						PrimeFA.PrimeAllD(tI);
					else if (name == "ALLOWFHT")
					{
						MultiID.allowFHT = !Common.ZTestN(tI);
						if (!MultiID.allowFHT) MultiID.forceFHT = false;
					}
					else if (name == "AUTODISPLAY")
						Common.autoD = !Common.ZTestN(tI);
					else if (name == "BASE")
					{
						CalSBaseI(tI);
						CalSBaseO(tI);
					}
					else if (name == "BASEI")
						CalSBaseI(tI);
					else if (name == "BASEO")
						CalSBaseO(tI);
					else if (name == "D1LINE")
						MultiID.d1LineOn = !Common.ZTestN(tI);
					else if (name == "DBOOL")
						MultiID.dBoolOn = !Common.ZTestN(tI);
					else if (name == "DDIG")
						MultiID.dDigOn = !Common.ZTestN(tI);
					else if (name == "DIAG")
					{
						if (!Common.ZTestN(tI) && !MultiID.timeIt) Common.DoubleSpace();
						MultiID.diagOn = !Common.ZTestN(tI);
						MultiID.debug = Common.nList[tI].S;
						MultiID.timeIt = MultiID.diagOn;
					}
					else if (name == "FORCEFHT")
					{
						MultiID.forceFHT = !Common.ZTestN(tI);
						if (MultiID.forceFHT) MultiID.allowFHT = true;
					}
					else if (name == "GENBERN")
						GenBern(tI);
					else if (name == "GENEULER")
						GenEuler(tI);
					else if (name == "HISTH")
					{
						MultiID.GetDbInSI(out db, 100, 5000, Common.nList[tI]);
						Global.objRunForm.SetHistHeight((int)db);
					}
					else if (name == "HISTW")
					{
						MultiID.GetDbInSI(out db, 100, 5000, Common.nList[tI]);
						Global.objRunForm.SetHistWidth((int)db);
					}
					else if (name == "HELPH")
					{
						MultiID.GetDbInSI(out db, 100, 5000, Common.nList[tI]);
						Global.objRunForm.SetHelpHeight((int)db);
					}
					else if (name == "HELPW")
					{
						MultiID.GetDbInSI(out db, 100, 5000, Common.nList[tI]);
						Global.objRunForm.SetHelpWidth((int)db);
					}
					else if (name == "LOGSCREEN" || name == "ECHOSCREEN")
					{
						if (MultiID.logg == Common.ZTestN(tI)) Common.ToggleLogg();
					}
					else if (name == "PFA")
						PrimeFA.PrimeFAA(tI);
					else if (name == "PFB")
						XICommon.PrimeFAB(tI);
					else if (name == "PFE")
						PrimeFA.PrimeFAE(tI);
					else if (name == "PTAB")
					{
						MultiID.GetDbInSI(out db, 2, Int32.MaxValue, Common.nList[tI]);
						XICommon.GenPrimeTable((int)db);
					}
					else if (name == "PRI")
					{
						MultiID.GetDbInSI(out db, -3, 3, Common.nList[tI]); // 0 for normal priority
						Common.SetPriority((int)db);
						Common.DisplayPriority();
					}
					else if (name == "QUIET")
						Common.quiet = !Common.ZTestN(tI);
					else if (name == "RUNH")
					{
						MultiID.GetDbInSI(out db, 100, 5000, Common.nList[tI]);
						Global.objRunForm.SetRunHeight((int)db);
					}
					else if (name == "RUNW")
					{
						MultiID.GetDbInSI(out db, 100, 5000, Common.nList[tI]);
						Global.objRunForm.SetRunWidth((int)db);
					}
					else if (name == "SAVETOP")
						Common.saveTop = !Common.ZTestN(tI);
					else if (name == "SETC")
					{
						MultiID.GetDbInSI(out db, 0, 100000, Common.nList[tI]); // 0 for no change status
						Common.ReSizeHist((int)db);
					}
					else if (name == "SETD")
					{
						MultiID.GetDbInSI(out db, 14, Common.nMax * MultiID.muDMax, Common.nList[tI]);
						MultiID.maxDis = (int)db;
					}
					else if (name == "SETM")
						CalSMan(tI);
					else if (name == "SETMAX")
						CalSMan(tI);
					Common.LDelete(tI);
					return true;
				}
			}
			if (st != "" && st[0] == '(') // process Write and WriteLn
			{
				Common.DelNPBls(ref st, 1);
				if (st != "")
				{
					tot = 0;
					if (st != "" && st[0] == ')')
						Common.DelNPBls(ref st, 1);
					else if (st != "" && st[0] == '\"')
					{
						po = st.IndexOf("\"", 1);
						if (po < 0) po = st.Length;
						MultiID.WriteT(st.Substring(1, po - 1), ref tot);
						Common.DelNPBls(ref st, po+1);	// 1 too many ok for DelNPBls
					}
					else
					{
						Common.InitNAdd(fMC, "AProcedure-tI-2", out tI);
						if (!Expression(ref st, tI))
						{
							Common.LDelete(tI);
							Common.ReportSin("Expression expected: " + name + "(|", ref st);
							return true;
						}
						MultiID.WriteSI(Common.nList[tI], ref tot);
						Common.LDelete(tI);
					}
					if (st != "" && st[0] == ')') Common.DelNPBls(ref st, 1);
				}
			}
			if (name == "WRITELN") MultiID.WriteLn();
			return true;
		} // AProcedure

		public static bool AssignmentOp(string op) // is this an assignment?
		{
			return (op == "+=" || op == "-=" || op == "*=" || op == "/=" || op == "%=");
		}

		public static bool Assignment(ref string st, ref int nI)
		// do an assignment, nI unchanged if not an assignment
		{
			int pI; // pointer to left member of assignment statement
			int tI;
			string name = Common.GetField(ref st);
			int iL = name.Length;
			if (iL == 0 || iL == st.Length) return false;
			if (st.Length > iL+2)
			{
				string op = st.Substring(iL, 2);
				if (AssignmentOp(op))
				{
					op = op[0] + "(";
					st = name + "=" + name + op + st.Substring(iL+2);
				}
			}
			if (st[iL] == '=')
			{
				if (Variable(ref st, out pI)) // pI points to new top, may be the same as old top
				{
					Common.DelNPBls(ref st, 1);		// delete the = sign
					nI = pI;
					if (st.Length == 0)
					{
						return true;				// merely change top
					}
					Common.InitNAdd(fMC, "Assignment-tI", out tI);
					if (Expression(ref st, tI))
					{
						SetToII(tI, nI);
						Common.LDelete(tI);
						return true;
					}
					Common.LDelete(tI);
				}
			}
			return false;
		} // Assignment

		public static void ListReport() // report the contents of the nList
		// output name and value for each item on the list
		{
			int nI;
			int mI;
			int uI;
			int tot;
			int uB = Common.cList;
			int cI = uB;
			MultiID.WriteDLn(Common.StringOf(40, "-"));
			while (cI >= 1)
			{
				tot = 0;
				MultiID.WriteT(cI + ": ", ref tot);
				Common.WriteNV(Common.nList[cI], ref tot);
				nI = Common.nList[cI].N;
				mI = Common.nList[cI].M;
				uI = Common.nList[cI].V.GetUpperBound(0);
				if (MultiID.diagOn || nI != mI || nI != uI)
					MultiID.WriteT(" N=" + nI + " M=" + mI + " U=" + uI, ref tot);
				MultiID.WriteLn();
				if (cI > 1) MultiID.WriteLn(); // double space between values
				cI--;
			}
			MultiID.WriteLn(Common.StringOf(40, "-"));
		}

		public static void CalReadCode(string fName) // read in a Cal code file and Run it
		{
			if (fName == "" && xICIn != 0)
				fName = Common.nList[xICIn].Nm.Substring(7);		// remove "XICIn: "
			if (fName == "" && Common.comI != 0)
				fName = Common.nList[Common.comI].Nm.Substring(6);	// remove "File: "
			if (fName == "") fName = "NoName.XIC";
			Common.FixFName(ref fName, "XIC");
			if (!Common.RunFile(fName))
			{
				if (Common.MakeReady() == DialogResult.OK)			// pause for operator to make file/drive ready
				{
					if (!Common.RunFile(fName))
						MultiID.WriteLn("Aborting file input...");
				}
				MultiID.WriteLn();
			}
		}

		public static void CalDel(int nI) // delete nI from list
		// don't ever delete x at nI = 1, careful, nI and iTop may be the same Integer
		{
			if (nI > 1)
			{
				if (nI == Common.comI) Common.comI = 0;
				if (nI == Common.lrnL) Common.lrnL = 0;
				if (nI == xICIn) xICIn = 0;
				if (nI == xILOut) xILOut = 0;
				if (nI == xINIn) xINIn = 0;
				if (nI == xINOut) xINOut = 0;
				Common.LDelete(nI);
				if (Common.comI > nI) Common.comI--;
				if (Common.lrnL > nI) Common.lrnL--;
				if (xICIn > nI) xICIn--;
				if (xILOut > nI) xILOut--;
				if (xINIn > nI) xINIn--;
				if (xINOut > nI) xINOut--;
				if (Common.iTop >= nI) Common.iTop--;
			}
			else
			{
				if (Common.iTop == 1) Common.iTop = Common.cList;
			}
		}

		public static void CalComment(ref string st) // get Comment from command line in st
		{
			CalFileNm("File", ref st, ref Common.comI);
		}

		public static void CalSDpG(int nI)
		// set digits per group in number output display [0, nMax * muDMax], 0 => no ,'s
		{
			double db;
			MultiID.GetDbInSI(out db, 0, Common.nMax * MultiID.muDMax, Common.nList[nI]);
			MultiID.muDpG = (int)db;
		}

		public static void CalSBaseO(int nI)
		// set Display base in input and output [2, 36], 0 => 10, 'A' = 10, 'Z' = 35
		{
			double db;
			string maxD; // max Input digit "1" to "Z"
			MultiID.GetDbInSI(out db, 0, 36, Common.nList[nI]);
			if (db < 2) db = 10;
			MultiID.baseO = (int)db;
			maxD = MultiID.MaxDig(MultiID.baseO);
			if (!Common.quiet) MultiID.WriteLn("BaseO = " + MultiID.baseO + " base ten, Max digit = " + maxD);
		}

		public static void CalSBaseI(int nI)
		// set Display base in input and output [2, 36], 0 => 10, 'A' = 10, 'Z' = 35
		{
			double db;
			string maxD; // max Input digit "1" to "Z"
			MultiID.GetDbInSI(out db, 0, 36, Common.nList[nI]);
			if (db < 2) db = 10;
			MultiID.baseI = (int)db;
			maxD = MultiID.MaxDig(MultiID.baseI);
			if (!Common.quiet) MultiID.WriteLn("BaseI = " + MultiID.baseI + " base ten, Max digit = " + maxD);
		}

		public static void SetNFMB(int nI) // set Modulo base FMB on Common.nList = value of nI
		{
			int fMBI;
			Common.LFindAdd("FMB", out fMBI);
			if (fMBI == nI) return;
			SetToII(nI, fMBI);
		}

		public static void SetFMB() // set Modulo base FMB in MultiID package to FMB on the Common.nList
		{
			int fMBI;
			Common.LFindAdd("FMB", out fMBI);
			MultiID.SetToSIN(Common.nList[fMBI], MultiID.fMB);
		}

		public static void CalExxLrn(int nI) // setup to execute learned line x times
		{
			double db;
			MultiID.GetDbInSI(out db, 0, Int32.MaxValue, Common.nList[nI]);
			Common.exX = (int)db;
		}

		public static bool Primitive(ref string st, int nI) // do operation
		{
			if (MultiID.muErr) return false;
			string op = st.Substring(0, 1).ToUpper();	// operation code character "+", "S", etc.
			if (op == " " || op == ";")					// " " and ";" never get this far
				{} // noOp
			else if (op == "A")
				Common.autoD = !Common.autoD;
			else if (op == "B")
				Common.CalDLrn(ref st);
			else if (op == "C")
			{
				Common.nList[nI].S = !Common.nList[nI].S;
				MultiID.NormSI(Common.nList[nI]);
			}
			else if (op == "F" || op == "!")
				FacBiN(nI, nI);
			else if (op == "#")
				XICommon.Primorial(nI);
			else if (op == "G")
				CalSDpG(nI);
			else if (op == "H")
				Common.ToggleLogg();
			else if (op == "I")
				CalRead("", Common.iTop);
			else if (op == "J")
				CalReadCode("");
			else if (op == "K")
				CalExxLrn(nI);
			else if (op == "M")
				CalSMan(nI);
			else if (op == "N")
				RanN(nI);
			else if (op == "Q")
			{
				MultiID.muAbort = true;
				Common.tQuitReq = true;
			}
			else if (op == "R")
				XICommon.SqRtRemN(nI, nI);
			else if (op == "S")
				XICommon.MulN(nI, nI, nI);
			else if (op == "W")
				CalWrite("", Common.iTop);
			else if (op == "X")
				Common.CalExLrn(ref st);
			else if (op == "Y")
				CalDel(nI);
			else if (op == "Z")
				ListReport();
			else if (op == "\"")
				CalComment(ref st);
			else if (op == "%")
				SetNFMB(nI);
			else if (op == "/")
			{
				SetFMB();
				MultiID.ModMBSI(Common.nList[nI]);
				NormN(nI);
			}
			else if (op == @"\")
			{
				CalSBaseI(nI);
				CalSBaseO(nI);
			}
			else if (op == "$")
			{
				RunForm.ClearOutput();
				new Calc();				// re-initialize class Calc
			}
			else if (op == ">")
				CalWriteConfig();
			else if (op == "<")
			{
				st = "";
				CalReadConfig();
			}
			else if (op == "]")
				Common.SaveHist();
			else if (op == "[")
				Common.RestoreHist();
			else if (op == "?")
				RunForm.HelpForm();
			else
			{
				return false;
			}
			Common.DelNPBls(ref st, 1);
			return true;
		} // Primitive

		public static void FacMBN(int xI, int zI) // z = x! = 1*2*3*...*x % FMB
		{
			SetFMB();
			MultiID.FacMBSI(Common.nList[xI], Common.nList[zI]);
		}

		public static void FacBiN(int xI, int zI) // z = x! = 1*2*3*...*x by binary splitting
		{
			MultiID.ClearSI(MultiID.fMB);
			MultiID.FacMBiSI(Common.nList[xI], Common.nList[zI]);
		}

		public static void FacMBiN(int xI, int zI) // z = x! = 1*2*3*...*x by binary splitting
		{
			SetFMB();
			MultiID.FacMBiSI(Common.nList[xI], Common.nList[zI]);
		}

		public static void FacN(int xI, int zI) // z = x! = 1*2*3*...*x
		{
			MultiID.ClearSI(MultiID.fMB);
			MultiID.FacMBSI(Common.nList[xI], Common.nList[zI]);
		}

		public static void FacM2(MultiSI a, MultiSI b, MultiSI z)
			// z = Fac(a) / Fac(b) by binary splitting
			// a, b are not modified unless they share memory with z
			// will write to standard output if diagOn is true
		{
			SetFMB();
			MultiID.Fac2SI(a, b, z);
			MultiID.NormSI(z);
		} // Fac2

		public static void Fac2(MultiSI a, MultiSI b, MultiSI z)
			// z = Fac(a) / Fac(b) by binary splitting
			// a, b are not modified unless they share memory with z
			// will write to standard output if diagOn is true
		{
			MultiID.ClearSI(MultiID.fMB);
			MultiID.Fac2SI(a, b, z);
			MultiID.NormSI(z);
		} // Fac2

		public static void GamN(int xI, int zI) // z = Gamma(x) = (x-1)! = 1*2*3*...*(x-1)
		{
			MultiID.ClearSI(MultiID.fMB);
			MultiID.Add1SI(Common.nList[xI], -1, Common.nList[zI]);
			MultiID.FacMBiSI(Common.nList[zI], Common.nList[zI]);
		}

		public static void FibN(int xI, int zI) // z = FibonacciNumber(x)
		{
			FibSI(Common.nList[xI], Common.nList[zI]);
		}

		public static void FibSI(MultiSI x, MultiSI z)
		// z = FibonacciNumber(x), Fib(0) = 0
		// x may have the same address in memory as z
		// x is not changed unless it shares memory with z
		// sets muErr true if overflow or error
		{
			int maxFib = Int32.MaxValue;
			bool sign = x.S;
			x.S = false;
			double db;
			MultiID.GetDbInSI(out db, 0, (double)(maxFib) + 1.0, x);
			x.S = sign;
			if (db > maxFib)	// n too large
			{
				Common.ReportError("FibSI:", "n > " + maxFib + ", too large for Fibonacci number");
				MultiID.muErr = true;
				z &= 0;			// n too large
				return;
			}
			int n = (int)db;
			if (n == 0) { z &= 0; return; }
			if (n == 1) { z &= 1; return; }
			if (n == 2) { z &= 1; z.S = sign; return; }
			MultiSI a = new MultiSI(MultiID.mMax);
			MultiSI b = new MultiSI(MultiID.mMax);
			MultiSI c = new MultiSI(MultiID.mMax);
			a &= 1;
			b &= 1;
			for (int i = 2; i < n; i++)
			{
				MultiID.AddSI(a, b, c);
				MultiID.SetToSI(b, a);
				MultiID.SetToSI(c, b);
				MultiID.MuInterrupt();
				if (MultiID.muAbort) break; // exit for
				if (MultiID.statReq2)
				{
					MultiID.nDone = i - 1;
					MultiID.nToGo = n - i - 1;
					MultiID.WritenDone("FibSI:");
				}
			}
			if ((n & 1) == 1) sign = false;		// n odd => answer > 0
			z &= c;
			z.S = sign;
			if (MultiID.muAbort) z &= 0;
			MultiID.DoneSI(c);
			MultiID.DoneSI(b);
			MultiID.DoneSI(a);
		} // FibSI

		public static void GenBern(int nI)
		// generate even numbered Bernoulli numbers B(0) thru B(nI) = bernN[i/2] / bernD[i/2]
		{
			double db;
			MultiID.GetDbInSI(out db, 4, Common.maxBern + 1, Common.nList[nI]);
			int n = (int)db;
			if (n > Common.maxBern) // n too large
				Common.ReportError("GenBern", "n > " + Common.maxBern + ", too large for Bernoulli number");
			else
				Common.GenBernI(n);
			MultiID.muErr = false; // because no value is returned to nList[nI]
		}

		public static void GenEuler(int nI)
		// generate even numbered Euler numbers E(0) thru E(nI) = euler[i/2]
		{
			double db;
			MultiID.GetDbInSI(out db, 4, Common.maxEuler + 1, Common.nList[nI]);
			int n = (int)db;
			if (n > Common.maxEuler) // n too large
				Common.ReportError("GenEuler", "n > " + Common.maxEuler + ", too large for Euler number");
			else
				Common.GenEulerI(n);
			MultiID.muErr = false; // because no value is returned to nList[nI]
		}

		public static void BernD(MultiSI nSI, MultiSI z)
		// z = denominator of B(n), the n'th Bernoulli number
		{
			if (nSI.S) { z &= 1; return; }	// n negative
			int n;
			if (nSI.N > 1)
				n = Common.maxBern + 1;		// n too large
			else
				MultiID.Get1SI(out n, nSI);
			if (n > Common.maxBern)
			{
				Common.ReportError("BernD", "n > " + Common.maxBern + ", too large for Bernoulli number");
				MultiID.muErr = true;
				z &= 1;						// n too large
				return;
			}
			if (n == 0) { z &= 1; return; }
			if (n == 1) { z &= 2; return; }
			if ((n & 1) == 1) { z &= 1; return; }	// n odd > 1
			if (n/2 > Common.nBern) Common.GenBernI(n);
			if (MultiID.muErr || MultiID.muAbort)
				z &= 1;
			else
				z &= Common.bernD[n/2];
		} // BernD

		public static void BernN(MultiSI nSI, MultiSI z)
		// z = numerator of B(n), the n'th Bernoulli number
		{
			if (nSI.S) { z &= 0; return; }	// n negative
			int n;
			if (nSI.N > 1)
				n = Common.maxBern + 1;		// n too large
			else
				MultiID.Get1SI(out n, nSI);
			if (n > Common.maxBern)
			{
				Common.ReportError("BernN", "n > " + Common.maxBern + ", too large for Bernoulli number");
				MultiID.muErr = true;
				z &= 0;						// n too large
				return;
			}
			if (n == 0) { z &= 1; return; }
			if (n == 1) { z &= -1; return; }
			if ((n & 1) == 1) { z &= 0; return; } // n odd > 1
			if (n/2 > Common.nBern) Common.GenBernI(n);
			if (MultiID.muErr || MultiID.muAbort)
				z &= 0;
			else
				z &= Common.bernN[n/2];
		} // BernN

		public static void Euler(MultiSI nSI, MultiSI z)
		// z = E(n), the n'th Euler number
		{
			if (nSI.S) { z &= 0; return; }	// n negative
			double db;
			MultiID.GetDbInSI(out db, 0, Common.maxEuler + 1, nSI);
			int n = (int)db;
			if (n > Common.maxEuler)		// n too large
			{
				Common.ReportError("Euler", "n > " + Common.maxEuler + ", too large for Euler number");
				MultiID.muErr = true;
				z &= 0;						// n too large
				return;
			}
			if ((n & 1) == 1) { z &= 0; return; }	// n odd > 0
			if (n == 0) { z &= 1; return; }
			if (n == 2) { z &= -1; return; }
			if (n == 4) { z &= 5; return; }
			if (n/2 > Common.nEuler) Common.GenEulerI(n);
			if (MultiID.muErr || MultiID.muAbort)
				z &= 0;
			else
				z &= Common.euler[n/2];
		} // Euler

		public static void Bino(MultiSI a, MultiSI b, MultiSI z)
		// z = Binomial coefficient (a, b) by binary splitting
		// a, b are not modified unless they share memory with z
		// will write to standard output if diagOn is true
		{
			MultiID.ClearSI(MultiID.fMB);
			MultiID.BinoSI(a, b, z);
		} // Bino

		public static void MaxN(MultiSI x, MultiSI y, int zI)	// z = max of x and y
		{
			if (x >= y)
				SetToN(x, zI);
			else
				SetToN(y, zI);
			Calc.NormN(zI);
		} // MaxN

		public static void MinN(MultiSI x, MultiSI y, int zI)	// z = min of x and y
		{
			if (x >= y)
				SetToN(y, zI);
			else
				SetToN(x, zI);
			Calc.NormN(zI);
		} // MinN

		public static void MagN(MultiSI x, MultiSI y, int zI)	// z = SqRt(Sq(x) + Sq(y)), Re = remainder
		{
			int tI;
			Common.InitNAdd(1, "MagN-tI", out tI);
			SetToN(x, tI);
			XICommon.MulN(tI, tI, tI);
			SetToN(y, zI);
			XICommon.MulN(zI, zI, zI);
			XICommon.RAddN(tI, zI);
			Common.LDelete("MagN-tI");
			XICommon.SqRtRemN(zI, zI);
		} // MagN

		public static void DivIntN(int xI, int yI, int zI)	// z = Floor(x/y)
		// sets muErr true if overflow
		{
			int tI;
			int m = Common.nList[xI].N;
			Common.InitNAdd(m, "DivIntN-tI", out tI);
			MultiID.DivSI(Common.nList[xI], Common.nList[yI], Common.nList[tI]);
			SetToII(tI, zI);
			Common.LDelete(tI);
			NormN(zI);
		} // DivIntN
	
		public static void DivRemN(int xI, int yI, int zI)	// z = x/y, Re = remainder
		{
			XICommon.DivN(xI, yI, zI);
		} // DivRemN
	
		public static void Cleanup() // cleanup named list after a run-time error
		{
			Common.LDelete("AFunction-t2I");
			Common.LDelete("AFunction-t3I");
			Common.LDelete("AFunction-tI");
			Common.LDelete("AProcedure-tI-1");
			Common.LDelete("AProcedure-tI-2");
			Common.LDelete("Assignment-tI");
			Common.LDelete("Condition-tI");
			Common.LDelete("DivN-tI");
			Common.LDelete("Expression-tI");
			Common.LDelete("MulN-tI");
			Common.LDelete("Power-t2I");
			Common.LDelete("Power-tI");
			Common.LDelete("PrimeFAB-dI");
			Common.LDelete("PrimeFAB-qI");
			Common.LDelete("PrimeFAB-rI");
			Common.LDelete("Primorial-tI");
			Common.LDelete("RAddN-tI");
			Common.LDelete("RAddSIN-tI");
			Common.LDelete("ReadFile-tI");
			Common.LDelete("SimpExpr-tI");
			Common.LDelete("Term-t2I");
			Common.LDelete("Term-tI");
			GC.Collect();	// force garbage collection of all generations
		} // Cleanup

		public static int fMC;			// current max # of super digits in a result
		public static int xICIn;		// code input list item, its name has the File name
		public static int xILOut;		// log output list item, its name has the File name
		public static int xINIn;		// number input list item, its name has the File name
		public static int xINOut;		// number output list item, its name has the File name
	}
}
