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