fraction.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // FIXME: Check the operators' names
  2. // FIXME: This class should probably be immutable?
  3. export class Fraction {
  4. private static maximumAllowedNumber: number = 46340;
  5. private numerator: number = 0;
  6. private denominator: number = 1;
  7. private realValue: number;
  8. public static max(f1: Fraction, f2: Fraction): Fraction {
  9. if (f1.RealValue > f2.RealValue) {
  10. return f1;
  11. } else {
  12. return f2;
  13. }
  14. }
  15. public static Equal(f1: Fraction, f2: Fraction): boolean {
  16. // FIXME
  17. return f1.Denominator === f2.Denominator && f1.Numerator === f2.Numerator;
  18. }
  19. public static createFromFraction(fraction: Fraction): Fraction {
  20. return new Fraction(fraction.numerator, fraction.denominator);
  21. }
  22. public static plus (f1: Fraction, f2: Fraction): Fraction {
  23. let sum: Fraction = f1.clone();
  24. sum.Add(f2);
  25. return sum;
  26. }
  27. public static minus(f1: Fraction , f2: Fraction): Fraction {
  28. let sum: Fraction = f1.clone();
  29. sum.Sub(f2);
  30. return sum;
  31. }
  32. private static greatestCommonDenominator(a: number, b: number): number {
  33. if (a === 0) {
  34. return b;
  35. }
  36. if (b === 1) {
  37. return 1;
  38. }
  39. while (b !== 0) {
  40. if (a > b) {
  41. a -= b;
  42. } else {
  43. b -= a;
  44. }
  45. }
  46. return a;
  47. }
  48. constructor(numerator: number = 0, denominator: number = 1, simplify: boolean = true) {
  49. this.numerator = numerator;
  50. this.denominator = denominator;
  51. if (simplify) { this.simplify(); }
  52. this.setRealValue();
  53. }
  54. public toString(): string {
  55. return this.numerator + "/" + this.denominator;
  56. }
  57. public clone(): Fraction {
  58. return new Fraction(this.numerator, this.denominator, false);
  59. }
  60. public get Numerator(): number {
  61. return this.numerator;
  62. }
  63. public set Numerator(value: number) {
  64. if (this.numerator !== value) {
  65. this.numerator = value;
  66. this.simplify();
  67. this.setRealValue();
  68. }
  69. }
  70. public get Denominator(): number {
  71. return this.denominator;
  72. }
  73. public set Denominator(value: number) {
  74. if (this.denominator !== value) {
  75. this.denominator = value;
  76. if (this.numerator !== 0) {
  77. this.simplify();
  78. }
  79. this.setRealValue();
  80. }
  81. }
  82. public get RealValue(): number {
  83. return this.realValue;
  84. }
  85. public multiplyWithFactor(factor: number): void {
  86. this.numerator *= factor;
  87. this.denominator *= factor;
  88. }
  89. public multiplyDenominatorWithFactor(factor: number): void {
  90. this.denominator *= factor;
  91. this.setRealValue();
  92. }
  93. public Add(fraction: Fraction): void {
  94. this.numerator = this.numerator * fraction.denominator + fraction.numerator * this.denominator;
  95. this.denominator = this.denominator * fraction.denominator;
  96. this.simplify();
  97. this.setRealValue();
  98. }
  99. public Sub(fraction: Fraction): void {
  100. this.numerator = this.numerator * fraction.denominator - fraction.numerator * this.denominator;
  101. this.denominator = this.denominator * fraction.denominator;
  102. this.simplify();
  103. this.setRealValue();
  104. }
  105. public Quantize(maxAllowedDenominator: number): Fraction {
  106. if (this.denominator <= maxAllowedDenominator) {
  107. return this;
  108. }
  109. let upTestFraction: Fraction = new Fraction(this.numerator + 1, this.denominator);
  110. while (upTestFraction.Denominator > maxAllowedDenominator) {
  111. upTestFraction.Numerator++;
  112. }
  113. if (this.numerator > this.denominator) {
  114. let downTestFraction: Fraction = new Fraction(this.numerator - 1, this.denominator);
  115. while (downTestFraction.Denominator > maxAllowedDenominator) {
  116. downTestFraction.Numerator--;
  117. }
  118. if (downTestFraction.Denominator < upTestFraction.Denominator) {
  119. return downTestFraction;
  120. }
  121. }
  122. return upTestFraction;
  123. }
  124. public Equals(obj: Fraction): boolean {
  125. return this.RealValue === obj.RealValue;
  126. }
  127. public CompareTo(obj: Fraction): number {
  128. let diff: number = this.numerator * obj.Denominator - this.denominator * obj.Numerator;
  129. // Return the sign of diff
  130. return diff ? diff < 0 ? -1 : 1 : 0;
  131. }
  132. public lt(frac: Fraction): boolean {
  133. return (this.numerator * frac.Denominator - this.denominator * frac.Numerator) < 0;
  134. }
  135. public lte(frac: Fraction): boolean {
  136. return (this.numerator * frac.Denominator - this.denominator * frac.Numerator) <= 0;
  137. }
  138. //public Equals(f: Fraction): boolean {
  139. // if (ReferenceEquals(this, f))
  140. // return true;
  141. // if (ReferenceEquals(f, undefined))
  142. // return false;
  143. // return <number>this.numerator * f.denominator === <number>f.numerator * this.denominator;
  144. //}
  145. public GetInversion(): Fraction {
  146. return new Fraction(this.denominator, this.numerator);
  147. }
  148. private setRealValue(): void {
  149. this.realValue = this.numerator / this.denominator;
  150. }
  151. private simplify(): void {
  152. if (this.numerator === 0) {
  153. this.denominator = 1;
  154. return;
  155. }
  156. let i: number = Fraction.greatestCommonDenominator(Math.abs(this.numerator), Math.abs(this.denominator));
  157. this.numerator /= i;
  158. this.denominator /= i;
  159. if (this.denominator > Fraction.maximumAllowedNumber) {
  160. let factor: number = this.denominator / Fraction.maximumAllowedNumber;
  161. this.numerator = Math.round(this.numerator / factor);
  162. this.denominator = Math.round(this.denominator / factor);
  163. }
  164. if (this.numerator > Fraction.maximumAllowedNumber) {
  165. let factor: number = this.numerator / Fraction.maximumAllowedNumber;
  166. this.numerator = Math.round(this.numerator / factor);
  167. this.denominator = Math.round(this.denominator / factor);
  168. }
  169. }
  170. //private static equals(f1: Fraction, f2: Fraction): boolean {
  171. // return <number>f1.numerator * f2.denominator === <number>f2.numerator * f1.denominator;
  172. //}
  173. //
  174. //public static ApproximateFractionFromValue(value: number, epsilonForPrecision: number): Fraction {
  175. // let n: number = 1;
  176. // let d: number = 1;
  177. // let fraction: number = n / d;
  178. // while (Math.abs(fraction - value) > epsilonForPrecision) {
  179. // if (fraction < value) {
  180. // n++;
  181. // }
  182. // else {
  183. // d++;
  184. // n = <number>Math.round(value * d);
  185. // }
  186. // fraction = n / <number>d;
  187. // }
  188. // return new Fraction(n, d);
  189. //}
  190. //public static GetEarlierTimestamp(m1: Fraction, m2: Fraction): Fraction {
  191. // if (m1 < m2)
  192. // return m1;
  193. // else return m2;
  194. //}
  195. //public static getFraction(value: number, denominatorPrecision: number): Fraction {
  196. // let numerator: number = <number>Math.round(value / (1.0 / denominatorPrecision));
  197. // return new Fraction(numerator, denominatorPrecision);
  198. //}
  199. //public static fractionMin(f1: Fraction, f2: Fraction): Fraction {
  200. // if (f1 < f2)
  201. // return f1;
  202. // else return f2;
  203. //}
  204. //public static GetMaxValue(): Fraction {
  205. // return new Fraction(Fraction.maximumAllowedNumber, 1);
  206. //}
  207. //public static get MaxAllowedNumerator(): number {
  208. // return Fraction.maximumAllowedNumber;
  209. //}
  210. //public static get MaxAllowedDenominator(): number {
  211. // return Fraction.maximumAllowedNumber;
  212. //}
  213. //public ToFloatingString(): string {
  214. // return this.RealValue.ToString();
  215. //}
  216. //public Compare(x: Fraction, y: Fraction): number {
  217. // if (x > y)
  218. // return 1;
  219. // if (x < y)
  220. // return -1;
  221. // return 0;
  222. //}
  223. //#region operators
  224. //
  225. // // operator overloads must always come in pairs
  226. // // operator overload +
  227. // public static Fraction operator + (Fraction f1, Fraction f2)
  228. //{
  229. // Fraction sum = new Fraction(f1);
  230. // sum.Add(f2);
  231. // return sum;
  232. //}
  233. //
  234. //// operator overload -
  235. //public static Fraction operator - (Fraction f1, Fraction f2)
  236. //{
  237. // Fraction diff = new Fraction(f1);
  238. // diff.Sub(f2);
  239. // return diff;
  240. //}
  241. //
  242. //// operator overloads must always come in pairs
  243. //// operator overload >
  244. //public static bool operator > (Fraction f1, Fraction f2)
  245. //{
  246. // //return (long) f1.Numerator*f2._denominator > (long) f2._numerator*f1._denominator;
  247. // return f1.RealValue > f2.RealValue;
  248. //}
  249. //
  250. //// operator overload <
  251. //public static bool operator < (Fraction f1, Fraction f2)
  252. //{
  253. // //return (long) f1._numerator*f2._denominator < (long) f2._numerator*f1._denominator;
  254. // return f1.RealValue < f2.RealValue;
  255. //}
  256. //
  257. //// operator overload ==
  258. //public static bool operator === (Fraction f1, Fraction f2)
  259. //{
  260. // // code enhanced for performance
  261. // // System.Object.ReferenceEquals(f1, undefined) is better than if (f1 === undefined)
  262. // // and comparisons between booleans are quick
  263. // bool f1IsNull = System.Object.ReferenceEquals(f1, undefined);
  264. // bool f2IsNull = System.Object.ReferenceEquals(f2, undefined);
  265. //
  266. // // method returns true when both are undefined, false when only the first is undefined, otherwise the result of equals
  267. // if (f1IsNull !== f2IsNull)
  268. // return false;
  269. //
  270. // if (f1IsNull /*&& f2IsNull*/)
  271. // return true;
  272. //
  273. // return equals(f1, f2);
  274. //}
  275. //
  276. //// operator overload !=
  277. //public static bool operator !== (Fraction f1, Fraction f2)
  278. //{
  279. // return (!(f1 === f2));
  280. //}
  281. //
  282. //// operator overload >=
  283. //public static bool operator >= (Fraction f1, Fraction f2)
  284. //{
  285. // return (!(f1 < f2));
  286. //}
  287. //
  288. //// operator overload <=
  289. //public static bool operator <= (Fraction f1,Fraction f2)
  290. //{
  291. // return (!(f1 > f2));
  292. //}
  293. //
  294. //public static Fraction operator / (Fraction f, int i)
  295. //{
  296. // return new Fraction(f._numerator, f._denominator *= i);
  297. //}
  298. //
  299. //public static Fraction operator / (Fraction f1, Fraction f2)
  300. //{
  301. // let res = new Fraction(f1.Numerator*f2.Denominator, f1.Denominator*f2.Numerator);
  302. // return res.Denominator === 0 ? new Fraction(0, 1) : res;
  303. //}
  304. //
  305. //public static Fraction operator * (Fraction f1, Fraction f2)
  306. //{
  307. // return new Fraction(f1.Numerator*f2.Numerator, f1.Denominator*f2.Denominator);
  308. //}
  309. //
  310. //public static Fraction operator % (Fraction f1, Fraction f2)
  311. //{
  312. // let a = f1/f2;
  313. // return new Fraction(a.Numerator%a.Denominator, a.Denominator)*f2;
  314. //}
  315. //
  316. //#endregion operators
  317. }