/// <summary>
        /// Test two numeric values for equality, performing the usual numeric 
        /// conversions and using a provided or default tolerance. If the tolerance 
        /// provided is Empty, this method may set it to a default tolerance.
        /// </summary>
        /// <param name="expected">The expected value</param>
        /// <param name="actual">The actual value</param>
        /// <param name="tolerance">A reference to the tolerance in effect</param>
        /// <returns>True if the values are equal</returns>
		public static bool AreEqual( object expected, object actual, ref Tolerance tolerance )
		{
            if ( expected is double || actual is double )
                return AreEqual( Convert.ToDouble(expected), Convert.ToDouble(actual), ref tolerance );

            if ( expected is float || actual is float )
                return AreEqual( Convert.ToSingle(expected), Convert.ToSingle(actual), ref tolerance );

            if (tolerance.Mode == ToleranceMode.Ulps)
                throw new InvalidOperationException("Ulps may only be specified for floating point arguments");

			if ( expected is decimal || actual is decimal )
				return AreEqual( Convert.ToDecimal(expected), Convert.ToDecimal(actual), tolerance );

            if (expected is ulong || actual is ulong)
                return AreEqual(Convert.ToUInt64(expected), Convert.ToUInt64(actual), tolerance );
		
			if ( expected is long || actual is long )
				return AreEqual( Convert.ToInt64(expected), Convert.ToInt64(actual), tolerance );
			
			if ( expected is uint || actual is uint )
				return AreEqual( Convert.ToUInt32(expected), Convert.ToUInt32(actual), tolerance );

			return AreEqual( Convert.ToInt32(expected), Convert.ToInt32(actual), tolerance );
		}
		/// <summary>
		/// Display Expected and Actual lines for given values, including
		/// a tolerance value on the Expected line.
		/// </summary>
		/// <param name="expected">The expected value</param>
		/// <param name="actual">The actual value causing the failure</param>
		/// <param name="tolerance">The tolerance within which the test was made</param>
		public abstract void DisplayDifferences(object expected, object actual, Tolerance tolerance);
		/// <summary>
		/// Write the generic 'Expected' line for a given value
		/// and tolerance.
		/// </summary>
		/// <param name="expected">The expected value</param>
		/// <param name="tolerance">The tolerance within which the test was made</param>
		private void WriteExpectedLine(object expected, Tolerance tolerance)
		{
			Write(Pfx_Expected);
			WriteExpectedValue(expected);

            if (tolerance != null && !tolerance.IsEmpty)
            {
                WriteConnector("+/-");
                WriteExpectedValue(tolerance.Value);
            }

			WriteLine();
		}
		/// <summary>
		/// Display Expected and Actual lines for given values, including
		/// a tolerance value on the expected line.
		/// </summary>
		/// <param name="expected">The expected value</param>
		/// <param name="actual">The actual value causing the failure</param>
		/// <param name="tolerance">The tolerance within which the test was made</param>
		public override void DisplayDifferences(object expected, object actual, Tolerance tolerance)
		{
			WriteExpectedLine(expected, tolerance);
			WriteActualLine(actual);
		}
		private static bool AreEqual( int expected, int actual, Tolerance tolerance )
		{
            switch (tolerance.Mode)
            {
                case ToleranceMode.None:
                    return expected.Equals(actual);

                case ToleranceMode.Linear:
                    int intTolerance = Convert.ToInt32(tolerance.Value);
                    if (intTolerance > 0)
                        return Math.Abs(expected - actual) <= intTolerance;

                    return expected.Equals(actual);

                case ToleranceMode.Percent:
                    if (expected == 0)
                        return expected.Equals(actual);

                    double relativeError = Math.Abs(
                        (double)(expected - actual) / (double)expected);
                    return (relativeError <= Convert.ToDouble(tolerance.Value) / 100.0);

                default:
                    throw new ArgumentException("Unknown tolerance mode specified", "mode");
            }
		}
		private static bool AreEqual( uint expected, uint actual, Tolerance tolerance )
		{
            switch (tolerance.Mode)
            {
                case ToleranceMode.None:
                    return expected.Equals(actual);

                case ToleranceMode.Linear:
                    uint uintTolerance = Convert.ToUInt32(tolerance.Value);
                    if(uintTolerance > 0)
			        {
				        uint diff = expected >= actual ? expected - actual : actual - expected;
                        return diff <= uintTolerance;
			        }
				
			        return expected.Equals( actual );

                case ToleranceMode.Percent:
                    if(expected == 0u)
                        return expected.Equals(actual);

                    // Can't do a simple Math.Abs() here since it's unsigned
                    uint difference = Math.Max(expected, actual) - Math.Min(expected, actual);
                    double relativeError = Math.Abs((double)difference / (double)expected );
                    return (relativeError <= Convert.ToDouble(tolerance.Value) / 100.0);

                default:
                    throw new ArgumentException("Unknown tolerance mode specified", "mode");
            }
		}
        private static bool AreEqual( float expected, float actual, ref Tolerance tolerance )
		{
            if ( float.IsNaN(expected) && float.IsNaN(actual) )
                return true;

            // handle infinity specially since subtracting two infinite values gives 
            // NaN and the following test fails. mono also needs NaN to be handled
            // specially although ms.net could use either method.
            if (float.IsInfinity(expected) || float.IsNaN(expected) || float.IsNaN(actual))
            {
                return expected.Equals(actual);
            }

            if (tolerance.IsEmpty && GlobalSettings.DefaultFloatingPointTolerance > 0.0d)
                tolerance = new Tolerance(GlobalSettings.DefaultFloatingPointTolerance);

            switch (tolerance.Mode)
            {
                case ToleranceMode.None:
                    return expected.Equals(actual);

                case ToleranceMode.Linear:
                    return Math.Abs(expected - actual) <= Convert.ToDouble(tolerance.Value);

                case ToleranceMode.Percent:
                    if (expected == 0.0f)
                        return expected.Equals(actual);
                    float relativeError = Math.Abs((expected - actual) / expected);
                    return (relativeError <= Convert.ToSingle(tolerance.Value) / 100.0f);
#if !NETCF_1_0
                case ToleranceMode.Ulps:
                    return FloatingPointNumerics.AreAlmostEqualUlps(
                        expected, actual, Convert.ToInt32(tolerance.Value));
#endif
                default:
                    throw new ArgumentException("Unknown tolerance mode specified", "mode");
            }
		}