C#实现的分数结构(编辑中)

基本完工了,除了一个抄自python的限制分母大小的方法会有bug(Σ( ° △ °|||)︴其他基本可以了

另外ToString重写了,所以直接ToString是分数形式(X/Y),要想显示小数形式要先转成double。

using System;

using System.Linq;

using System.Text.RegularExpressions;

using System.Threading;



namespace RainbowFraction

{

    public struct RainbowFraction : IComparable,  IComparable<RainbowFraction>, IEquatable<RainbowFraction>

    {

        #region 字段

        private long _numerator;

        private long _denominator;

        #endregion



        #region 属性

        /// <summary>

        /// 分子

        /// </summary>

        public long Numerator

        {

            set 

            {

                SetNumAndDen(out _numerator, out _denominator, value, Denominator);

            }

            get { return _numerator; }

        }

        /// <summary>

        /// 分母

        /// </summary>

        public long Denominator

        {

            get { return _denominator; }

            set

            {//分母分子不能同为负

                if (value != 0)

                {

                    SetNumAndDen(out _numerator, out _denominator, Numerator, value);

                }

                else

                {

                    throw new RainbowFractionException("分母不可为0.");

                }

            }

        }

        /// <summary>

        /// 值

        /// </summary>

        public double Value

        {

            get { return Numerator / (double)Denominator; }

        }

        #endregion



        #region 构造

        /// <summary>

        /// 以分子分母构造

        /// </summary>

        /// <param name="srcNum"></param>

        /// <param name="srcDen"></param>

        public RainbowFraction(long srcNum, long srcDen)

        {

            if (srcDen == 0)

            {

                throw new RainbowFractionException("分母不可为0");

            }

            if (srcNum * srcDen >= 0)

            {

                _numerator = Math.Abs(srcNum);

                _denominator = Math.Abs(srcDen);

            }

            else

            {

                _numerator = Math.Abs(srcNum) * -1;

                _denominator = Math.Abs(srcDen);

            }

        }

        /// <summary>

        /// 以double构造

        /// </summary>

        /// <param name="srcDouble"></param>

        public RainbowFraction(double srcDouble)

        {

            _numerator = 0;

            _denominator = 1;

            RainbowFraction tmp = ToRainbowFraction(srcDouble);

            _numerator = tmp.Numerator;

            _denominator = tmp.Denominator;

        }

        /// <summary>

        /// 以字符串构造

        /// </summary>

        /// <param name="srcString"></param>

        public RainbowFraction(string srcString)

        {

            _numerator = 0;

            _denominator = 1;

            RainbowFraction tmp = ToRainbowFraction(srcString);

            _numerator = tmp.Numerator;

            _denominator = tmp.Denominator;

        }

        #endregion



        #region 方法

        /// <summary>

        /// double to fraction

        /// </summary>

        /// <param name="srcDouble"></param>

        /// <returns></returns>

        public static RainbowFraction ToRainbowFraction(double srcDouble)

        {

            RainbowFraction result = new RainbowFraction();

            try

            {

                checked

                {

                    string srcString = srcDouble.ToString();

                    double tmpNum = srcDouble;

                    long tmpDen = 1;

                    while (srcString.IndexOf('E') > 0)

                    {

                        tmpNum *= 10;

                        tmpDen *= 10;

                        srcString = tmpNum.ToString();

                    }

                    if (srcString.Contains('.'))

                    {

                        int lengthAfterDot = srcString.Split('.')[1].Length;

                        while (lengthAfterDot > 0)

                        {

                            tmpNum *= 10;

                            tmpDen *= 10;

                            lengthAfterDot--;

                        }

                    }

                    result = new RainbowFraction((long)Math.Round(tmpNum), tmpDen);

                }

            }

            catch (OverflowException)

            {

                throw new RainbowFractionException("转换时发生溢出");

            }

            catch (Exception)

            {

                throw new RainbowFractionException("转换失败");

            }

            return result;

        }

        /// <summary>

        /// string to double

        /// </summary>

        /// <param name="srcString"></param>

        /// <returns></returns>

        public static RainbowFraction ToRainbowFraction(string srcString)

        {

            RainbowFraction result = new RainbowFraction();

            try

            {

                double srcDouble = 0;

                Regex fracRegex = new Regex(@"^-?\d+\/-?\d+$");

                if (double.TryParse(srcString, out srcDouble))

                {//形如1.23

                    result = ToRainbowFraction(srcDouble);

                }

                else if (fracRegex.IsMatch(srcString))

                {//形如1/23

                    result = new RainbowFraction(Convert.ToInt64(srcString.Split('/')[0]), Convert.ToInt64(srcString.Split('/')[1]));

                }

                else

                {

                    throw new RainbowFractionException("输入字符串有误");

                }

            }

            catch

            {

                throw new RainbowFractionException("转换失败");

            }

            return result;

        }

        /// <summary>

        /// 转化为字符串

        /// </summary>

        /// <returns></returns>

        public override string ToString()

        {

            return Denominator == 0 ? "NaN" : string.Format("{0}/{1}", Numerator, Denominator);

        }

        /// <summary>

        /// 限制分母最大值

        /// 抄自python,个别情况下会出异常

        /// </summary>

        /// <param name="srcMaxDen"></param>

        /// <returns></returns>

        public RainbowFraction LimitDenominator(long srcMaxDen)

        {

            if (srcMaxDen < 1)

            {

                throw new RainbowFractionException("分母需要大于0.");

            }

            if (srcMaxDen > long.MaxValue)

            {

                throw new RainbowFractionException("分母过大.");

            }

            if (Denominator < srcMaxDen)

            {

                return this;

            }

            try

            {

                long p0 = 0;

                long q0 = 1;

                long p1 = 1;

                long q1 = 0;

                long n = Numerator;

                long d = Denominator;

                while (true)

                {

                    long a = n / d;

                    long q2 = q0 + a * q1;

                    if (q2 > srcMaxDen)

                    {

                        break;

                    }

                    long p0Old = p0;

                    p0 = p1;

                    q0 = q1;

                    p1 = p0Old + a * p1;

                    q1 = q2;

                    long nOld = n;

                    n = d;

                    d = nOld - a * d;

                }

                long k = (srcMaxDen - q0) / q1;

                RainbowFraction result1 = new RainbowFraction(p0 + k * p1, q0 + k * q1);

                RainbowFraction result2 = new RainbowFraction(p1, q1);



                if (Math.Abs(result2 - this) <= Math.Abs(result1 - this))

                {

                    return result2;

                }

                else

                {

                    return result1;

                }

            }

            catch (DivideByZeroException)

            {

                throw new RainbowFractionException("转化错误,请尝试别的数字.");

            }



        }

        /// <summary>

        /// 设置分子分母及符号

        /// </summary>

        /// <param name="srcNum"></param>

        /// <param name="srcDen"></param>

        /// <param name="destNum"></param>

        /// <param name="destDen"></param>

        private static void SetNumAndDen(out long srcNum, out long srcDen, long destNum, long destDen)

        {

            if (destNum * destDen >= 0)

            {

                srcNum = Math.Abs(destNum);

                srcDen = Math.Abs(destDen);

            }

            else

            {

                srcNum = -Math.Abs(destNum);

                srcDen = Math.Abs(destDen);

            }

        }

        /// <summary>

        /// 约分后分数

        /// </summary>

        /// <returns></returns>

        public RainbowFraction ReduceNumAndDen()

        {

            long gcd = GreatestCommonDivisor(Numerator, Denominator);

            return new RainbowFraction(Numerator/gcd, Denominator/gcd);

        }

        /// <summary>

        /// 辗转相除法求最大公约数

        /// </summary>

        /// <param name="srcBig"></param>

        /// <param name="srcSmall"></param>

        /// <returns></returns>

        private static long GreatestCommonDivisor(long srcBig, long srcSmall)

        {

            srcBig = Math.Abs(srcBig);

            srcSmall = Math.Abs(srcSmall);

            if (srcSmall > srcBig)

            {

                srcSmall = srcSmall ^ srcBig;

                srcBig = srcSmall ^ srcBig;

                srcSmall = srcSmall ^ srcBig;

            }

            if (srcBig%srcSmall == 0)

            {

                return srcSmall;

            }

            else

            {

                return GreatestCommonDivisor(srcSmall, srcBig % srcSmall);

            }

        }

        #endregion



        #region 接口实现

        /// <summary>

        /// 分数比较

        /// </summary>

        /// <param name="obj"></param>

        /// <returns></returns>

        public int CompareTo(object obj)

        {

            int result;

            double tmpValue;

            if (obj == null)

            {

                throw new RainbowFractionException("比较失败");

            }



            if (obj is string)

            {

                if (this > ToRainbowFraction(obj as string))

                {

                    result = 1;

                }

                else if (this < ToRainbowFraction(obj as string))

                {

                    result = -1;

                }

                else

                {

                    result = 0;

                }

            }

            else if (double.TryParse(obj as string, out tmpValue))

            {

                result = Value.CompareTo(tmpValue);

            }

            else

            {

                throw new RainbowFractionException("比较失败");

            }

            return result;

        }

        /// <summary>

        /// 分数比较

        /// </summary>

        /// <param name="other"></param>

        /// <returns></returns>

        public int CompareTo(RainbowFraction other)

        {

            int result = 0;

            if (this > other)

            {

                result = 1;

            }

            else if (this < other)

            {

                result = -1;

            }

            return result;

        }

        /// <summary>

        /// 分数判等

        /// </summary>

        /// <param name="other"></param>

        /// <returns></returns>

        public bool Equals(RainbowFraction other)

        {

            return Value == other.Value;

        }

        #endregion



        #region 隐式转化

        /// <summary>

        /// double to fraction

        /// </summary>

        /// <param name="srcDouble"></param>

        /// <returns></returns>

        public static implicit operator RainbowFraction(double srcDouble)

        {

            RainbowFraction result = new RainbowFraction(srcDouble);

            return result;

        }

        /// <summary>

        /// fraction to double

        /// </summary>

        /// <param name="srcFrac"></param>

        /// <returns></returns>

        public static implicit operator double(RainbowFraction srcFrac)

        {

            return srcFrac.Value;

        }

        #endregion



        #region 运算符重载

        //一元运算

        public static RainbowFraction operator -(RainbowFraction srcFrac)

        {

            return new RainbowFraction(srcFrac.Numerator * -1, srcFrac.Denominator);

        }



        //二元逻辑运算

        public static bool operator >(RainbowFraction left, RainbowFraction right)

        {

            return left.Value > right.Value;

        }

        public static bool operator >=(RainbowFraction left, RainbowFraction right)

        {

            return left.Value >= right.Value;

        }

        public static bool operator <(RainbowFraction left, RainbowFraction right)

        {

            return left.Value < right.Value;

        }

        public static bool operator <=(RainbowFraction left, RainbowFraction right)

        {

            return left.Value < right.Value;

        }

        public static bool operator ==(RainbowFraction left, RainbowFraction right)

        {

            return left.Value == right.Value;

        }

        public static bool operator !=(RainbowFraction left, RainbowFraction right)

        {

            return left.Value != right.Value;

        }

        //二元算术运算

        /// <summary>

        /// RainbowFraction Add

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        public static RainbowFraction operator +(RainbowFraction left, RainbowFraction right)

        {

            return AddFraction(left, right);

        }

        /// <summary>

        /// RainbowFraction Minus

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        public static RainbowFraction operator -(RainbowFraction left, RainbowFraction right)

        {

            return SubFraction(left, right);

        }

        /// <summary>

        /// RainbowFraction Mult

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        public static RainbowFraction operator *(RainbowFraction left, RainbowFraction right)

        {

            return MultFraction(left, right);

        }

        /// <summary>

        /// RainbowFraction Div

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        public static RainbowFraction operator /(RainbowFraction left, RainbowFraction right)

        {

            return DivFraction(left, right);

        }

        /// <summary>

        /// Add function

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        private static RainbowFraction AddFraction(RainbowFraction left, RainbowFraction right)

        {

            RainbowFraction result = new RainbowFraction();

            result.Denominator = left.Denominator * right.Denominator;

            result.Numerator = left.Numerator * right.Denominator + right.Numerator * left.Denominator;

            return result;

        }

        /// <summary>

        /// Sub function

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        private static RainbowFraction SubFraction(RainbowFraction left, RainbowFraction right)

        {

            RainbowFraction result = new RainbowFraction();

            result.Denominator = left.Denominator * right.Denominator;

            result.Numerator = left.Numerator * right.Denominator - right.Numerator * left.Denominator;

            return result;

        }

        /// <summary>

        /// Mult fraction

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        private static RainbowFraction MultFraction(RainbowFraction left, RainbowFraction right)

        {

            RainbowFraction result = new RainbowFraction();

            result.Denominator = left.Denominator * right.Denominator;

            result.Numerator = left.Numerator * right.Numerator;

            return result;

        }

        /// <summary>

        /// div fraction

        /// </summary>

        /// <param name="left"></param>

        /// <param name="right"></param>

        /// <returns></returns>

        private static RainbowFraction DivFraction(RainbowFraction left, RainbowFraction right)

        {

            RainbowFraction result = new RainbowFraction();

            result.Denominator = left.Denominator * right.Numerator;

            result.Numerator = left.Numerator * right.Denominator;

            return result;

        }

        #endregion



    }

    /// <summary>

    /// 分数异常

    /// </summary>

    public class RainbowFractionException : Exception

    {

        public RainbowFractionException(string srcMsg)

            : base(srcMsg)

        {

        }

    }

}

  

你可能感兴趣的:(C#)