C#實現的分數類
阿新 • • 發佈:2019-01-06
前陣子開始想做成一個完備的分數類,昨天有時間進行了實現,今天再看程式碼一團糟。
於今天進行重構,尚未完成,待續。
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) { } } }