Fraction.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. namespace MatrixIO
  6. {
  7. public struct Fraction : IComparable, IComparable<Fraction>, IEquatable<Fraction>
  8. {
  9. #region Value
  10. private readonly int _numerator;
  11. public int Numerator { get { return _numerator; } }
  12. private readonly int _denominator;
  13. public int Denominator { get { return _denominator; } }
  14. #endregion
  15. #region Properties
  16. private readonly bool _isInLowestTerms;
  17. public bool IsInLowestTerms { get { return _isInLowestTerms; } }
  18. #endregion
  19. #region Constructors
  20. public Fraction(int numerator, int denominator)
  21. {
  22. if (denominator == 0) throw new ArgumentOutOfRangeException("Denominator must not be 0.");
  23. if(denominator < 0 )
  24. {
  25. if(numerator < 0)
  26. {
  27. _numerator = Math.Abs(numerator);
  28. _denominator = Math.Abs(denominator);
  29. }
  30. else
  31. {
  32. _numerator = -numerator;
  33. _denominator = Math.Abs(denominator);
  34. }
  35. }
  36. _numerator = numerator;
  37. _denominator = denominator;
  38. _isInLowestTerms = false;
  39. }
  40. public Fraction(int numerator, int denominator, bool asLowestTerms)
  41. : this(numerator, denominator)
  42. {
  43. if(asLowestTerms)
  44. {
  45. var gcd = GreatestCommonDivisor(_numerator, _denominator);
  46. _numerator = _numerator / gcd;
  47. _denominator = _denominator / gcd;
  48. }
  49. _isInLowestTerms = asLowestTerms;
  50. }
  51. private Fraction(bool inLowestTerms, int numerator, int denominator)
  52. : this(numerator, denominator)
  53. {
  54. _isInLowestTerms = inLowestTerms;
  55. }
  56. #endregion
  57. public Fraction GetLowestTerms()
  58. {
  59. if (_isInLowestTerms) return this;
  60. var gcd = GreatestCommonDivisor(_numerator, _denominator);
  61. return new Fraction(true, _numerator / gcd, _denominator / gcd);
  62. }
  63. public Fraction GetReciprocal()
  64. {
  65. return new Fraction(_isInLowestTerms, _denominator, _numerator);
  66. }
  67. public int GetIntegerPart()
  68. {
  69. return Numerator / Denominator;
  70. }
  71. public IEnumerable<int> GetFractionalPartEnumerator()
  72. {
  73. var remainder = (long)Numerator % Denominator;
  74. while (remainder > 0)
  75. {
  76. var newNumerator = (remainder > Denominator) ? remainder : remainder * 10;
  77. var digit = newNumerator / Denominator;
  78. yield return digit;
  79. remainder = (long)newNumerator % Denominator;
  80. }
  81. }
  82. #region Arithmetic Operators
  83. public static Fraction operator +(Fraction a, Fraction b)
  84. {
  85. var lcm = LeastCommonMultiple(a.Denominator, b.Denominator);
  86. var numerator = (a.Numerator * lcm) + (b.Numerator * lcm);
  87. var denominator = (a.Denominator * lcm) + (b.Denominator * lcm);
  88. return new Fraction(numerator, denominator, true);
  89. }
  90. public static Fraction operator -(Fraction a, Fraction b)
  91. {
  92. var lcm = LeastCommonMultiple(a.Denominator, b.Denominator);
  93. var numerator = (a.Numerator * lcm) - (b.Numerator * lcm);
  94. var denominator = (a.Denominator * lcm) - (b.Denominator * lcm);
  95. return new Fraction(numerator, denominator, true);
  96. }
  97. public static Fraction operator *(Fraction a, Fraction b)
  98. {
  99. return new Fraction(a.Numerator * b.Numerator, a.Denominator * b.Denominator);
  100. }
  101. public static Fraction operator /(Fraction a, Fraction b)
  102. {
  103. return a * b.GetReciprocal();
  104. }
  105. #endregion
  106. #region Conversion Operators
  107. public static explicit operator float(Fraction a)
  108. {
  109. return (float)a.Numerator / a.Denominator;
  110. }
  111. public static explicit operator double(Fraction a)
  112. {
  113. return (double)a.Numerator / a.Denominator;
  114. }
  115. public static explicit operator decimal(Fraction a)
  116. {
  117. return (decimal)a.Numerator / a.Denominator;
  118. }
  119. public static implicit operator Fraction(int a)
  120. {
  121. return new Fraction(true, a, 1);
  122. }
  123. #endregion
  124. #region Equality Operators
  125. public static bool operator ==(Fraction a, Fraction b)
  126. {
  127. return ((long)a.Numerator * b.Denominator) == ((long)a.Denominator * b.Numerator);
  128. }
  129. public static bool operator !=(Fraction a, Fraction b)
  130. {
  131. return !(a == b);
  132. }
  133. public static bool operator >(Fraction a, Fraction b)
  134. {
  135. return ((long)a.Numerator * b.Denominator) > ((long)a.Denominator * b.Numerator);
  136. }
  137. public static bool operator <(Fraction a, Fraction b)
  138. {
  139. return ((long)a.Numerator * b.Denominator) < ((long)a.Denominator * b.Numerator);
  140. }
  141. #endregion
  142. #region IComparable<Fraction> Implementation
  143. public int CompareTo(Fraction other)
  144. {
  145. return ((long)Numerator * b.Denominator) - ((long)Denominator * b.Numerator);
  146. }
  147. public int CompareTo(object obj)
  148. {
  149. throw new NotImplementedException();
  150. }
  151. #endregion
  152. public bool Equals(Fraction other)
  153. {
  154. return this == other;
  155. }
  156. #region Object overrides
  157. public override bool Equals(object obj)
  158. {
  159. if (obj == null || !(obj is Fraction)) return false;
  160. return Equals((Fraction)obj);
  161. }
  162. public override int GetHashCode()
  163. {
  164. return _numerator.GetHashCode() ^ _denominator.GetHashCode();
  165. }
  166. public override string ToString()
  167. {
  168. // TODO: Call ToString(string format) instead once it's written.
  169. return String.Format("{0}/{1}", _numerator, _denominator);
  170. }
  171. #endregion
  172. public byte[] GetBytes()
  173. {
  174. var bytes = new byte[8];
  175. var numerator = BitConverter.GetBytes(_numerator);
  176. Buffer.BlockCopy(numerator, 0, bytes, 0, numerator.Length);
  177. var denominator = BitConverter.GetBytes(_isInLowestTerms ? -_denominator : _denominator);
  178. Buffer.BlockCopy(denominator, 0, bytes, numerator.Length, denominator.Length);
  179. return bytes;
  180. }
  181. public static Fraction FromBytes(byte[] buffer, int offset)
  182. {
  183. throw new NotImplementedException();
  184. }
  185. public static int LeastCommonMultiple(int a, int b)
  186. {
  187. return LeastCommonMultiple(a, b, GreatestCommonDivisor(a, b));
  188. }
  189. public static int LeastCommonMultiple(int a, int b, int gcd)
  190. {
  191. return (a * b) / gcd;
  192. }
  193. public static int GreatestCommonDivisor(int dividend, int divisor)
  194. {
  195. var remainder = -1;
  196. while (remainder != 0)
  197. {
  198. int quotient = dividend / divisor;
  199. remainder = dividend % divisor;
  200. if (remainder != 0)
  201. {
  202. dividend = divisor;
  203. divisor = remainder;
  204. }
  205. }
  206. return divisor;
  207. }
  208. }
  209. }