/// <summary>
            /// Takes two TNumbers and subtracts one from the other.
            /// </summary>
            /// <param name="interpreter">The interpreter that the method is being called from.</param>
            /// <param name="a">The left hand operand of the operation.</param>
            /// <param name="b">The right hand operand of the operation.</param>
            /// <returns>
            /// The TType resulting from the operation. An MExcpetion or null is returned when there is an error.
            /// </returns>
            public static TType Subtract(Interpreter interpreter, TType a, TType b)
            {
                // Try to get TNumber values from the TType arguments
                TNumber numberA, numberB;
                TException exception = AssignNumberValue(interpreter, out numberA, a);
                if (exception != null) return exception;
                exception = AssignNumberValue(interpreter, out numberB, b);
                if (exception != null) return exception;

                // No errors, but one or both of the arguments could be a TString; check them
                if ((numberA == null) || (numberB == null))
                    return new TException(interpreter, "Strings cannot be used in subtraction operations");

                switch (numberA.TypeName)
                {
                    case TType.T_INTEGER_TYPENAME:
                        {
                            // If the other operand is a fraction, treat this integer as a fraction (i.e. value/1)
                            TFraction rhsFraction = numberB as TFraction;
                            if (rhsFraction != null)
                            {
                                // Order of fractions matters in this case
                                TFraction lhsFraction = new TFraction(numberA.TIntegerValue, 1);
                                lhsFraction.Subtract(rhsFraction.Numerator, rhsFraction.Denominator);
                                return lhsFraction;
                            }
                            return new TInteger(numberA.TIntegerValue - numberB.TIntegerValue);
                        }

                    case TType.T_REAL_TYPENAME:
                        return new TReal(numberA.TRealValue - numberB.TRealValue);

                    case TType.T_FRACTION_TYPENAME:
                        {
                            // Create a copy of the left hand fraction
                            TFraction fraction = numberA as TFraction;
                            fraction = new TFraction(fraction.Numerator, fraction.Denominator);

                            // Convert the right hand operand to a fraction
                            long numerator, denominator;
                            TFraction otherFraction = numberB as TFraction;
                            if (otherFraction != null) // If it's a fraction, simply copy the values
                            {
                                numerator = otherFraction.Numerator;
                                denominator = otherFraction.Denominator;
                            }
                            else
                            {
                                // Check if it's a TInteger first. It might not need to use DoubleToFraction
                                if (numberB is TInteger)
                                {
                                    numerator = numberB.TIntegerValue;
                                    denominator = 1;
                                }
                                else Operations.Misc.DoubleToFraction(numberB.TRealValue, out numerator,
                                    out denominator);
                            }

                            fraction.Subtract(numerator, denominator);
                            return fraction;
                        }
                }

                return null;
            }
            /// <summary>
            /// Takes two TNumbers or two TStrings (or up to two TVariables containing TNumbers or TStrings) and
            /// adds them together.
            /// </summary>
            /// <param name="interpreter">The interpreter that the method is being called from.</param>
            /// <param name="a">The left hand operand of the operation.</param>
            /// <param name="b">The right hand operand of the operation.</param>
            /// <returns>
            /// The TType resulting from the operation. An MExcpetion or null is returned when there is an error.
            /// </returns>
            public static TType Add(Interpreter interpreter, TType a, TType b)
            {
                // Convert arguments 'a' and 'b' into either a TNumber or a TString
                TNumber numberA, numberB;
                TString strA = null, strB = null;

                TException exception = AssignNumberValue(interpreter, out numberA, a);
                if (exception != null) return exception;

                if (numberA == null)
                {
                    // No errors yet, and numberA is null, so argument 'a' could be a TString or a TVariable
                    // containing a TString
                    strA = a as TString;
                    if (strA == null)
                    {
                        TVariable variable = a as TVariable;
                        if (variable != null) strA = variable.Value as TString;
                    }
                }
                if ((numberA == null) && (strA == null)) // Nothing useful, return a TException
                    return new TException(interpreter, "Value is not a number or string");

                // Same procedure for argument 'b'
                exception = AssignNumberValue(interpreter, out numberB, b);
                if (exception != null) return exception;
                if (numberB == null)
                {
                    strB = b as TString;
                    if (strB == null)
                    {
                        TVariable variable = b as TVariable;
                        if (variable != null) strB = variable.Value as TString;
                    }
                }
                if ((numberB == null) && (strB == null))
                    return new TException(interpreter, "Value is not a number or string");

                // Attempt addition if both operands are the same type, otherwise return a TException
                if ((numberB == null) && (strA == null))
                    return new TException(interpreter, "Attempted addition of a string to a number");
                else if ((numberA == null) && (strB == null))
                    return new TException(interpreter, "Attempted addition of a number to a string");
                else if ((numberA == null) && (numberB == null))
                {
                    return new TString(strA.Value + strB.Value);
                }
                else
                {
                    //The left hand operand decides the type of the returned value
                    switch (numberA.TypeName)
                    {
                        case TType.T_INTEGER_TYPENAME:
                            {
                                // If the other operand is a fraction, treat this integer as a fraction (i.e. value/1)
                                TFraction fraction = numberB as TFraction;
                                if (fraction != null)
                                {
                                    // Copy the right hand fraction and add the left hand integer to it
                                    fraction = new TFraction(fraction.Numerator, fraction.Denominator);
                                    fraction.Add(numberA.TIntegerValue, 1);
                                    return fraction;
                                }
                                return new TInteger(numberA.TIntegerValue + numberB.TIntegerValue);
                            }

                        case TType.T_REAL_TYPENAME:
                            return new TReal(numberA.TRealValue + numberB.TRealValue);

                        case TType.T_FRACTION_TYPENAME:
                            {
                                // Create a copy of the left hand fraction
                                TFraction fraction = numberA as TFraction;
                                fraction = new TFraction(fraction.Numerator, fraction.Denominator);

                                // Convert the right hand operand to a fraction
                                long numerator, denominator;
                                TFraction otherFraction = numberB as TFraction;
                                if (otherFraction != null) // If it's a fraction, simply copy the values
                                {
                                    numerator = otherFraction.Numerator;
                                    denominator = otherFraction.Denominator;
                                }
                                else
                                {
                                    // Check if it's a TInteger first. It might not need to use DoubleToFraction
                                    if (numberB is TInteger)
                                    {
                                        numerator = numberB.TIntegerValue;
                                        denominator = 1;
                                    }
                                    else Operations.Misc.DoubleToFraction(numberB.TRealValue, out numerator,
                                        out denominator);
                                }

                                fraction.Add(numerator, denominator);
                                return fraction;
                            }
                    }
                }

                return null;
            }