1 //
2 // Rational.cs
3 //
4 // Authors:
5 //	Alexander Chebaturkin (chebaturkin@gmail.com)
6 //
7 // Copyright (C) 2012 Alexander Chebaturkin
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 
29 using System;
30 
31 using Mono.CodeContracts.Static.DataStructures;
32 
33 namespace Mono.CodeContracts.Static.Analysis.Numerical {
34         /// <summary>
35         /// Represents a rational number.
36         /// </summary>
37         public struct Rational : IEquatable<Rational> {
38                 public static readonly Rational Zero = new Rational (0L);
39                 public static readonly Rational One = new Rational (1L);
40                 public static readonly Rational MinusOne = new Rational (-1L);
41 
42                 public static Rational PlusInfinity = new Rational (Kind.PlusInfinity);
43                 public static Rational MinusInfinity = new Rational (Kind.MinusInfinity);
44 
45                 public static Rational MaxValue = new Rational (long.MaxValue);
46                 public static Rational MinValue = new Rational (long.MinValue);
47 
48                 readonly long down;
49                 readonly Kind kind;
50                 readonly long up;
51 
RationalMono.CodeContracts.Static.Analysis.Numerical.Rational52                 Rational (Kind kind)
53                 {
54                         if (kind == Kind.Normal)
55                                 throw new ArgumentException (
56                                         "Kind should be equal to Kind.PlusInfinity or Kind.MinusInfinity", "kind");
57 
58                         this.kind = kind;
59                         this.up = 0L;
60                         this.down = 0L;
61                 }
62 
RationalMono.CodeContracts.Static.Analysis.Numerical.Rational63                 Rational (long number)
64                         : this (number, 1L)
65                 {
66                 }
67 
RationalMono.CodeContracts.Static.Analysis.Numerical.Rational68                 Rational (long nominator, long denominator)
69                 {
70                         if (denominator == 0L)
71                                 throw new ArgumentException ("Denominator should not be equal to 0");
72 
73                         if (nominator == 0L) {
74                                 this.kind = Kind.Normal;
75                                 this.up = 0L;
76                                 this.down = 1L;
77 
78                                 return;
79                         }
80 
81                         this.kind = Kind.Normal;
82 
83                         int sign = System.Math.Sign (nominator) * System.Math.Sign (denominator);
84 
85                         if (nominator == long.MinValue)
86                                 nominator = sign >= 0 ? long.MaxValue : long.MinValue;
87                         else
88                                 nominator = sign * System.Math.Abs (nominator);
89 
90                         if (denominator == long.MinValue)
91                                 denominator = long.MaxValue;
92                         else
93                                 denominator = System.Math.Abs (denominator);
94 
95                         if (nominator % denominator == 0) {
96                                 this.up = nominator / denominator;
97                                 this.down = 1L;
98 
99                                 return;
100                         }
101 
102                         long gcd = (nominator == 0L || nominator == long.MaxValue ||
103                                     denominator == 0L || denominator == long.MaxValue)
104                                            ? 1L
105                                            : GCD (System.Math.Abs (nominator), System.Math.Abs (denominator));
106 
107                         this.up = nominator / gcd;
108                         this.down = denominator / gcd;
109                 }
110 
111                 public bool IsInteger { get { return !this.IsInfinity && (this.up % this.down == 0L); } }
112 
113                 public bool IsInt32 { get { return this.IsInteger && this.up >= int.MinValue && this.up <= int.MaxValue; } }
114 
115                 public bool IsInfinity { get { return this.kind == Kind.PlusInfinity || this.kind == Kind.MinusInfinity; } }
116                 public bool IsPlusInfinity { get { return this.kind == Kind.PlusInfinity; } }
117                 public bool IsMinusInfinity { get { return this.kind == Kind.MinusInfinity; } }
118 
119                 public bool IsZero { get { return this.kind == Kind.Normal && this.up == 0L; } }
120 
121                 public bool IsMaxValue { get { return this.kind == Kind.Normal && this.up == long.MaxValue && this.down == 1L; } }
122                 public bool IsMinValue { get { return this.kind == Kind.Normal && this.up == -long.MaxValue && this.down == 1L; } }
123 
124                 public int Sign { get { return GetSign (this); } }
125 
126                 public Rational NextInt32
127                 {
128                         get
129                         {
130                                 if (this.IsInfinity)
131                                         return this;
132                                 var next = (long) System.Math.Ceiling ((double) this);
133 
134                                 return For (next >= int.MaxValue ? int.MaxValue : next);
135                         }
136                 }
137 
138                 public Rational PreviousInt32
139                 {
140                         get
141                         {
142                                 if (this.IsInfinity)
143                                         return this;
144 
145                                 var prev = (long) System.Math.Floor ((double) this);
146 
147                                 return For (prev <= int.MinValue ? int.MinValue : prev);
148                         }
149                 }
150 
151                 public Rational NextInt64
152                 {
153                         get
154                         {
155                                 if (this.IsInfinity)
156                                         return this;
157                                 double next = System.Math.Ceiling ((double) this);
158 
159                                 return For (next >= (double) long.MaxValue ? long.MaxValue : (long) System.Math.Truncate (next));
160                         }
161                 }
162 
163                 public long Up { get { return up; } }
164                 public long Down { get { return down; } }
165 
IsInRangeMono.CodeContracts.Static.Analysis.Numerical.Rational166                 public bool IsInRange (long min, long max)
167                 {
168                         return min <= this && this <= max;
169                 }
170 
ForMono.CodeContracts.Static.Analysis.Numerical.Rational171                 public static Rational For (long number)
172                 {
173                         return new Rational (number);
174                 }
175 
ForMono.CodeContracts.Static.Analysis.Numerical.Rational176                 public static Rational For (long nominator, long denominator)
177                 {
178                         switch (denominator) {
179                                 case 0L:
180                                         return new Rational (nominator >= 0 ? Kind.PlusInfinity : Kind.MinusInfinity);
181                                 default:
182                                         return new Rational (nominator, denominator);
183                         }
184                 }
185 
operator ==Mono.CodeContracts.Static.Analysis.Numerical.Rational186                 public static bool operator == (Rational l, Rational r)
187                 {
188                         if (l.kind != r.kind)
189                                 return false;
190 
191                         if (l.kind != Kind.Normal)
192                                 return true;
193 
194                         return l.up == r.up && l.down == r.down;
195                 }
196 
operator !=Mono.CodeContracts.Static.Analysis.Numerical.Rational197                 public static bool operator != (Rational l, Rational r)
198                 {
199                         return !(l == r);
200                 }
201 
operator <Mono.CodeContracts.Static.Analysis.Numerical.Rational202                 public static bool operator < (Rational l, Rational r)
203                 {
204                         if (l.IsMinusInfinity && !r.IsMinusInfinity
205                             || r.IsPlusInfinity && !l.IsPlusInfinity)
206                                 return true;
207                         if (l.IsPlusInfinity || r.IsMinusInfinity)
208                                 return false;
209                         if (l.down == r.down)
210                                 return l.up < r.up;
211                         if (l.up <= 0L && r.up > 0L)
212                                 return true;
213                         if (l.up < 0L && r.up == 0L)
214                                 return true;
215 
216                         try {
217                                 return checked(l.up * r.down) < checked(r.up * l.down);
218                         }
219                         catch (ArithmeticException) {
220                                 return (decimal) l.up / l.down < (decimal) r.up / r.down;
221                         }
222                 }
223 
operator <=Mono.CodeContracts.Static.Analysis.Numerical.Rational224                 public static bool operator <= (Rational l, Rational r)
225                 {
226                         if (l.IsMinusInfinity || r.IsPlusInfinity)
227                                 return true;
228                         if (l.IsPlusInfinity || r.IsMinusInfinity)
229                                 return false;
230 
231                         if (l.down == r.down)
232                                 return l.up <= r.up;
233 
234                         try {
235                                 return checked(l.up * r.down) <= checked(r.up * l.down);
236                         }
237                         catch (ArithmeticException) {
238                                 return (decimal) l.up / l.down <= (decimal) r.up / r.down;
239                         }
240                 }
241 
operator >=Mono.CodeContracts.Static.Analysis.Numerical.Rational242                 public static bool operator >= (Rational l, Rational r)
243                 {
244                         return r <= l;
245                 }
246 
operator <=Mono.CodeContracts.Static.Analysis.Numerical.Rational247                 public static bool operator <= (Rational l, long r)
248                 {
249                         switch (l.kind) {
250                                 case Kind.PlusInfinity:
251                                         return false;
252                                 case Kind.MinusInfinity:
253                                         return true;
254                                 default:
255                                         try {
256                                                 return l.up <= checked(l.down * r);
257                                         }
258                                         catch (ArithmeticException) {
259                                                 return (decimal) l.up / l.down <= r;
260                                         }
261                         }
262                 }
263 
operator <=Mono.CodeContracts.Static.Analysis.Numerical.Rational264                 public static bool operator <= (long l, Rational r)
265                 {
266                         switch (r.kind) {
267                                 case Kind.PlusInfinity:
268                                         return true;
269                                 case Kind.MinusInfinity:
270                                         return false;
271                                 default:
272                                         try {
273                                                 return r.up >= checked(r.down * l);
274                                         }
275                                         catch (ArithmeticException) {
276                                                 return (decimal) r.up / r.down >= l;
277                                         }
278                         }
279                 }
280 
operator >=Mono.CodeContracts.Static.Analysis.Numerical.Rational281                 public static bool operator >= (long l, Rational r)
282                 {
283                         return r <= l;
284                 }
285 
operator >=Mono.CodeContracts.Static.Analysis.Numerical.Rational286                 public static bool operator >= (Rational l, long r)
287                 {
288                         return r <= l;
289                 }
290 
operator >Mono.CodeContracts.Static.Analysis.Numerical.Rational291                 public static bool operator > (Rational l, Rational r)
292                 {
293                         return r < l;
294                 }
295 
operator <Mono.CodeContracts.Static.Analysis.Numerical.Rational296                 public static bool operator < (Rational l, long r)
297                 {
298                         switch (l.kind) {
299                                 case Kind.PlusInfinity:
300                                         return false;
301                                 case Kind.MinusInfinity:
302                                         return true;
303                                 default:
304                                         try {
305                                                 return l.up < checked(r * l.down);
306                                         }
307                                         catch {
308                                                 return (decimal) l.up / l.down < r;
309                                         }
310                         }
311                 }
312 
operator >Mono.CodeContracts.Static.Analysis.Numerical.Rational313                 public static bool operator > (Rational l, long r)
314                 {
315                         return r < l;
316                 }
317 
operator <Mono.CodeContracts.Static.Analysis.Numerical.Rational318                 public static bool operator < (long l, Rational r)
319                 {
320                         switch (r.kind) {
321                                 case Kind.PlusInfinity:
322                                         return true;
323                                 case Kind.MinusInfinity:
324                                         return false;
325                                 default:
326                                         try {
327                                                 return checked(l * r.down) < r.up;
328                                         }
329                                         catch {
330                                                 return l < (decimal) r.up / r.down;
331                                         }
332                         }
333                 }
334 
operator >Mono.CodeContracts.Static.Analysis.Numerical.Rational335                 public static bool operator > (long l, Rational r)
336                 {
337                         return r < l;
338                 }
339 
operator +Mono.CodeContracts.Static.Analysis.Numerical.Rational340                 public static Rational operator + (Rational l, Rational r)
341                 {
342                         Rational result;
343                         if (TryAdd (l, r, out result))
344                                 return result;
345 
346                         throw new ArithmeticException ();
347                 }
348 
operator -Mono.CodeContracts.Static.Analysis.Numerical.Rational349                 public static Rational operator - (Rational l, Rational r)
350                 {
351                         Rational result;
352                         if (TrySubtract (l, r, out result))
353                                 return result;
354 
355                         throw new ArithmeticException ();
356                 }
357 
operator *Mono.CodeContracts.Static.Analysis.Numerical.Rational358                 public static Rational operator * (Rational l, Rational r)
359                 {
360                         Rational result;
361                         if (TryMultiply (l, r, out result))
362                                 return result;
363 
364                         throw new ArithmeticException ();
365                 }
366 
operator /Mono.CodeContracts.Static.Analysis.Numerical.Rational367                 public static Rational operator / (Rational l, Rational r)
368                 {
369                         Rational result;
370                         if (TryDivide (l, r, out result))
371                                 return result;
372 
373                         throw new ArithmeticException ();
374                 }
375 
operator -Mono.CodeContracts.Static.Analysis.Numerical.Rational376                 public static Rational operator - (Rational l, long i)
377                 {
378                         if (l.kind == Kind.Normal && l.down == 1L)
379                                 try {
380                                         return For (checked(l.up - i));
381                                 }
382                                 catch (ArithmeticException) {
383                                 }
384 
385                         return l - For (i);
386                 }
387 
operator +Mono.CodeContracts.Static.Analysis.Numerical.Rational388                 public static Rational operator + (Rational l, long i)
389                 {
390                         if (l.kind == Kind.Normal && l.down == 1L)
391                                 try {
392                                         return For (checked(l.up + i));
393                                 }
394                                 catch (ArithmeticException) {
395                                 }
396 
397                         return l + For (i);
398                 }
399 
operator -Mono.CodeContracts.Static.Analysis.Numerical.Rational400                 public static Rational operator - (Rational value)
401                 {
402                         Rational result;
403                         if (TryUnaryMinus (value, out result))
404                                 return result;
405 
406                         throw new ArithmeticException ();
407                 }
408 
operator doubleMono.CodeContracts.Static.Analysis.Numerical.Rational409                 public static explicit operator double (Rational r)
410                 {
411                         switch (r.kind) {
412                                 case Kind.PlusInfinity:
413                                         return double.PositiveInfinity;
414                                 case Kind.MinusInfinity:
415                                         return double.NegativeInfinity;
416                                 default:
417                                         return (double) r.up / r.down;
418                         }
419                 }
420 
operator longMono.CodeContracts.Static.Analysis.Numerical.Rational421                 public static explicit operator long (Rational r)
422                 {
423                         if (r.down == 0L)
424                                 return r.up >= 0L ? long.MaxValue : long.MinValue;
425 
426                         if (!r.IsInteger)
427                                 return (long) System.Math.Round ((double) r.up / r.down);
428 
429                         return r.up;
430                 }
431 
operator intMono.CodeContracts.Static.Analysis.Numerical.Rational432                 public static explicit operator int (Rational r)
433                 {
434                         if (r.down != 0L)
435                                 return (int) System.Math.Round ((double) r.up / r.down);
436 
437                         return r.up >= 0L ? int.MaxValue : int.MinValue;
438                 }
439 
operator RationalMono.CodeContracts.Static.Analysis.Numerical.Rational440                 public static implicit operator Rational (long l)
441                 {
442                         return For (l);
443                 }
444 
AbsMono.CodeContracts.Static.Analysis.Numerical.Rational445                 public static Rational Abs (Rational a)
446                 {
447                         switch (a.kind) {
448                                 case Kind.PlusInfinity:
449                                 case Kind.MinusInfinity:
450                                         return PlusInfinity;
451                                 default:
452                                         return a.IsZero || a > 0L ? a : -a;
453                         }
454                 }
455 
MaxMono.CodeContracts.Static.Analysis.Numerical.Rational456                 public static Rational Max (Rational a, Rational b)
457                 {
458                         return a < b ? b : a;
459                 }
460 
MinMono.CodeContracts.Static.Analysis.Numerical.Rational461                 public static Rational Min (Rational a, Rational b)
462                 {
463                         return a < b ? a : b;
464                 }
465 
TryAddMono.CodeContracts.Static.Analysis.Numerical.Rational466                 public static bool TryAdd (Rational l, Rational r, out Rational result)
467                 {
468                         if (l.IsZero)
469                                 return true.With (r, out result);
470 
471                         if (r.IsZero || l.IsInfinity)
472                                 return true.With (l, out result);
473 
474                         if (r.IsInfinity)
475                                 return true.With (r, out result);
476 
477                         if (l.IsMaxValue && r > 0L || r.IsMaxValue && l > 0L)
478                                 return true.With (PlusInfinity, out result);
479 
480                         long nom;
481                         long denom;
482                         try {
483                                 if (l.down == r.down) {
484                                         if (l.up == r.up && (r.down & 1L) == 0L) {
485                                                 nom = l.up;
486                                                 denom = l.down >> 1;
487                                         }
488                                         else {
489                                                 nom = checked (l.up + r.up);
490                                                 denom = l.down;
491                                         }
492                                 }
493                                 else {
494                                         nom = checked (l.up * r.down + r.up * l.down);
495                                         denom = checked (l.down * r.down);
496                                 }
497                         }
498                         catch (ArithmeticException) {
499                                 try {
500                                         long gcd = GCD (l.down, r.down);
501                                         nom =
502                                                 checked (
503                                                         l.up * unchecked (r.down / gcd) +
504                                                         r.up * unchecked (l.down / gcd));
505                                         denom = checked ((l.down / gcd) * r.down);
506                                 }
507                                 catch (ArithmeticException) {
508                                         return false.Without (out result);
509                                 }
510                         }
511 
512                         return true.With (denom == 1L ? For (nom) : For (nom, denom), out result);
513                 }
514 
TrySubtractMono.CodeContracts.Static.Analysis.Numerical.Rational515                 public static bool TrySubtract (Rational l, Rational r, out Rational result)
516                 {
517                         if (r.IsZero)
518                                 return true.With (l, out result);
519 
520                         if (l.IsZero)
521                                 return true.With (-r, out result);
522 
523                         if (l == r)
524                                 return true.With (Zero, out result);
525 
526                         if (r < 0L && !r.IsMinValue)
527                                 return TryAdd (l, Abs (r), out result);
528 
529                         if (l.IsInfinity)
530                                 return true.With (l, out result);
531 
532                         if (r.IsInfinity)
533                                 return true.With (-r, out result);
534 
535                         if (l.IsMinValue && r > 0L)
536                                 return true.With (MinusInfinity, out result);
537 
538                         long nom;
539                         long denom;
540                         try {
541                                 if (l.down == r.down) {
542                                         nom = checked (l.up - r.up);
543                                         denom = l.down;
544                                 }
545                                 else {
546                                         nom = checked (l.up * r.down - r.up * l.down);
547                                         denom = checked (l.down * r.down);
548                                 }
549                         }
550                         catch (ArithmeticException) {
551                                 return false.Without (out result);
552                         }
553 
554                         return true.With (For (nom, denom), out result);
555                 }
556 
TryDivideMono.CodeContracts.Static.Analysis.Numerical.Rational557                 public static bool TryDivide (Rational l, Rational r, out Rational result)
558                 {
559                         if (r == One)
560                                 return true.With (l, out result);
561 
562                         if (r.IsZero)
563                                 return false.Without (out result);
564 
565                         if (l.IsZero || r.IsInfinity)
566                                 return true.With (Zero, out result);
567 
568                         if (l.IsPlusInfinity)
569                                 return true.With (r.Sign > 0 ? PlusInfinity : MinusInfinity, out result);
570 
571                         if (l.IsMinusInfinity)
572                                 return true.With (r.Sign > 0 ? MinusInfinity : PlusInfinity, out result);
573 
574                         long nom;
575                         long denom;
576 
577                         if (l.up == r.up) {
578                                 // (a/b)/(a/c) = (c/b)
579 
580                                 nom = r.down;
581                                 denom = l.down;
582                         }
583                         else if (l.down == r.down) {
584                                 // (a/c)/(b/c) = (a/b)
585 
586                                 nom = l.up;
587                                 denom = r.up;
588                         }
589                         else {
590                                 // (x/y) / (e/f) == (x/e) * (f/y)
591 
592                                 Rational a = For (l.up, r.up);
593                                 Rational b = For (r.down, l.down);
594 
595                                 try {
596                                         return TryMultiply (a, b, out result);
597                                 }
598                                 catch (ArithmeticException) {
599                                         return false.Without (out result);
600                                 }
601                         }
602 
603                         return true.With (For (nom, denom), out result);
604                 }
605 
TryMultiplyMono.CodeContracts.Static.Analysis.Numerical.Rational606                 public static bool TryMultiply (Rational l, Rational r, out Rational result)
607                 {
608                         if (l.IsZero || r.IsZero)
609                                 return true.With (Zero, out result);
610 
611                         if (l == One)
612                                 return true.With (r, out result);
613                         if (r == One)
614                                 return true.With (l, out result);
615 
616                         if (l.IsPlusInfinity) {
617                                 if (r.IsPlusInfinity)
618                                         result = PlusInfinity;
619                                 else if (r.IsMinusInfinity)
620                                         result = MinusInfinity;
621                                 else if (r.IsZero)
622                                         result = Zero;
623                                 else
624                                         result = r.Sign > 0 ? PlusInfinity : MinusInfinity;
625 
626                                 return true;
627                         }
628 
629                         if (l.IsMinusInfinity) {
630                                 if (r.IsPlusInfinity)
631                                         result = MinusInfinity;
632                                 else if (r.IsMinusInfinity)
633                                         result = PlusInfinity;
634                                 else if (r.IsZero)
635                                         result = Zero;
636                                 else
637                                         result = r.Sign > 0 ? MinusInfinity : PlusInfinity;
638 
639                                 return true;
640                         }
641 
642                         if (r.IsPlusInfinity) {
643                                 if (l.IsZero)
644                                         result = Zero;
645                                 else
646                                         result = l.Sign > 0 ? PlusInfinity : MinusInfinity;
647 
648                                 return true;
649                         }
650 
651                         if (r.IsMinusInfinity) {
652                                 if (l.IsZero)
653                                         result = Zero;
654                                 else
655                                         result = l.Sign > 0 ? MinusInfinity : PlusInfinity;
656 
657                                 return true;
658                         }
659 
660                         long nom;
661                         long denom;
662 
663                         try {
664                                 Rational a = For (l.up, r.down);
665                                 Rational b = For (r.up, l.down);
666 
667                                 nom = checked(a.up * b.up);
668                                 denom = checked(a.down * b.down);
669                         }
670                         catch (ArithmeticException) {
671                                 return false.Without (out result);
672                         }
673 
674                         return true.With (For (nom, denom), out result);
675                 }
676 
TryUnaryMinusMono.CodeContracts.Static.Analysis.Numerical.Rational677                 public static bool TryUnaryMinus (Rational value, out Rational result)
678                 {
679                         if (value.IsZero)
680                                 return true.With (value, out result);
681 
682                         switch (value.kind) {
683                                 case Kind.PlusInfinity:
684                                         return true.With (MinusInfinity, out result);
685                                 case Kind.MinusInfinity:
686                                         return true.With (PlusInfinity, out result);
687                         }
688 
689                         if (value.IsMinValue)
690                                 return true.With (MaxValue, out result);
691                         if (value.IsMaxValue)
692                                 return true.With (MinValue, out result);
693 
694                         return true.With (For (-value.up, value.down), out result);
695                 }
696 
GetSignMono.CodeContracts.Static.Analysis.Numerical.Rational697                 static int GetSign (Rational r)
698                 {
699                         switch (r.kind) {
700                                 case Kind.PlusInfinity:
701                                         return 1;
702                                 case Kind.MinusInfinity:
703                                         return -1;
704                                 default:
705                                         return System.Math.Sign (r.up) * System.Math.Sign (r.down);
706                         }
707                 }
708 
GCDMono.CodeContracts.Static.Analysis.Numerical.Rational709                 static long GCD (long a, long b)
710                 {
711                         var aa = (ulong) a;
712                         var bb = (ulong) b;
713 
714                         int pow = 0;
715 
716                         while (((aa | bb) & 1L) == 0L) //while both divide by 2
717                         {
718                                 aa >>= 1;
719                                 bb >>= 1;
720                                 ++pow;
721                         }
722 
723                         while ((aa & 1L) == 0L) //get rid of other 2's factors
724                                 aa >>= 1;
725 
726                         do {
727                                 while ((bb & 1L) == 0L)
728                                         bb >>= 1;
729 
730                                 ulong cc;
731                                 if (aa < bb)
732                                         cc = bb - aa;
733                                 else {
734                                         ulong tmp = aa - bb;
735                                         aa = bb;
736                                         cc = tmp;
737                                 }
738 
739                                 bb = cc >> 1;
740                         } while (bb != 0L);
741 
742                         return (long) aa << pow;
743                 }
744 
EqualsMono.CodeContracts.Static.Analysis.Numerical.Rational745                 public override bool Equals (object obj)
746                 {
747                         if (ReferenceEquals (null, obj))
748                                 return false;
749                         if (ReferenceEquals (this, obj))
750                                 return true;
751                         return obj is Rational && this.Equals ((Rational) obj);
752                 }
753 
EqualsMono.CodeContracts.Static.Analysis.Numerical.Rational754                 public bool Equals (Rational other)
755                 {
756                         return this == other;
757                 }
758 
GetHashCodeMono.CodeContracts.Static.Analysis.Numerical.Rational759                 public override int GetHashCode ()
760                 {
761                         unchecked {
762                                 int hashCode = this.kind.GetHashCode ();
763                                 hashCode = (hashCode * 397) ^ this.up.GetHashCode ();
764                                 hashCode = (hashCode * 1001) ^ this.down.GetHashCode ();
765                                 return hashCode;
766                         }
767                 }
768 
ToStringMono.CodeContracts.Static.Analysis.Numerical.Rational769                 public override string ToString ()
770                 {
771                         switch (this.kind) {
772                                 case Kind.MinusInfinity:
773                                         return "-oo" +
774                                                (this.up == -1L || this.down == 0L
775                                                         ? ""
776                                                         : string.Format ("({0} / {1})", this.up, this.down));
777                                 case Kind.PlusInfinity:
778                                         return "+oo" +
779                                                (this.up == 1L || this.down == 0L
780                                                         ? ""
781                                                         : string.Format ("({0} / {1})", this.up, this.down));
782                                 default:
783                                         return this.IsInteger
784                                                        ? this.up.ToString ()
785                                                        : string.Format ("({0} / {1})", this.up, this.down);
786                         }
787                 }
788 
789                 enum Kind {
790                         Normal,
791                         PlusInfinity,
792                         MinusInfinity,
793                 }
794         }
795 
796         static class RationalExtensions {
ToExpression(this Rational value, IExpressionEncoder<TVar, TExpr> encoder )797                 public static TExpr ToExpression<TVar, TExpr>(this Rational value, IExpressionEncoder<TVar, TExpr> encoder )
798                 {
799                         if (value.IsInteger)
800                                 return encoder.ConstantFor ((long) value);
801                         if (value.IsPlusInfinity)
802                                 return encoder.CompoundFor (ExpressionType.Int32, ExpressionOperator.Div,
803                                                             encoder.ConstantFor (1L), encoder.ConstantFor (0L));
804                         if (value.IsMinusInfinity)
805                                 return encoder.CompoundFor (ExpressionType.Int32, ExpressionOperator.Div,
806                                                             encoder.ConstantFor (-1L), encoder.ConstantFor (0L));
807 
808                         TExpr l = encoder.ConstantFor (value.Up);
809                         TExpr r = encoder.ConstantFor (value.Down);
810 
811                         return encoder.CompoundFor (ExpressionType.Int32, ExpressionOperator.Div, l, r);
812                 }
813         }
814 }
815