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

  

原文地址:https://www.cnblogs.com/zhuyc110/p/4069867.html