/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/Core/Machines/RealType.cs,v $
 * $Revision: 1.7 $
 * $Date: 2002/10/22 19:41:32 $
 */

using System;
using System.Diagnostics;

namespace BC.Core
{
	using Exceptions;

	namespace Machines
	{
		[Serializable]
		public class RealType: MachineType
		{
			public RealType (Type t) :
				base(t)
			{
				double dmax = (double)Convert.ChangeType(Type.GetField("MaxValue").GetValue(null), typeof(double));
				double deps = (double)Convert.ChangeType(Type.GetField("Epsilon").GetValue(null), typeof(double));

				e = (int)(Math.Log(Math.Log(dmax, 2), 2) + 0.5) + 1;

				object nd = 0.0D, d = deps;

				for (m = -2; !nd.Equals(d); ++m)
				{
					nd = Convert.ChangeType((double)Convert.ChangeType(d, typeof(double)) * 2, Type);
					d = Convert.ChangeType((double)Convert.ChangeType(nd, typeof(double)) + deps, Type);
				}
			}

			public RealType () :
				base(typeof(float))
			{
			}

			public override ASTs.AbstractPrimitiveType ASTType
			{
				get
				{
					ASTs.RealType t = new ASTs.RealType();

					t.Precision = Precision;

					return t;
				}
			}

			public override int Precision
			{
				get
				{
					return 1 + ExponentPrecision + MantissaPrecision;
				}
			}

			public int MantissaPrecision
			{
				get
				{
					return m;
				}
			}

			public int ExponentPrecision
			{
				get
				{
					return e;
				}
			}

			public bool Contains (double d)
			{
				object o;

				try
				{
					o = Type.GetMethod("Parse", new Type[] {typeof(string)}).Invoke(null, new object[] {d.ToString()});
				}
				catch
				{
					return false;
				}

				return true;
			}

			protected int m;
			protected int e;

			protected static readonly RealType[] RealTypes =
			{
				new RealType(typeof(Single)),	// float
				new RealType(typeof(Double)),	// double
				new RealType(typeof(Double)),	// long double
			};

			public static RealType Get (string c)
			{
				double d = double.Parse(c);

				foreach (RealType t in RealTypes)
					if (t.Contains(d))
						return t;

				return null;
			}

			public static RealType Get (int p)
			{
				foreach (RealType t in RealTypes)
					if (t.Precision == p)
						return t;

				return null;
			}

			public static RealType Dominator (RealType t1, RealType t2)
			{
				int i1 = Array.IndexOf(RealTypes, t1);
				int i2 = Array.IndexOf(RealTypes, t2);

				Debug.Assert(i1 >= 0 && i2 >= 0);

				return RealTypes[Math.Max(i1, i2)];
			}
		}
	}
}