1. 程式人生 > >C#實現的分數類

C#實現的分數類

前陣子開始想做成一個完備的分數類,昨天有時間進行了實現,今天再看程式碼一團糟。

於今天進行重構,尚未完成,待續。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

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 
            {//分母分子不能同為負
                if (value * _denominator >= 0)
                {
                    _numerator = Math.Abs(value);
                    _denominator = Math.Abs(_denominator);
                }
                else
                {
                    _numerator = Math.Abs(value) * -1;
                    _denominator = Math.Abs(_denominator);
                }
            }
            get { return _numerator; }
        }
        /// <summary>
        /// 分母
        /// </summary>
        public long Denominator
        {
            get { return _denominator; }
            set
            {//分母分子不能同為負
                if (value != 0)
                {
                    if (_numerator * value >= 0)
                    {
                        _numerator = Math.Abs(_numerator);
                        _denominator = Math.Abs(value);
                    }
                    else
                    {
                        _numerator = Math.Abs(_numerator) * -1;
                        _denominator = Math.Abs(value);
                    }
                }
                else
                {
                    throw new RainbowFractionException("分母不可為0.");
                }
            }
        }
        /// <summary>
        /// 值
        /// </summary>
        public double Value
        {
            get { return (double)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);
        }
        #endregion

        #region 介面實現
        public int CompareTo(object obj)
        {
            int result = 0;
            double tmpValue = 0;
            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 = this.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 this.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;
        }
        //二元算術運算
        public static RainbowFraction operator +(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;
        }
        public static RainbowFraction operator -(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;
        }
        public static RainbowFraction operator *(RainbowFraction left, RainbowFraction right)
        {
            RainbowFraction result = new RainbowFraction();
            result.Denominator = left.Denominator * right.Denominator;
            result.Numerator = left.Numerator * right.Numerator;
            return result;
        }
        public static RainbowFraction operator /(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)
        {
        }
    }
}