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

namespace MyNamespace
{
	/// <summary>
	///		Multiple precision floating-point 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>

	// ------- A multiple-precision signed floating number
	public class MultiF : MultiSI	// signed integer part
	{
		public long C;				// characteristic, 2 => * baseM^2

		public MultiF()				// initialize with M = 2
			: base()				// calls MultiSI()
		{
			C = 0;	// constructor logic
		}

		public MultiF(int nMaxI)		// initialize with M = nMaxI
			: base(nMaxI)				// calls MultiSI(i)
		{
			C = 0;
		}

//		public static bool operator = (MultiF left, MultiF right)	// not allowed to overload =
//		{
//			MultiFD.SetToF(right, left);
//			return true;
//		}

		public static MultiF operator & (MultiF left, MultiF right)	// use &= for = assignment
		{
			MultiFD.SetToF(right, left);
			return left;
		}

		public static MultiF operator & (MultiF left, MultiSI right)	// use &= for = assignment
		{
			MultiFD.SetToSIF(right, left);
			return left;
		}

		public static MultiF operator & (MultiF left, int right)	// use &= for = assignment
		{
			MultiFD.SetTo1F(right, left);
			return left;
		}

		public static MultiF operator & (MultiF left, long right)	// use &= for = assignment
		{
			MultiFD.SetToExF(right, left);
			return left;
		}

		public static MultiF operator & (MultiF left, double right)	// use &= for = assignment
		{
			MultiFD.SetToDbF(right, left);
			return left;
		}

		public static MultiF operator & (MultiF left, decimal right)	// use &= for = assignment
		{
			MultiFD.SetToDeF(right, left);
			return left;
		}

		public static MultiF operator + (MultiF left, MultiF right) // can be used for a += b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.AddF(left, right, z);
			return z;
		}

		public static MultiF operator + (MultiF left, int right) // can be used for a += b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.Add1F(left, right, z);
			return z;
		}

		public static MultiF operator + (int left, MultiF right) // can be used for a += b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.Add1F(right, left, z);
			return z;
		}

		public static MultiF operator - (MultiF left, MultiF right) // can be used for a -= b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.SubF(left, right, z);
			return z;
		}

		public static MultiF operator - (MultiF left, int right) // can be used for a -= b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.Add1F(left, -right, z);
			return z;
		}

		public static MultiF operator - (int left, MultiF right) // can be used for a -= b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.Add1F(right, -left, z);
			MultiFD.ChSF(z);
			return z;
		}

		public static MultiF operator - (MultiF x)
		{
			MultiF z = new MultiF(x.N);
			MultiFD.SetToF(x, z);
			MultiFD.ChSF(z);
			return z;
		}
		public static MultiF operator * (MultiF left, MultiF right) // can be used for a *= b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.MulF(left, right, z);
			return z;
		}

		public static MultiF operator * (MultiF left, int right) // can be used for a *= b
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.Mul1F(left, right, z);	// right <= maxDigit
			return z;
		}

		public static MultiF operator * (int left, MultiF right)
		{
			MultiF z = new MultiF(Calc.fMC);
			MultiFD.Mul1F(right, left, z);	// left <= maxDigit
			return z;
		}

		public static MultiF operator / (MultiF left, MultiF right) // can be used for a /= b
		{
			MultiF q = new MultiF(Calc.fMC);
			MultiFD.DivF(left, right, q);
			return q;
		}

		public static MultiF operator / (MultiF left, int right) // can be used for a /= b
		{
			MultiF q = new MultiF(Calc.fMC);
			MultiFD.Div1F(left, right, q);
			return q;
		}

		// % and ^ will default to Singed Integer versions

		public static bool operator == (int d1, MultiF z)
		{
			MultiF dF = new MultiF(MultiID.sdInInt);
			MultiFD.SetTo1F(d1, dF);
			return (MultiFD.CompFF(dF, z) == 0);
		}

		public static bool operator != (int d1, MultiF z)
		{
			MultiF dF = new MultiF(MultiID.sdInInt);
			MultiFD.SetTo1F(d1, dF);
			return (MultiFD.CompFF(dF, z) != 0);
		}

		public static bool operator == (MultiF z, int d1)
		{
			MultiF dF = new MultiF(MultiID.sdInInt);
			MultiFD.SetTo1F(d1, dF);
			return (MultiFD.CompFF(dF, z) == 0);
		}

		public static bool operator != (MultiF z, int d1)
		{
			MultiF dF = new MultiF(MultiID.sdInInt);
			MultiFD.SetTo1F(d1, dF);
			return (MultiFD.CompFF(dF, z) != 0);
		}

		public static bool operator == (long ex, MultiF z)
		{
			MultiF exF = new MultiF(MultiID.sdInLong);
			MultiFD.SetToExF(ex, exF);
			return (MultiFD.CompFF(exF, z) == 0);
		}

		public static bool operator != (long ex, MultiF z)
		{
			MultiF exF = new MultiF(MultiID.sdInLong);
			MultiFD.SetToExF(ex, exF);
			return (MultiFD.CompFF(exF, z) != 0);
		}

		public static bool operator == (MultiF z, long ex)
		{
			MultiF exF = new MultiF(MultiID.sdInLong);
			MultiFD.SetToExF(ex, exF);
			return (MultiFD.CompFF(exF, z) == 0);
		}

		public static bool operator != (MultiF z, long ex)
		{
			MultiF exF = new MultiF(MultiID.sdInLong);
			MultiFD.SetToExF(ex, exF);
			return (MultiFD.CompFF(exF, z) != 0);
		}

		public static bool operator == (MultiF x, MultiF y)
		{
			return (MultiFD.CompFF(y, x) == 0);
		}

		public static bool operator != (MultiF x, MultiF y)
		{
			return (MultiFD.CompFF(y, x) != 0);
		}

		public static bool operator < (MultiF x, MultiF y)
		{
			return (MultiFD.CompFF(y, x) < 0);
		}

		public static bool operator > (MultiF x, MultiF y)
		{
			return (MultiFD.CompFF(y, x) > 0);
		}

		public static bool operator <= (MultiF x, MultiF y)
		{
			return (MultiFD.CompFF(y, x) <= 0);
		}

		public static bool operator >= (MultiF x, MultiF y)
		{
			return (MultiFD.CompFF(y, x) >= 0);
		}

		public static MultiF operator ++ (MultiF x)
		{
			MultiFD.RAddF(MultiFD.fOne, x);
			return x;
		}

		public static MultiF operator -- (MultiF x)
		{
			MultiFD.RAddF(MultiFD.fMOne, x);
			return x;
		}

		public override bool Equals(object o)	// dummy
		{
			return true;
		}

		public override int GetHashCode()		// dummy
		{
			return 0;
		}
	}

	public class MultiFD
	{
		public MultiFD()	// constructor logic
		// initialize Multiple-precision floating decimal package
		// input: MultiID.muDMax, MultiID.muNMax, MultiID.baseM
		{
			int i;
			fRound = MultiID.baseM / 2;						// set floating point rounding constant to round
			Calc.fMC = 2 + 23 / MultiID.muDMax;				// set for at least 25 decimal digits
			fTn = 1;										// set to truncate 1 super digits in display
			writeExtra = true;								// set (aa) [bb] to be written with number
			MultiID.maxDis = Common.nMax * MultiID.muDMax;	// set max digits to display to max
			scieN = false;
			expanded = false;
			fGuard = 4;						// needed for ValueF, may be changed
			fMOne = new MultiF(1);
			SetTo1F(-1, fMOne);				// fMOne = -1.0, minus works in SetTo1F
			fMHalf = new MultiF(1);
			ValueF("-0.5", out i, fMHalf);	// fHalf = -0.5
			fP25 = new MultiF(1);
			fZero = new MultiF(1);			// fZero =  0.0, zero is default value
			ValueF("0.25", out i, fP25);	// fP75  =  0.25
			fHalf = new MultiF(1);
			ValueF("0.5", out i, fHalf);	// fHalf =  0.5
			fP25 = new MultiF(1);
			ValueF("0.25", out i, fP25);	// fP25  =  0.25
			fP75 = new MultiF(1);
			ValueF("0.75", out i, fP75);	// fP75  =  0.75
			fOne = new MultiF(1);
			fOne.V[0] = 1;					// fOne  =  1.0, direct method
			f1P5 = new MultiF(2);
			ValueF("1.5", out i, f1P5);		// f1P5  =  1.5, ValueF function method
			fTwo = new MultiF(1);
			SetTo1F(2, fTwo);				// fTwo  =  2.0
			fThree = new MultiF(1);
			SetTo1F(3, fThree);				// fThree =  3.0
			fFour = new MultiF(1);
			SetTo1F(4, fFour);				// fFour  =  4.0
			fFive = new MultiF(1);
			SetTo1F(5, fFive);				// fFive  =  5.0
			fSix = new MultiF(1);
			SetTo1F(6, fSix);				// fSix   =  6.0
		}

		public static void DoneF(MultiF z) // free up space
		{
			MultiID.DoneSI(z);
			z.C = 0;
		}

		public static void ReSizeF(int m, MultiF z) // change M and set to zero
		{
			MultiID.ReSizeSI(m, z);
			z.C = 0;
		}

		public static void ClearF(MultiF z)	// set Value = 0
		{
			MultiID.ClearSI(z);
			z.C = 0;
		}

		public static void ChSF(MultiF z) // change sign, z = - z
		{
			if (!MultiID.ZTestSI(z)) z.S = !z.S;
		}

		public static void SetToF(MultiF x, MultiF z)	// z = x
		// can reduce precision and round
		{
		int i;
		int j;
		int k;
		decimal de;
		bool roundIt;
		if (Object.ReferenceEquals(x, z))
		{
			NormF(z);
			return;
		}
		k = z.M;
		if (k > Calc.fMC) k = Calc.fMC; // Min
		if (k >= x.N)
		{
			MultiID.SetToSI(x, z);
			z.C = x.C;
			return;
		}
		z.N = k;
		z.S = x.S;
		j = x.N - k;
		for (i = 0; i < k; i++)
		{
			z.V[i] = x.V[i + j];
		}
		de = x.C;
		de += j;
		if (de > Int64.MaxValue)
		{
			ClearF(z);
			MultiID.MuWriteErr("Floating SetTo overflow, continuing...");
		}
		else
		{
			z.C = x.C + j;
			if (fRound > 0)
			{
				if (x.V[j-1] >= fRound)
				{
					roundIt = true;
					if (x.V[j-1] == fRound && j == 1)
					{
						if ((x.V[j] & 1) == 0)				// !Odd(iL)
						{
							roundIt = false;
						}
					}
					if (roundIt)
					{
						MultiF t = new MultiF(1);
						t.V[0] = 1;
						t.S = z.S;
						t.C = z.C;
						RAddF(t, z);
						DoneF(t);
						return;
					}
				}
			}
			NormF(z);
		}
		} // SetToF

		public static void SetToSIF(MultiSI x, MultiF z) // z = x
		// can reduce precision and round
		{
			if (x.N <= z.M)
			{
				MultiID.SetToSI(x, z);	// this is an SI assignment
				z.C = 0;
				NormF(z);
				return;
			}
			int d = x.N - z.M;
			z.C = d;
			z.N = z.M;
			z.S = x.S;
			for (int i = 0; i < z.M; i++)
				z.V[i] = x.V[i+d];
			if (fRound > 0 && x.V[d-1] >= fRound)
			{
				bool roundIt = true;
				if (x.V[d-1] == fRound)
				{
					if ((z.V[0] & 1) == 0) // !Odd(iL)
					{
							roundIt = false;
					}
				}
				if (roundIt)
				{
					MultiF t = new MultiF(1); // temp
					t.V[0] = 1;
					t.S = z.S;
					t.C = z.C;
					RAddF(t, z);
					DoneF(t);
				}				
			}
			NormF(z);
		}

		public static void SetToFS(MultiF x, MultiF z) // z = x, same size
		// copy everything but .Nm Name
		{
			MultiID.SetToSIS(x, z);
			z.C = x.C;
		}

		public static void NormF(MultiF z) // normalize
		{
			int i;
			int j;
			decimal de;
			int saveFR;
			int saveFMC;
			bool roundIt;
			MultiID.NormSI(z);	// NormSI prevents -0
			if (ZTestF(z))
			{
				z.C = 0;
				return;
			}
			i = 0;
			if (z.N > Calc.fMC)
			{
				i = z.N - Calc.fMC;
				de = z.C;
				de += i;
				if (de > Int64.MaxValue)
				{
					MultiID.MuWriteErr("Floating Norm overflow, continuing...");
					ClearF(z);
					return;
				}
				if (fRound > 0 && z.V[i-1] >= fRound)
				{
					roundIt = true;
					if (z.V[i-1] == fRound)
					{
						if ((z.V[i] & 1) == 0)		// !Odd(iL)
						{
							roundIt = false;
							j = i - 2;
							while (j >= 0)
							{
								if (z.V[j] != 0)
								{
									j = 0;
									roundIt = true;
								}
								j--;
							}
						}
					}
					if (roundIt)
					{
						saveFR = fRound;
						fRound = 0;
						saveFMC = Calc.fMC;
						Calc.fMC = z.M;
						MultiF t = new MultiF(1);
						t.V[0] = 1;
						t.S = z.S;
						t.C = z.C + i;
						if (z.V[0] == 0)
							z.V[0] = 1;	// prevent Normalizing early
						RAddF(t, z);
						DoneF(t);
						fRound = saveFR;
						Calc.fMC = saveFMC;
					}
				}
				z.N -= i;
				z.C += i;
			}
			while (z.V[i] == 0)
			{
				i++; // i = # of trailing zero super digits
				z.N--;
				de = z.C;
				de++;
				if (de > Int64.MaxValue)
				{
					MultiID.MuWriteErr("Floating Norm overflow, continuing...");
					ClearF(z);
					return;
				}
				z.C++;
			}
			if (i > 0)
			{
				for (j = 0; j < z.N; j++)
				{
					z.V[j] = z.V[i];
					i++;
				}
			}
		} // NormF

		public static void ShiftR(long r, MultiF z) // z = z, r "digits" lost, un-normalized
		// r < 0 => Shift left, Sets muErr true if underflow
		{
			int i;
			if (r == 0) return;
			if (r < 0)
			{
				ShiftL(-r, z);
				return;
			}
			if (r >= z.N)
			{
				ClearF(z);
				return;
			}
			if (r > Int32.MaxValue) r = Int32.MaxValue;
			if (r < Int32.MinValue) r = Int32.MinValue;
			int ri = (int) r;
			if ( fRound > 0 && (z.V[ri] == 0 || z.V[ri] == fRound) )
			{
				i = 0;
				while (i < ri)
				{
					if (z.V[i] != 0)
					{
						i = ri;
						z.V[ri]++; // add sticky bit to meet IEEE standard
					}
					i++;
				}
			}
			for (i = ri; i < z.N; i++)
			{
				z.V[i - ri] = z.V[i];
			}
			z.N -= ri;
			if (z.C > (Int64.MaxValue - r))
			{
				ClearF(z);
				MultiID.MuWriteErr("Floating shift right underflow, continuing...");
				MultiID.muUnderflow = true;
			}
			else
			{
				z.C += r;
			}
		} // ShiftR

		public static void ShiftL(long iL, MultiF z) // z = z, iL "digits" more, un-normalized
		// r < 0 => Shift right, 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("Floating shift left overflow, continuing...");
				ClearF(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;
			if (z.C < (iL - Int64.MaxValue))
			{
				ClearF(z);
			}
			else
			{
				z.C -= iL;
			}
		} // ShiftL

		public static void RAddF(MultiF x, MultiF z) // z = z + x
		// sets muErr true if overflow
		{
			AddF(z, x, z);
		}

		public static void RSubF(MultiF x, MultiF z) // z = z - x
		// sets muErr true if overflow
		{
			if (Object.ReferenceEquals(x, z))
			{
				ClearF(z);
			}
			else
			{
				ChSF(x);
				RAddF(x, z);
				ChSF(x);
			}
		}

		public static void AddF(MultiF x, MultiF y, MultiF z) // z = x + y
		// sets muErr true if overflow
		{
			decimal xF; // length of mantissa
			decimal yF;
			int maxS;
			bool xBig;
			if (ZTestF(x))
			{
				SetToF(y, z);
				return;
			}
			if (ZTestF(y))
			{
				SetToF(x, z);
				return;
			}
			xF = (decimal)x.C + x.N;
			yF = (decimal)y.C + y.N;
			xBig = (xF >= yF);
			if (!xBig)
			{
				xF = (decimal)y.C + y.N;
				yF = (decimal)x.C + x.N;
			}
			if (xF - yF - 3 >= z.M)
			{
				if (xBig)
				{
					SetToF(x, z);
				}
				else
				{
					SetToF(y, z);
				}
			}
			else
			{
				xF -= Math.Min(x.C, y.C);
				maxS = Math.Min((int)xF, z.M) + fGuard;	// n guard "digits"
				MultiF xT = new MultiF(maxS);
				MultiF yT = new MultiF(maxS);
				if (xBig)
				{
					SetToF(x, xT);
					SetToF(y, yT);
				}
				else
				{
					SetToF(y, xT);
					SetToF(x, yT);
				}
				ShiftL(xT.M - xT.N - 1, xT);
				ShiftR(xT.C - yT.C, yT);
				MultiID.RAddSI(yT, xT);
				DoneF(yT);
				NormF(xT);
				SetToF(xT, z);
				DoneF(xT);
			}
		} // AddF

		public static void SubF(MultiF x, MultiF y, MultiF z) // z = x - y
		// sets muErr true if overflow
		{
			if (Object.ReferenceEquals(x, y))
				ClearF(z);
			else if (Object.ReferenceEquals(x, z))
				RSubF(y, z);
			else if (Object.ReferenceEquals(y, z))
			{
				RSubF(x, z);
					ChSF(z);
			}
			else
			{
				ChSF(y);
				AddF(x, y, z);
				ChSF(y);
			}
		}

		public static void ValueF10(string st, out int i, MultiF z)
		// 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;
			ValueF(st, out i, z);
			MultiID.baseI = saveBaseI;
		}

		public static void ValueF(string st, out int i, MultiF z)
		// convert String to z, returns i = # of character used
		// allows st to be a literal, muErr set true if overflow
		{
			int j;
			int k;
			int iL;
			int d1;
			decimal ee;
			decimal dI;
			bool sign;
			bool expB;
			char st1;
			char st2;
			char st3;
			int baseS;
			string maxD; // max Input digit "1" to "Z"
			maxD = MultiID.MaxDig(MultiID.baseI);
			sign = (st[0] == '-');
			MultiID.ValueSI(st, out j, z);
			i = j;
			z.C = 0;
			NormF(z);
			MultiID.Delete(ref st, 0, j);
			if (st.Length == 1 && st[0] == '.')
			{
				i++;
				MultiID.Delete(ref st, 0, 1); // delete final "."
			}
			if (st.Length < 2) return;
			MultiF x = new MultiF();	// temp
			MultiF bF = new MultiF(1);	// baseI as a MultiF
			st1 = st[0];
			st2 = Char.ToUpper(st[1]);
			if (st1 == '.' && st2 >= '0' && st2 <= maxD[0] && (st2 <= '9' || st2 >= 'A'))
			{
				MultiID.Delete(ref st, 0, 1);
				if (MultiID.baseI == 10)
				{
					ReSizeF(1 + st.Length / MultiID.muDMax, x);
				}
				else
				{
					j = (int)Math.Max(2 + (st.Length * Math.Log10(MultiID.baseI)) / MultiID.muDMax, Calc.fMC);
					ReSizeF(j, x);
				}
				MultiID.ValueSI(st, out j, x);
				i += j + 1;
				k = 0;
				for (iL = 1; iL <= j; iL++)
				{
					st1 = st[iL-1];
					if (st1 != ',') k++;
				}
				if (MultiID.baseI == 10)
				{
					x.C = -(long)((k - 1) / MultiID.muDMax) - 1;
					k = MultiID.muDMax - ((k - 1) % MultiID.muDMax) - 1;
					d1 = 1;
					for (iL = 1; iL <= k; iL++)
						d1 *= 10;
					MultiID.RMul1SI(d1, x);
					DoneF(bF);
				}
				else
				{
					x.C = 0;
					SetTo1F(MultiID.baseI, bF);
					MultiF kF = new MultiF(1);
					SetTo1F(k, kF);
					MultiF y = new MultiF(1);
					XPCalLst.PowNF(bF, kF, y); // y=baseI^k
					RDivF(y, x);
					DoneF(y);
					DoneF(kF);
					DoneF(bF);
				}
				x.S = sign;
				RAddF(x, z);
				MultiID.Delete(ref st, 0, j);
				DoneF(x);
			}
			else
			{
				if (st.Length > 0 && st[0] == '.')
				{
					i++;
					MultiID.Delete(ref st, 0, 1); // delete final "."
				}
			}
			if (st.Length < 2) return;
			st1 = st[0];
			st2 = st[1];
			st3 = ' ';
			if (st.Length > 2) st3 = st[2];
			expB = false;
			if (st1 == 'E' || st1 == 'e' || st1 == '`')
			{
				if (st2 >= '0' && st2 <= '9')
					expB = true;
				else if (st2 == '+' || st2 == '-')
				{
					if (st3 >= '0' && st3 <= '9') expB = true;
				}
			}
			if (expB)
			{
				MultiID.Delete(ref st, 0, 1);
				ReSizeF(1 + st.Length / MultiID.muDMax, x);
				baseS = MultiID.baseI;
				MultiID.baseI = 10;
				MultiID.ValueSI(st, out j, x); // exponent is always in decimal, but can have commas
				MultiID.baseI = baseS;
				i += j + 1;
				if (MultiID.baseI == 10)
				{
					MultiID.GetDeSI(out ee, x);
					DoneF(x);
					dI = Decimal.Floor(ee / MultiID.muDMax);
					decimal de = dI;
					de += z.C;
					if (de > Int64.MaxValue)
					{
						MultiID.MuWriteErr("Floating Value overflow, continuing...");
						ClearF(z);
						return;
					}
					if (de < -Int64.MaxValue)
					{
						ClearF(z);
						MultiID.MuWriteErr("Floating value underflow, continuing...");
						MultiID.muUnderflow = true;
						return;
					}
					z.C = (long)de;
					int kk = (int)(ee - dI * MultiID.muDMax);
					d1 = 1;
					for (iL = 1; iL <= kk; iL++)
						d1 *= 10;
					RMul1F(d1, z);
				}
				else
				{
					SetTo1F(MultiID.baseI, bF);
					MultiF y = new MultiF(1);
					XPCalLst.PowNF(bF, x, y);	// y=baseI^x
					RMulF(y, z);
					DoneF(y);
					DoneF(bF);
					DoneF(x);
				}
			}
			NormF(z);
		} // ValueF

		public static bool aDigit(string st, string maxD)	// true if ch is a digit <= maxD
		{
			char ch;
			ch = Char.ToUpper(st[0]);
			return (ch >= '0' && ch <= maxD[0] && (ch <= '9' || ch >= 'A'));
		}

		public static void SetTo1F(int d1, MultiF z)	// z = d1
		// allows a literal d1, d1 an integer, d1 not changed
		{
			MultiID.SetTo1SI(d1, z);
			z.C = 0;
			NormF(z);
		}

		public static void SetToExF(Int64 ext, MultiF z)	// z = ext (Int64 = long)
		// allows a literal ext, ext not changed, max Int64 = 9223,37203,68547,75807 = 2^63-1
		{
			MultiID.SetToExSI(ext, z);
			z.C = 0;
			NormF(z);
		}

		public static void SetToDbF(double db, MultiF z) // z = db % baseM^4
		// allows a literal db, db not changed, muErr set true if overflow
		{
			MultiID.SetToDbSI(db, z);
			z.C = 0;
			NormF(z);
		}

		public static void SetToDbA(double db, MultiF z) // z = db integer and fraction
		// allows a literal db, db not changed, muErr set true if overflow
		{
			int i;
			ValueF10(db.ToString("E17"), out i, z);
		}

		public static void SetToDeF(decimal de, MultiF z) // z = db
		// allows a literal de, de not changed, muErr set true if overflow
		{
			MultiID.SetToDeSI(de, z);
			z.C = 0;
			NormF(z);
		}

		public static void Get1F(out int d1, MultiF z) // d1 = z % baseM
		// z is not changed
		{
			bool saveB;
			saveB = MultiID.muErrRep;
			MultiID.muErrRep = false;	// suppress error messages
			MultiF x = new MultiF(5);
			SetToF(z, x);
			if (x.C > 4)
			{
				MultiID.muErrRep = saveB;
				ClearF(x);			// HJS 1992-11-28
				MultiID.MuWriteErr("Get1 overflow, continuing...");
			}
			else
			{
				ShiftL(x.C, x);
			}
			MultiID.Get1SI(out d1, x);
			DoneF(x);
			MultiID.muErrRep = saveB;
		}

		public static void GetLgF(out long n, MultiF z)	// n = z
		// z is not changed
		// max long is 2^63-1 = 9223,37203,68547,75807 (19 Digits)
		{
			decimal de;
			GetDeF(out de, z);
			if (Math.Abs(de) > Int64.MaxValue)
			{
				de = 0;
				MultiID.MuWriteErr("GetLg overflow, continuing...");
			}
			n = (long)de;			
		}

		public static void GetDeF(out decimal ext, MultiF z)	// ext = z
		// z is not changed
		// max integer decimal is 2^96-1 = 7922,81625,14264,33759,35439,50335 29 digits
		{
			int d = 1 + (28 / MultiID.muDMax);	// d = max super digits in a decimal type
			MultiF x = new MultiF(d);
			decimal max = decimal.MaxValue;
			decimal min = decimal.MinValue;
			x &= max;
			if (z > x)
			{
				ext = max;
				MultiID.MuWriteErr("GetD overflow, continuing...");
				return;
			}
			x &= min;
			if (z < x)
			{
				ext = min;
				MultiID.MuWriteErr("GetD underflow, continuing...");
				return;
			}
			SetToF(z, x);
			ShiftL(x.C, x);
			MultiID.GetDeSI(out ext, x);
		}

		public static void GetDbF(out double db, MultiF z)	// db = IntegerPart(z) % baseM^4
		// z is not changed, 2^53-1 = 9,00719,92547,40991 16 digits
		{
			bool saveB;
			saveB = MultiID.muErrRep;
			MultiID.muErrRep = false;	// suppress error messages
			MultiF x = new MultiF(5);
			SetToF(z, x);
			if (x.C >= 5)
			{
				MultiID.muErrRep = saveB;
				ClearF(x);
				MultiID.MuWriteErr("GetD overflow, continuing...");
			}
			else
			{
				ShiftL(x.C, x);
			}
			MultiID.GetDbSI(out db, x);
			DoneF(x);
			MultiID.muErrRep = saveB;
		}

		public static void GetDbA(out double db, MultiF z)	// db = IntegerPart(z) + FractionPart(z)
		// z is not changed
		{
			int iMin = z.N - 4;				// use at most 4 super-digits
			if (iMin < 0) iMin = 0;
			db = 0;
			for (int i = z.N - 1; i >= 0; i--)
			{
				db += z.V[i] * Math.Pow(MultiID.baseM, i + z.C);
			}
			if (z.S) db = -db;
		}

		public static void GetDbInF(out double db, double low, double high, MultiF z)
		// db = z % baseM^4, in a range, + or -
		{
			long i = z.N + z.C;
			if (i >= 5)
			{
				if (z.S)
				{
					db = low;
				}
				else
				{
					db = high;
				}
				return;
			}
			GetDbF(out db, z);
			if (db < low) db = low;
			if (db > high) db = high;
		}

		public static void RAdd1F(int d1, MultiF z) // z = z + d1
		// allows literal d1, d1 is not changed, sets muErr true if overflow
		{
			MultiF x = new MultiF(2);
			SetTo1F(d1, x);
			RAddF(x, z);
			DoneF(x);
		}

		public static void RSub1F(int d1, MultiF z) // z = z - d1
		// allows literal d1, d1 is not changed, sets muErr true if overflow
		{
			MultiF x = new MultiF(2);
			SetTo1F(d1, x);
			RSubF(x, z);
			DoneF(x);
		}

		public static void Add1F(MultiF x, int d1, MultiF z) // z = x + d1
		// allows literal d1, d1 is not changed, sets muErr true if overflow
		{
			SetToF(x, z);
			RAdd1F(d1, z);
		}

		public static int SignF(MultiF z) // sign(z) = -1 if z < 0, 0 if z = 0, +1 if z > 0
		// z.S and x.S used but not changed  z not changed
		{
			if (ZTestF(z))
				return 0;
			else if (z.S)
				return -1;
			else
				return 1;
		}

		public static int CompFF(MultiF x, MultiF z) // CompFF = sign(z - x)
		// sign = -1 if z < x, sign = 0 if z = x, sign = +1 if z > x
		// z.S and x.S used but not changed  z, x not changed
		{
			int iCompFF;
			MultiF dif = new MultiF(1 + Math.Max(z.N, x.N));
			SubF(z, x, dif);
			iCompFF = SignF(dif);
			DoneF(dif);
			return iCompFF;
		}

		public static void WriteFixedL(RichTextBox outB, StreamWriter outF, MultiF z, ref int tot, int width)
		// Write Fixed Long
		{
			int i;
			string st;
			string stL = "";
			bool started = false;
			bool point = false;
			if (width == 0) width = 80;
			if (z == 0)
			{
				MultiID.WriteT(outB, outF, "0.0", ref tot, width);
				return;
			}
			MultiF t = new MultiF(1); // temp
			if (width == 0) width = 80;
			int trunc = Math.Max(Calc.fMC - (MultiID.maxDis + 12) / MultiID.muDMax, fTn); // trunc not in DOS VPCalc
			trunc = Math.Min(trunc, Calc.fMC - 2);
			if (trunc > 0 && z.N > Calc.fMC - trunc)
			{
				ReSizeF(Calc.fMC - trunc, t);
				SetToF(z, t);	// keeps size of t fixed, reduces precision and rounds
			}
			else
			{
				SetToFS(z, t);	// expands size of t (t Same as z)
			}
			long did = MultiID.muDpG - (t.N + t.C) * MultiID.muDMax;
			if (t.S) MultiID.WriteT(outB, outF, "-", ref tot, width);
			if (t.N + t.C <= 0)
			{
				MultiID.WriteT(outB, outF, "0.", ref tot, width);
				did = 0;
				started = true;
				point = true;
				for (i = 1; i <= -(t.N + t.C); i++)		// do zeros before digits
				{
					MultiID.MuInterrupt();	// allow for abort
					if (MultiID.muAbort)
					{
						DoneF(t);
						return;
					}
					st = "";
					for (int d = 1; d <= MultiID.muDMax; d++)
					{
						did++;
						st += "0";
						if (MultiID.muDpG > 0 && (did % MultiID.muDpG) == 0)
							st += ",";
					}
					stL += st;
					if ( stL.Length >= (width - (tot % width)) )			// built for speed:
					{
						MultiID.WriteT(outB, outF, stL, ref tot, width);	// don't call WriteT too often
						stL = "";											// and call at a line break so
					}														// Write is called less
				}
			}
			for (i = t.N-1; i >= 0; i--)		// do digits
			{
				int digit;
				int digits = t.V[i];
				int div = MultiID.baseM;
				MultiID.MuInterrupt();	// allow for abort
				st = "";
				for (int d = 1; d <= MultiID.muDMax; d++)
				{
					did++;
					div /= 10;
					digit = Math.DivRem(digits, div, out digits);
					if (digit != 0 || started)
					{
						started = true;
						st += digit.ToString();
						if ((i == 0 && digits == 0 && point) || MultiID.muAbort)
						{
							stL += st;
							MultiID.WriteT(outB, outF, stL, ref tot, width);
							DoneF(t);
							return;
						}
						if (MultiID.muDpG > 0 && (did % MultiID.muDpG) == 0 && !(i == -t.C && d == MultiID.muDMax))
							st += ",";
					}
				}
				stL += st;
				if ( stL.Length >= (width - (tot % width)) )			// built for speed:
				{
					MultiID.WriteT(outB, outF, stL, ref tot, width);	// don't call WriteT too often
					stL = "";											// and call at a line break so
				}														// Write is called less
				if (i == -t.C)
				{
					stL += ".";
					point = true;
					if (i == 0)
						stL += "0";
				}
			}
			MultiID.WriteT(outB, outF, stL, ref tot, width);
			stL = "";
			if (point)
			{
				MultiID.WriteT(outB, outF, stL, ref tot, width);
				stL = "";
				DoneF(t);
				return;
			}
			for (long j = t.C; j > 0; j--)		// do zeros after digits
			{
				MultiID.MuInterrupt();	// allow for abort
				if (MultiID.muAbort)
				{
					DoneF(t);
					return;
				}
				st = "";
				for (int d = 1; d <= MultiID.muDMax; d++)
				{
					did++;
					st += "0";
					if (MultiID.muDpG > 0 && (did % MultiID.muDpG) == 0 && !(j == 1 && d == MultiID.muDMax))
						st += ",";
				}
				stL += st;
				if ( stL.Length >= (width - (tot % width)) )			// built for speed:
				{
					MultiID.WriteT(outB, outF, stL, ref tot, width);	// don't call WriteT too often
					stL = "";											// and call at a line break so
				}														// Write is called less
			}
			stL += ".0";
			MultiID.WriteT(outB, outF, stL, ref tot, width);
			stL = "";
			DoneF(t);
		} // WriteFixedL

		public static void WriteFixed(RichTextBox outB, StreamWriter outF, MultiF z, ref int tot, int width)
		{
			int j;
			int k;
			int didZ;
			string st;
			int did = 0;
			if (z.S) MultiID.WriteT(outB, outF, "-", ref tot, width);
			if (z.N + z.C > 0)
			{
				st = ((int)(MultiID.baseM + z.V[z.N-1])).ToString();
				j = 1;
				do
					j++;
				while (st[j-1] == '0' && j != MultiID.muDMax + 1);
				did = j - 2 - MultiID.muDMax;
				if (z.N + z.C > 1) did -= MultiID.muDMax;
				if (MultiID.muDpG > 0) did = did % MultiID.muDpG;
				if (did < 0) did += MultiID.muDpG;
				didZ = did;
				k = MultiID.muDMax + 1;
				j--;
				Write1F(st, ref j, k, ref did, didZ, outB, outF, ref tot, width);
				if (z.N + z.C > 1)
				{
					if (z.N > 1)
						st = ((int)(MultiID.baseM + z.V[z.N-2])).ToString();
					else
					{
						st = ((int)(MultiID.baseM)).ToString();
					}
					k = MultiID.muDMax + 1;
					j = 1;
					Write1F(st, ref j, k, ref did, didZ, outB, outF, ref tot, width);
				}
			}
			else
			{
				MultiID.WriteT(outB, outF, "0", ref tot, width);
			}
			MultiID.WriteT(outB, outF, ".", ref tot, width);
			didZ = did;
			if (-z.C == 2)
			{
				st = ((int)(MultiID.baseM + z.V[1])).ToString();
				k = MultiID.muDMax + 1;
				j = 1;
				Write1F(st, ref j, k, ref did, didZ, outB, outF, ref tot, width);
			}
			if (-z.C > 0)
			{
				st = ((int)(MultiID.baseM + z.V[0])).ToString();
				j = MultiID.muDMax + 2;
				do
					j--;
				while (st[j-1] == '0');
				k = j;
				j = 1;
				Write1F(st, ref j, k, ref did, didZ, outB, outF, ref tot, width);
			}
			else
			{
				MultiID.WriteT(outB, outF, "0", ref tot, width);
			}
			return;
		} // WriteFixed

		private static void Write1F(string st, ref int j, int k, ref int did, int didZ, RichTextBox outB, StreamWriter outF, ref int tot, int width)
		// part of WriteFixed
		{
			while (j < k)
			{
				j++;
				if (did != didZ && MultiID.muDpG > 0)
				{
					if (did % MultiID.muDpG == 0) MultiID.WriteT(outB, outF, ",", ref tot, width);
				}
				MultiID.WriteT(outB, outF, st.Substring(j - 1, 1), ref tot, width);
				did++;
			}
			return;
		}

		public static void WriteF(MultiF z, ref int tot)
		{
			WriteF(MultiID.outS, null, z, ref tot, 0);
		}

		public static void WriteF(RichTextBox outB, StreamWriter outF, MultiF z, ref int tot, int width)
		// output z as a line of text, tot = characters on line so far, z is not modified
		// good for any base = baseO [2, 36], base 10 much faster
		{
			MultiF t = new MultiF(1); // temp
			int zL;
			string ch;
			int i;
			int j;
			int k;
			int did;
			string st;
			bool bFixed;
			int trunc;
			string stL;
			if (width == 0)
			{
				if (outB == null)
					width = 60; // 60 for files
				else
				{
					width = 80; // 80 for screen
				}
			}
			if (ZTestF(z) && outF == null)
			{
				if (MultiID.writeBool) MultiID.WriteT(outB, outF, "0.0 (False)", ref tot, width);
				else MultiID.WriteT(outB, outF, "0.0", ref tot, width);
				return;
			}
			if (z.C == 0 && !z.S && MultiID.EQ1UI(1, z) && outF == null)
			{
				if (MultiID.writeBool) MultiID.WriteT(outB, outF, "1.0 (True) ", ref tot, width);
				else MultiID.WriteT(outB, outF, "1.0", ref tot, width);
				return;
			}
			if (MultiID.baseO != 10)
			{
				XPCalLst.WriteFB(outB, outF, z, ref tot, width);
				return;
			}
			int min = 2;
			bFixed = (!scieN) && (z.C <= min - z.N) && (-z.C <= min);
			if (bFixed)
			{
				WriteFixed(outB, outF, z, ref tot, 0);	// format <= 99999999999999.99999999999999
				return;
			}
			trunc = Math.Max(Calc.fMC - (MultiID.maxDis + 12) / MultiID.muDMax, fTn); // trunc not in DOS VPCalc
			trunc = Math.Min(trunc, Calc.fMC - 2);
			if (trunc > 0 && z.N > Calc.fMC - trunc)
			{
				ReSizeF(Calc.fMC - trunc, t);
				SetToF(z, t);	// keeps size of t fixed, reduces precision and rounds
			}
			else
			{
				SetToFS(z, t);	// expands size of t (t Same as z)
			}
			if (t.S) MultiID.WriteT(outB, outF, "-", ref tot, width);
			st = ((int)(MultiID.baseM + t.V[t.N-1])).ToString();
			j = 1;
			do
				j++;
			while (st[j-1] == '0' && j != MultiID.muDMax + 1);
			MultiID.WriteT(outB, outF, st.Substring(j - 1, 1) + ".", ref tot, width);
			zL = j - 2;
			did = 0;
			k = MultiID.muDMax + 1;
			if (t.N == 1)
			{
				while (st.Substring(k - 1, 1) == "0")
					k--;
			}
			if (j >= k && t.N == 1) MultiID.WriteT(outB, outF, "0", ref tot, width);
			while (j < k)
			{
				j++;
				if (did != 0 && MultiID.muDpG > 0)
				{
					if (did % MultiID.muDpG == 0)
						MultiID.WriteT(outB, outF, ",", ref tot, width);
				}
				MultiID.WriteT(outB, outF, st.Substring(j - 1, 1), ref tot, width);
				did++;
				if (did >= MultiID.maxDis - 1) k = 0;
			}
			if (did < (MultiID.maxDis - 1))
				i = 2;
			else
				i = t.N + 1;
			stL = "";
			while (i <= t.N)
			{
				st = ((int)(MultiID.baseM + t.V[t.N-i])).ToString();
				k = MultiID.muDMax + 1;
				if (i == t.N)
				{
					while (st[k-1] == '0')
						k--;
				}
				j = 2;
				while (j <= k)
				{
					if (did != 0 && MultiID.muDpG > 0)
					{
						if (did % MultiID.muDpG == 0)
						{
							stL = stL + ",";
							if ( stL.Length >= (width - (tot % width)) )
							{
								MultiID.WriteT(outB, outF, stL, ref tot, width);
								stL = "";
							}
						}
					}
					stL = stL + st.Substring(j - 1, 1);
					if ( stL.Length >= (width - (tot % width)) )			// built for speed:
					{
						MultiID.WriteT(outB, outF, stL, ref tot, width);	// don't call WriteT too often
						stL = "";											// and call at a line break so
					}														// Write is called less
					did++;
					if (did >= MultiID.maxDis - 1)
					{
						k = 0;
						i = t.N;
					}
					j++;
				}
				MultiID.MuInterrupt();
				if (MultiID.muAbort) i = t.N;
				i++;
			}
			MultiID.WriteT(outB, outF, stL, ref tot, width);
			decimal dE = t.C;
			dE = MultiID.muDMax * (dE + t.N) - zL - 1;
			if (dE >= 0)
				ch = "+";
			else
				ch = "-";
			if (outB == null) tot = width; // start E on a new line for file
			MultiID.WriteT(outB, outF, "E" + ch, ref tot, width);
			st = (Math.Abs(dE)).ToString();
			k = st.Length;
			if (k > MultiID.muDpG && MultiID.muDpG != 0)
			{
				j = k + 1;
			int iL = (k - 1) / MultiID.muDpG;
				for (i = 1; i <= iL; i++)
				{
					j -= MultiID.muDpG;
					st = st.Substring(0, j - 1) + "," + st.Substring(j - 1);
				}
			}
			MultiID.WriteT(outB, outF, st, ref tot, width);
			if (writeExtra)
			{
				if (did >= MultiID.muLenD)
				{
					st = (did + 1).ToString();
					MultiID.WriteT(outB, outF, " (" + st + ")", ref tot, width);
				}
				i = (z.V[z.N-1]).ToString().Length;
				st = (MultiID.baseM + z.V[0]).ToString();
				while (st[st.Length - 1] == '0') st = st.Remove(st.Length - 1, 1);
				i += st.Length - 1 - MultiID.muDMax;
				st = (i + (z.N - 1) * MultiID.muDMax).ToString();
				MultiID.WriteT(outB, outF, " [" + st + "]", ref tot, width);
			}
			DoneF(t);
		} // WriteF

		public static void WriteFLn(RichTextBox outB, StreamWriter outF, MultiF z, ref int tot)
		// output z as a line of text, tot = characters on line so far
		{
			WriteF(outB, outF, z, ref tot, 0);
			MultiID.Write(outB, outF, "\n");
			tot = 0;
		}

		public static void WriteFLn(MultiF z, ref int tot)
		{
			WriteFLn(MultiID.outS, null, z, ref tot);
		}

		public static void WriteFLn(MultiF z)
		{
			int tot = 0;
			WriteFLn(MultiID.outS, null, z, ref tot);
		}

		public static void RMul1F(int d1, MultiF z) // z = z * d1 (d1 <= maxDigit)
		// Multi-precision one super digit multiply d1 is not changed
		// muErr set true if z overflows
		{
			MultiF zT = new MultiF(z.N + 1);
			zT.C = z.C;
			zT.S = z.S;
			MultiID.Mul1SI(z, d1, zT);
			SetToF(zT, z);
			DoneF(zT);
			NormF(z);
		}

		public static void Mul1F(MultiF x, int d1, MultiF z) // z = x * d1 (d1 <= maxDigit)
		// Multi-precision one super digit multiply x and d1 are not changed
		// muErr set true if z overflows
		{
			SetToF(x, z);
			RMul1F(d1, z);
		}

		public static void MulF(MultiF x, MultiF y, MultiF z) // z = x * y
		// x or y or both may have the same address in memory as z
		// x, y are not changed unless they share memory with z
		// sets muErr true if overflow
		{
			bool slow;
			double t1, t2;
			int n, ldn;
			if (!MultiID.allowFHT)
				slow = true;
			else if (MultiID.forceFHT)
				slow = false;
			else
			{
				int xN = x.N;
				int yN = y.N;
				t1 = xN * (double)yN;	// t1 proportional to runtime of normal multiply
				if (t1 < 3387.25 || xN <= 2 || yN <= 2) // 3387.25 = 58.2^2
					slow = true;
				else
				{
					XIMult.FHTnLdn(xN, yN, out n, out ldn);	// compute n for FHT
					n /= 2;
					t2 = 9.0 * n * (ldn-1);					// t2 proportional to runtime of FHT multiply
					// the 9.0 above is a heuristic that causes a crossover at about xN = 58.2 if xN = yN
					// or about 232.5 decimal digits
					slow = (t1 < t2);						// t1 smaller so do normal multiply
				}
			}
			if (slow)
				MulSlowF(x, y, z);
			else
				MulFastF(x, y, z);
		}

		public static void MulFastF(MultiF x, MultiF y, MultiF z) // z = x * y
		// x or y or both may have the same address in memory as z
		// x, y are not changed unless they share memory with z
		// sets muErr true if overflow
		{
			decimal cDe = (decimal)x.C + y.C;
			int saveMMax = MultiID.mMax;
			MultiID.mMax = x.N + y.N;
			MultiF t = new MultiF(x.N + y.N);	// need large Temp to prevent integer value overflow
			XIMult.XIMul(x, y, t);				// do a FHT multiply
			t.S = x.S ^ y.S;					// compute sign
			SetToF(t, z);						// reduce precision of t to z
			MultiID.mMax = saveMMax;
			DoneF(t);
			NormF(z);
			cDe += z.C;							// compute final characteristic
			if (cDe > Int64.MaxValue)
			{
				ClearF(z);
				MultiID.MuWriteErr("Floating multiply overflow, continuing...");
			}
			else if (cDe < -Int64.MaxValue) // 2008-09-07
			{
				ClearF(z);
				MultiID.MuWriteErr("Floating multiply underflow, continuing...");
				MultiID.muUnderflow = true;
			}
			else
				z.C = (long)cDe;
		}

		public static void MulSlowF(MultiF x, MultiF y, MultiF z) // z = x * y
		// x or y or both may have the same address in memory as z
		// x, y are not changed unless they share memory with z
		// sets muErr true if overflow
		{
			double timeAtStart = MultiID.TimerF();
			int xN = x.N;
			int yN = y.N;
			int mM;
			int i;
			int j;
			int ii;
			int iJ = 0;		// = 0 to prevent "Use of unassigned local variable 'iJ' build error
			int k = 0;		// = 0 same reason for 'k'
			int bias;
			long t;
			MultiF xL = new MultiF(1);	// local pointer to x (or y) so xL.N >= yL.N
			MultiF yL = new MultiF(1);	// local pointer to y (or x) // HJS 1992-11-28
			if (x.N >= y.N)
			{
				SetToFS(x, xL);
				SetToFS(y, yL);
			}
			else
			{
				SetToFS(y, xL);
				SetToFS(x, yL);
			}
			i = 1;
			if (!expanded) i = fGuard;	// n guard "digits", no sticky bit
			mM = Math.Min(xL.N + yL.N, z.M + i);
			mM = Math.Min(mM, Calc.fMC + i);
			mM = Math.Min(mM, MultiID.muNMax);
			MultiF zT = new MultiF(mM);
			zT.S = xL.S ^ yL.S;	// ^ as Logical Xor
			bias = xL.N + yL.N - zT.M;
			if (bias < 0) bias = 0;
			// for (i = 0; i < (xL.N - bias); i++)
			// {
			//		zT.V[i] = 0; // clear lower of zT, not needed in Visual Basic or C#
			// }
			for (j = 0; j < yL.N; j++)
			{
				ii = bias - j;
				if (ii < 0) ii = 0;
				iJ = ii + j - bias;
				k = 0;
				for (i = ii; i < xL.N; i++) // Mult, add and carry next Digit
				{
					t = Math.BigMul(xL.V[i], yL.V[j]) + zT.V[iJ] + k;
					k = (int)(t / MultiID.baseML);
					zT.V[iJ] = (int)(t - Math.BigMul(k, MultiID.baseM));
					iJ++;
				}
				zT.V[iJ] = k;
				MultiID.MuInterrupt();
				if (MultiID.muAbort || MultiID.muErr)
				{
					DoneF(zT);
					ClearF(z);
					return;
				}
				if (MultiID.statReq)
				{
					MultiID.WriteLn("Floating Multiply: " +
						Math.Floor(100.0 * (j + 1) / yL.N) + " Percent done");
					MultiID.statReq = false;
				}
			}
			zT.N = iJ;
			if (k != 0) zT.N++;
			decimal de = xL.C;
			de += yL.C;
			de += bias;
			if (de > Int64.MaxValue)
			{
				ClearF(zT);		// HJS 1992-11-28
				MultiID.MuWriteErr("Floating multiply overflow, continuing...");
			}
			else if (de < -Int64.MaxValue) // 2008-09-07
			{
				ClearF(zT);	// HJS 1992-11-28 // underflow
				MultiID.MuWriteErr("Floating multiply underflow, continuing...");
				MultiID.muUnderflow = true;
			}
			else
				zT.C = (long)de;
			SetToF(zT, z);
			NormF(z);
			DoneF(zT);
			DoneF(yL);
			DoneF(xL);
//if (MultiID.diagOn)
//{
//		double delta = MultiID.TimerF() - timeAtStart;
//		if (delta > 0.025)
//		{
//				string st = string.Format("Normal multiply, baseM = {0}  DT = {1:0.00} sec.  ", MultiID.baseM, delta);
//				st += string.Format("x.N = {0}  y.N = {1}  z.N = {2})", xN, yN, z.N);
//				MultiID.WriteTDLn(st);
//		}
//}
		} // MulSlowF

		public static void RMulF(MultiF x, MultiF z) // z = z * x
		// 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
		{
			MulF(z, x, z);
		}

		public static void SqF(MultiF x, MultiF z) // z = x * x
		// 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
		{
			MulF(x, x, z);
		}

		public static void RSqF(MultiF z) // z = z * z
		// sets muErr true if overflow
		{
			MulF(z, z, z);
		}

		public static void RDiv1F(int d1, MultiF z) // z = z / d1 (d1 <= maxDigit)
		// Multi-precision one super digit divide, d1 is not changed
		// allows literal d1, muErr set true if d1 = 0
		{
			MultiF x = new MultiF(2); // temp
			SetTo1F(d1, x);
			RDivF(x, z);
			DoneF(x);
		}

		public static void Div1F(MultiF u, int d1, MultiF z) // z = u / d1 (d1 <= maxDigit)
		// Multi-precision one super digit divide, d1 and u not changed
		// u and z may have same address in memory, then u is changed
		// allows literal d1, muErr set true if d1 = 0
		{
			SetToF(u, z);
			RDiv1F(d1, z);
		}

		public static void DivF(MultiF u, MultiF d, MultiF z) // z = u / d
		// u or d or both may have the same address in memory as z
		// u, d are not changed unless they share memory with z
		// sets muErr true if d = 0
		{
			if (XPCalLst.DivFast(u, d, z)) return;
			int k;
			k = Math.Min(z.M, Calc.fMC);
			if (!expanded) k += fGuard;			// n guard "digits", no sticky bit
			if (k > MultiID.muNMax) k = MultiID.muNMax;
			MultiF zT = new MultiF(k + d.N);
			if (k + d.N > zT.M) k = zT.M - d.N; // added 2008-09-06		
			SetToF(u, zT);
			ShiftL(k - zT.N + d.N, zT);	// HJS u Changed to zT 2003-12-20
			MultiID.RDivSI(d, zT);
			NormF(zT);
			if (zT.C > 0 && d.C < 0)
			{
				if (zT.C > (Int64.MaxValue + d.C))
				{
					ClearF(zT);
					MultiID.MuWriteErr("Floating divide overflow, continuing...");
				}
				else
				{
					zT.C -= d.C;
				}
			}
			else
			{
				if (zT.C < 0 && d.C > 0)
				{
					if (zT.C < (-Int64.MaxValue + d.C))
						ClearF(zT);
					else
					{
						zT.C -= d.C;
					}
				}
				else
				{
					if (!ZTestF(zT))
					{
						zT.C -= d.C;
					}
				}
			}
			SetToF(zT, z);
			DoneF(zT);
		} // DivF

		public static void RDivF(MultiF d, MultiF z) // z = z / d
		// d may have the same address in memory as z
		// d is not changed unless it shares memory with z
		// sets muErr true if d = 0
		{
			DivF(z, d, z);
		}

		public static void SqRootF(MultiF x, MultiF z) // z = SqRt(x)
		// x is not changed, it is ok for x and this to have the same location in memory
		// but then x will be changed.  Sets muErr True if error
		{
			MultiF g = new MultiF(1);
			g.V = null;
			SqRootF(x, g, 0, z);
		} // SqRootF with no guess

		public static void SqRootF(MultiF x, MultiF g, int plG, MultiF z) // z = SqRt(x)
		// initial guess g, good to plG "super digits" places
		// g and plG are optional, default g.V = null, plG = 0;
		// x is not changed, it is ok for x and this to have the same location in memory
		// but then x will be changed.  Sets muErr True if error
		{
			int sh, saveFMC;
			int mL = 0;
			long zC;
			if (x.S)
				MultiID.MuWriteErr("Cannot take square root of negative number, continuing...");
			if (x.S || ZTestF(x)) { ClearF(z);  return; }
			sh = Math.Min(z.M, Calc.fMC) + 1;
			if (!expanded)  sh += fGuard; // n guard "digits", no sticky bit
			if (sh > MultiID.muNMax)  sh = MultiID.muNMax;

			if (sh > 14) {
				if (!Object.ReferenceEquals(x, z))  { mL = z.M;  ReSizeF(1, z); }
				MultiF xL = new MultiF(1);
				MultiF y = new MultiF(sh);
				MultiF t = new MultiF(sh);
				int ps, pl = 7;
				saveFMC = Calc.fMC;
				if (g.V == null || plG <= 5)
				{
					Calc.fMC = pl+2;
					SqRootF(x, t);	// t ~= SqRt(x)
				}
				else
				{
					pl = plG;
					SetToF(g, t);
				}
				while (pl <= sh)
				{
					pl += pl;
					if (pl > sh)  pl = sh + 1;
					int p;
					for(p = sh + 1; p > pl; p=(p+1)/2)  ;
					pl = p;
					Calc.fMC = pl+2;
					if (x.N > pl+2)
					{
						ps = x.N - (pl+2);
						ReducePrecisionF(ps, x, xL);
						DivF(xL, t, y);
					}
					else
					{
						DivF(x, t, y);
					}
					RSubF(t, y);
					RDiv1F(2, y);
					RAddF(y, t);		// (x/t - t) / 2 + t
				}
				xL.V = null;
				Calc.fMC = saveFMC;
				ReSizeF(1, y);			// y.NMax(0);
				if (!Object.ReferenceEquals(x, z))  ReSizeF(mL, z);
				SetToF(t, z);
			}
			else
			{
				if (((sh - x.N - x.C) & 1) != 0)  sh--; // if odd
				if (!Object.ReferenceEquals(x, z)) { mL = z.M;  ReSizeF(1, z); }
				int FRoundL = fRound;		// Floating point rounding constant, Base/2 or 0
				fRound = 0;					// Prevent x from rounding up to more digits
				MultiF t = new MultiF(sh);
				SetToF(x, t);
				fRound = FRoundL;
				ShiftL(sh - t.N, t);
				t.C /= 2;  zC = t.C;
				MultiID.RSqRtSI(t);  t.C = zC;
				NormF(t);
				if (ZTestF(t))
				{
					if (!Object.ReferenceEquals(x, z)) ReSizeF(mL, z);
					ClearF(z);
				}
				else
				{
					XPCalLst.NormNM(t);
					MultiF y = new MultiF(sh);
					saveFMC = Calc.fMC;
					Calc.fMC = sh;
					DivF(x, t, y);
					RSubF(t, y);
					RDiv1F(2, y);
					RAddF(t, y); // (x/t - t) / 2  + t
					Calc.fMC = saveFMC;
					ReSizeF(1, t);
					if (!Object.ReferenceEquals(x, z))  ReSizeF(mL, z);
					SetToF(y, z);
				}
			}
		} // SqRootF

		public static void RSqRtF(MultiF z) // z = SqRt(z)
		// sets muErr true if error
		{
			SqRootF(z, z);
		}

		public static void IntF(MultiF x, MultiF z) // z = Integer part of x
		{
			int i;
			int j;
			int svFRound;		// save Floating point rounding constant, baseM / 2 or 0
			svFRound = fRound;
			fRound = 0;
			SetToF(x, z);		// this can reduce precision
			if (z.C >= 0)		// if already an integer
			{
				fRound = svFRound;
				return;
			}
			if (-z.C >= z.N)
			{
				fRound = svFRound;
				ClearF(z);
				return;
			}
			long jL = z.C;
			jL = -jL - 1;
			if (jL > Int32.MaxValue) jL = Int32.MaxValue;
			if (jL < Int32.MinValue) jL = Int32.MinValue;
			j = (int)jL;
			for (i = 0; i <= j; i++)
				z.V[i] = 0;
			NormF(z);
			fRound = svFRound;
		}

		public static void RIntF(MultiF z) // z = Integer part of z
		{
			IntF(z, z);
		}

		public static void FracF(MultiF x, MultiF z) // z = Fractional part of x
		{
			int i;
			int j;
			int svFRound; // save Floating point rounding constant, baseM / 2 or 0
			svFRound = fRound;
			fRound = 0;
			SetToF(x, z);
			long jL = z.C;
			if (jL < -Int32.MaxValue) jL = -Int32.MaxValue;
			jL = -jL;
			if (jL < 0) jL = 0;
			j = (int)jL;
			for (i = j; i < z.N; i++)
				z.V[i] = 0;
			NormF(z);
			fRound = svFRound;
		}

		public static void RFracF(MultiF z) // z = Fractional part of z
		{
			FracF(z, z);
		}

		public static void FloorF(MultiF x, MultiF z) // z = integer <= and nearest to x
		{
			SetToF(x, z);
			if (z.C < 0)							// if not an integer already
			{
					bool sign = z.S;
					RIntF(z);						// Floor(2.9) = 2.0
					if (sign) RSubF(fOne, z);		// Floor(-2.1) = -3.0
			}
			NormF(z);
		}

		public static void LopF(MultiF x, MultiF z) // z = x with one less super digit
		{
			bool roundIt;
			SetToF(x, z);
			if (fRound > 0 && z.V[0] >= fRound)
			{
				roundIt = true;
				if (z.V[0] == fRound)
				{
					if ((z.V[1] & 1) == 0) // !Odd(iL)
					{
						roundIt = false;
					}
				}
				if (roundIt)
				{
					MultiF t = new MultiF(2); // temp
					t.V[0] = 0;
					t.V[1] = 1;
					t.N = 2;
					t.S = z.S;
					t.C = z.C;
					z.V[0] = 0;
					RAddF(t, z);
					DoneF(t);
					return;
				}
			}
			z.V[0] = 0;
			NormF(z);
		} // LopF

		public static void RLopF(MultiF z)	// z = z with one less least significant "digit"
		{
			LopF(z, z);
		}

		public static bool ZTestF(MultiF z) // true if z is Zero
		{
			if ((z.N != 1) || (z.V[0] != 0)) return false;
			z.S = false;	// side effect, prevents -0
			return true;
		}

		public static void ReducePrecisionF(int ps, MultiF d, MultiF dL)
		// remove lower ps super digits, d and dL may be the same object
		{

			int j = d.N - ps;
			if (j <= 0)
				ClearF(dL);
			else
			{
				if (dL.M < j) ReSizeF(j, dL);
				for (int i = ps; i < d.N; i++)
					dL.V[i-ps] = d.V[i];	// dL is d at a reduced precision
				dL.N = j;
				dL.C = d.C + ps;
			}
		}

		public static bool expanded;	// true if running in expanded precision
		public static bool scieN;		// force scientific notation on flag
		public static bool writeExtra;	// true if (aa) [bb] to be written with number
		public static int fGuard;		// number of guard super-digits in expanded mode
		public static int fMCB;			// base fMC when running expanded precision
		public static int fRound;		// floating point rounding constant, baseM / 2 or 0
		public static int fTn;			// current # of super digits to truncate display
		public static int mMaxB;		// base MultiID.mMax when running expanded precision
		public static MultiF fMOne;		// fMOne  = -1.0
		public static MultiF fMHalf;	// fMHalf = -0.5
		public static MultiF fZero;		// fZero  =  0.0
		public static MultiF fP25;		// fP25   =  0.25
		public static MultiF fHalf;		// fHalf  =  0.5
		public static MultiF fP75;		// fP75   =  0.75
		public static MultiF fOne;		// fOne   =  1.0
		public static MultiF f1P5;		// f1P5   =  1.5
		public static MultiF fTwo;		// fTwo   =  2.0
		public static MultiF fThree;	// fThree =  3.0
		public static MultiF fFour;		// fFour  =  4.0
		public static MultiF fFive;		// fFive  =  5.0
		public static MultiF fSix;		// fSix   =  6.0
		// Calc.fMC;					// current max # of super digits in a result
	}
}
