• C#实现的分数类


    最近又对分数类做了一些修改,有些优化有些改写。

    抄自python的限制分母大小的方法还是会有bug(Σ( ° △ °|||)︴。

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 
      6 namespace Rainbow.Core
      7 {
      8     public class Fraction : IComparable, IComparable<Fraction>, IEquatable<Fraction>
      9     {
     10         #region fields
     11         private long _numerator = 0;
     12         private long _denominator = 1;
     13         #endregion
     14 
     15         #region properties
     16         /// <summary>
     17         /// 分子
     18         /// </summary>
     19         public long Numerator
     20         {
     21             get { return _numerator; }
     22             set
     23             {
     24                 SetNumAndDen(value, Denominator);
     25             }
     26         }
     27         /// <summary>
     28         /// 分母
     29         /// </summary>
     30         public long Denominator
     31         {
     32             get { return _denominator; }
     33             set
     34             {//分母分子不能同为负
     35                 JudgeDenominator(value);
     36                 SetNumAndDen(Numerator, value);
     37             }
     38         }
     39         /// <summary>
     40         /// 41         /// </summary>
     42         public double Value
     43         {
     44             get { return Numerator / (double)Denominator; }
     45         }
     46         #endregion
     47 
     48         #region constructors
     49 
     50         public Fraction()
     51             : this(0, 1)
     52         { }
     53 
     54         public Fraction(long srcNum, long srcDen)
     55         {
     56             JudgeDenominator(srcDen);
     57             SetNumAndDen(srcNum, srcDen);
     58         }
     59 
     60         public Fraction(string srcNum, string srcDen)
     61         {
     62             long numerator, denominator;
     63             var result = Int64.TryParse(srcNum, out numerator);
     64             if (result == false)
     65                 throw new Exception("Can not convert numerator:" + srcNum + " to a number.");
     66             result = Int64.TryParse(srcNum, out denominator);
     67             if (result == false)
     68                 throw new Exception("Can not convert denominator:" + srcDen + " to a number.");
     69 
     70             JudgeDenominator(denominator);
     71             SetNumAndDen(numerator, denominator);
     72         }
     73 
     74         public Fraction(double srcDouble)
     75         {
     76             var tmp = ToFraction(srcDouble);
     77             SetNumAndDen(tmp.Numerator, tmp.Denominator);
     78         }
     79 
     80         public Fraction(string srcString)
     81         {
     82             var tmp = ToFraction(srcString);
     83             SetNumAndDen(tmp.Numerator, tmp.Denominator);
     84         }
     85         #endregion
     86 
     87         #region methods
     88         /// <summary>
     89         /// 设置分子分母值
     90         /// </summary>
     91         /// <param name="destNum"></param>
     92         /// <param name="destDen"></param>
     93         private void SetNumAndDen(long destNum, long destDen)
     94         {
     95             var negative = IsDifferentSign(destNum, destDen);
     96             _numerator = negative ? -Math.Abs(destNum) : Math.Abs(destNum);
     97             _denominator = Math.Abs(destDen);
     98         }
     99         /// <summary>
    100         /// 判断分母不为0
    101         /// </summary>
    102         /// <param name="srcDen"></param>
    103         private void JudgeDenominator(long srcDen)
    104         {
    105             if (srcDen == 0)
    106                 throw new Exception("Denominator can not be zero.");
    107         }        
    108         /// <summary>
    109         /// 分子分母是否异号
    110         /// </summary>
    111         /// <param name="destNum"></param>
    112         /// <param name="destDen"></param>
    113         /// <returns></returns>
    114         private static bool IsDifferentSign(long destNum, long destDen)
    115         {
    116             return ((destNum >> 63) ^ (destDen >> 63)) == 1 ? true : false;
    117         }
    118 
    119         public static Fraction ToFraction(double srcDouble)
    120         {
    121             var result = new Fraction();
    122             try
    123             {
    124                 checked
    125                 {
    126                     string srcString = srcDouble.ToString();
    127                     double tmpNum = srcDouble;
    128                     long tmpDen = 1;
    129                     while (srcString.IndexOf('E') > 0)
    130                     {
    131                         tmpNum *= 10;
    132                         tmpDen *= 10;
    133                         srcString = tmpNum.ToString();
    134                     }
    135                     if (srcString.Contains('.'))
    136                     {
    137                         int lengthAfterDot = srcString.Split('.')[1].Length;
    138                         while (lengthAfterDot > 0)
    139                         {
    140                             tmpNum *= 10;
    141                             tmpDen *= 10;
    142                             lengthAfterDot--;
    143                         }
    144                     }
    145                     result = new Fraction((long)Math.Round(tmpNum), tmpDen);
    146                 }
    147             }
    148             catch (OverflowException)
    149             {
    150                 throw new Exception("Overflow while converting " + srcDouble + " to fraction.");
    151             }
    152             return result;
    153         }
    154 
    155         public static Fraction ToFraction(string srcString)
    156         {
    157             Fraction result = new Fraction();
    158             double srcDouble = 0;
    159             if (double.TryParse(srcString, out srcDouble))
    160             {//形如1.23,1E23
    161                 result = ToFraction(srcDouble);
    162             }
    163             else if (new System.Text.RegularExpressions.Regex(@"^-?d+/-?d+$").IsMatch(srcString))
    164             {
    165                 result = new Fraction(srcString.Split('/')[0], srcString.Split('/')[1]);
    166             }
    167             else
    168             {
    169                 throw new Exception(string.Format("Failed while converting <{0}> to fraction.", srcString));
    170             }
    171             return result;
    172         }
    173         /// <summary>
    174         /// 约分
    175         /// </summary>
    176         /// <returns></returns>
    177         public Fraction ReduceNumAndDen()
    178         {
    179             var gcd = GreatestCommonDivisor(Numerator, Denominator);
    180             return new Fraction(Numerator / gcd, Denominator / gcd);
    181         }
    182         /// <summary>
    183         /// 辗转相除法求最大公约数
    184         /// </summary>
    185         /// <param name="srcBig"></param>
    186         /// <param name="srcSmall"></param>
    187         /// <returns></returns>
    188         private static long GreatestCommonDivisor(long srcBig, long srcSmall)
    189         {
    190             srcBig = Math.Abs(srcBig);
    191             srcSmall = Math.Abs(srcSmall);
    192             if (srcSmall > srcBig)
    193             {
    194                 srcSmall = srcSmall ^ srcBig;
    195                 srcBig = srcSmall ^ srcBig;
    196                 srcSmall = srcSmall ^ srcBig;
    197             }
    198             if (srcBig % srcSmall == 0)
    199             {
    200                 return srcSmall;
    201             }
    202             else
    203             {
    204                 return GreatestCommonDivisor(srcSmall, srcBig % srcSmall);
    205             }
    206         }
    207         /// <summary>
    208         /// 限制分母最大值
    209         /// 抄自python,个别情况下会出异常
    210         /// </summary>
    211         /// <param name="srcMaxDen"></param>
    212         /// <returns></returns>
    213         public Fraction LimitDenominator(long srcMaxDen)
    214         {
    215             if (srcMaxDen < 1)            
    216                 throw new Exception("Denominator should bigger than 0.");
    217             
    218             if (Denominator < srcMaxDen)            
    219                 return this;
    220             
    221             try
    222             {
    223                 long p0 = 0;
    224                 long q0 = 1;
    225                 long p1 = 1;
    226                 long q1 = 0;
    227                 long n = Numerator;
    228                 long d = Denominator;
    229                 while (true)
    230                 {
    231                     long a = n / d;
    232                     long q2 = q0 + a * q1;
    233                     if (q2 > srcMaxDen)
    234                     {
    235                         break;
    236                     }
    237                     long p0Old = p0;
    238                     p0 = p1;
    239                     q0 = q1;
    240                     p1 = p0Old + a * p1;
    241                     q1 = q2;
    242                     long nOld = n;
    243                     n = d;
    244                     d = nOld - a * d;
    245                 }
    246                 long k = (srcMaxDen - q0) / q1;
    247                 var result1 = new Fraction(p0 + k * p1, q0 + k * q1);
    248                 var result2 = new Fraction(p1, q1);
    249 
    250                 if (Math.Abs(result2.Value - this.Value) <= Math.Abs(result1.Value - this.Value))                
    251                     return result2;                
    252                 else                
    253                     return result1;                
    254             }
    255             catch (DivideByZeroException)
    256             {
    257                 //跟python结果不一致,要调查
    258                 return this;
    259             }
    260         }
    261         #endregion
    262 
    263         #region ToString
    264         /// <summary>
    265         /// 转化为x/y形式
    266         /// </summary>
    267         /// <returns></returns>
    268         public override string ToString()
    269         {
    270             return Denominator == 0 ? "NaN" : string.Format("{0}/{1}", Numerator, Denominator);
    271         }
    272         /// <summary>
    273         /// 转化为double字符串
    274         /// </summary>
    275         /// <returns></returns>
    276         public string ToDoubleString()
    277         {
    278             return Value.ToString();
    279         }
    280         #endregion
    281 
    282         #region interface
    283 
    284         #region IComparable<Fraction> 成员
    285 
    286         public int CompareTo(Fraction other)
    287         {
    288             return this.Value.CompareTo(other.Value);
    289         }
    290 
    291         #endregion
    292 
    293         #region IEquatable<Fraction> 成员
    294 
    295         public bool Equals(Fraction other)
    296         {
    297             return this == other;
    298         }
    299 
    300         #endregion
    301 
    302         #region IComparable 成员
    303 
    304         public int CompareTo(object obj)
    305         {
    306             int result;
    307             double tmpValue;
    308             if (obj == null)            
    309                 throw new Exception("比较失败");            
    310 
    311             if (obj is string)
    312             {
    313                 var strFrac = obj as string;
    314                 if (this > ToFraction(strFrac))                
    315                     result = 1;
    316                 else if (this < ToFraction(strFrac))                
    317                     result = -1;                
    318                 else                
    319                     result = 0;                
    320             }
    321             else if (double.TryParse(obj as string, out tmpValue))
    322             {
    323                 result = Value.CompareTo(tmpValue);
    324             }
    325             else
    326             {
    327                 throw new Exception("比较失败");
    328             }
    329             return result;
    330         }
    331 
    332         #endregion
    333 
    334         #endregion
    335 
    336         /// <summary>
    337         /// fraction to double
    338         /// </summary>
    339         /// <param name="srcFrac"></param>
    340         /// <returns></returns>
    341         public static implicit operator double(Fraction srcFrac)
    342         {
    343             return srcFrac.Value;
    344         }
    345 
    346         #region operator
    347 
    348         //一元运算
    349         public static Fraction operator -(Fraction srcFrac)
    350         {
    351             return new Fraction(srcFrac.Numerator * -1, srcFrac.Denominator);
    352         }
    353 
    354         //二元逻辑运算
    355         public static bool operator >(Fraction left, Fraction right)
    356         {
    357             return left.Value > right.Value;
    358         }
    359         public static bool operator >=(Fraction left, Fraction right)
    360         {
    361             return left.Value >= right.Value;
    362         }
    363         public static bool operator <(Fraction left, Fraction right)
    364         {
    365             return left.Value < right.Value;
    366         }
    367         public static bool operator <=(Fraction left, Fraction right)
    368         {
    369             return left.Value <= right.Value;
    370         }
    371         public static bool operator ==(Fraction left, Fraction right)
    372         {
    373             return left.Value == right.Value;
    374         }
    375         public static bool operator !=(Fraction left, Fraction right)
    376         {
    377             return left.Value != right.Value;
    378         }
    379 
    380         //二元算术运算
    381         private static Fraction AddFraction(Fraction left, Fraction right)
    382         {
    383             var result = new Fraction();
    384             result.Denominator = left.Denominator * right.Denominator;
    385             result.Numerator = left.Numerator * right.Denominator + right.Numerator * left.Denominator;
    386             return result;
    387         }
    388         private static Fraction SubFraction(Fraction left, Fraction right)
    389         {
    390             var result = new Fraction();
    391             result.Denominator = left.Denominator * right.Denominator;
    392             result.Numerator = left.Numerator * right.Denominator - right.Numerator * left.Denominator;
    393             return result;
    394         }
    395         private static Fraction MultFraction(Fraction left, Fraction right)
    396         {
    397             var result = new Fraction();
    398             result.Denominator = left.Denominator * right.Denominator;
    399             result.Numerator = left.Numerator * right.Numerator;
    400             return result;
    401         }
    402         private static Fraction DivFraction(Fraction left, Fraction right)
    403         {
    404             var result = new Fraction();
    405             result.Denominator = left.Denominator * right.Numerator;
    406             result.Numerator = left.Numerator * right.Denominator;
    407             return result;
    408         }
    409 
    410         public static Fraction operator +(Fraction left, Fraction right)
    411         {
    412             return AddFraction(left, right);
    413         }
    414         public static Fraction operator -(Fraction left, Fraction right)
    415         {
    416             return SubFraction(left, right);
    417         }
    418         public static Fraction operator *(Fraction left, Fraction right)
    419         {
    420             return MultFraction(left, right);
    421         }
    422         public static Fraction operator /(Fraction left, Fraction right)
    423         {
    424             return DivFraction(left, right);
    425         }
    426         #endregion
    427     }
    428 }
    Fraction

      

  • 相关阅读:
    SqlHelper.cs源代码,学习!
    Fiddler工具介绍一
    dhl:Linq之group by 学习 使用
    vpc2007上安装windows7
    (五) ViewEngine 深入解析与应用实例
    VirtualPC2007添加Shared Folder的方法for dos
    SQL Server 2005 无法连接数据库终极解决方案!
    switch……case里的case 同时定义多个值
    dhl:AjaxPro的使用后感
    ifram高度自适应,获取iframe元素,控制父页面
  • 原文地址:https://www.cnblogs.com/zhuyc110/p/4069867.html
Copyright © 2020-2023  润新知