/// <summary>
        /// Returns a type which is able to represent either of two given types without loss of precision
        /// </summary>
        /// <param name="td1">first given type</param>
        /// <param name="td2">second given type</param>
        /// <returns></returns>
        private static TypeDescriptor GetCommonType(TypeDescriptor td1, TypeDescriptor td2)
        {
            if (td1.Equals(td2))
                return td1;

            if (IsSFix(td1) && IsUFix(td2))
            {
                var fmt1 = SFix.GetFormat(td1);
                var fmt2 = UFix.GetFormat(td2);
                return SFix.MakeType(
                    Math.Max(fmt1.IntWidth, fmt2.IntWidth + 1),
                    Math.Max(fmt1.FracWidth, fmt2.FracWidth));
            }
            else if (IsUFix(td1) && IsSFix(td2))
            {
                return GetCommonType(td2, td1);
            }
            else if (IsSFix(td1) && IsSFix(td2))
            {
                var fmt1 = SFix.GetFormat(td1);
                var fmt2 = SFix.GetFormat(td2);
                return SFix.MakeType(
                    Math.Max(fmt1.IntWidth, fmt2.IntWidth),
                    Math.Max(fmt1.FracWidth, fmt2.FracWidth));
            }
            else if (IsUFix(td1) && IsUFix(td2))
            {
                var fmt1 = UFix.GetFormat(td1);
                var fmt2 = UFix.GetFormat(td2);
                return UFix.MakeType(
                    Math.Max(fmt1.IntWidth, fmt2.IntWidth),
                    Math.Max(fmt1.FracWidth, fmt2.FracWidth));
            }
            else if (IsSigned(td1))
            {
                var fmt = SFix.GetFormat(td1);
                var td1x = SFix.MakeType(fmt.IntWidth, fmt.FracWidth);
                return GetCommonType(td1x, td2);
            }
            else if (IsSigned(td2))
            {
                return GetCommonType(td2, td1);
            }
            else if (IsUnsigned(td1))
            {
                var fmt = UFix.GetFormat(td1);
                var td1x = UFix.MakeType(fmt.IntWidth, fmt.FracWidth);
                return GetCommonType(td1x, td2);
            }
            else if (IsUnsigned(td2))
            {
                return GetCommonType(td2, td1);
            }
            else
            {
                throw new NotSupportedException(
                    "Cannot determine common type between " +
                    td1.ToString() + " and " + td2.ToString());
            }
        }