1 /** This module contains an implementation of rational numbers that is templated
2  * on the underlying integer type.  It can be used with either builtin fixed
3  * width integers or arbitrary precision integers.  All relevant operators are
4  * overloaded for both rational-rational and rational-integer operations.
5  *
6  * Synopsis:
7  * ---
8  * // Compute pi using the generalized continued fraction approximation.
9  * import std.bigint, std.rational, std.stdio;
10  *
11  * enum maxTerm = 30;
12  *
13  * Rational!(BigInt) getTerm(int termNumber)
14  * {
15  *     auto addFactor = 2 * termNumber - 1;
16  *
17  *     if (termNumber == maxTerm)
18  *     {
19  *         return rational(BigInt(addFactor));
20  *     }
21  *
22  *     auto termNumberSquared = BigInt(termNumber * termNumber);
23  *     auto continued = termNumberSquared / getTerm(termNumber + 1);
24  *
25  *     continued += addFactor;
26  *     return continued;
27  * }
28  *
29  * void main()
30  * {
31  *     auto pi = rational(BigInt(4)) / getTerm(1);
32  *
33  *     // Display the result in rational form.
34  *     writeln(pi);
35  *
36  *     // Display the decimal equivalent, which is accurate to 18 decimal places.
37  *     writefln("%.18f", cast(real) pi);
38  * }
39  * ---
40  *
41  *
42  * Author:  David Simcha
43  * Copyright:  Copyright (c) 2009-2011, David Simcha.
44  * License:    $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
45  */
46 module nxt.rational;
47 
48 import std.conv : to;
49 import std.math : abs;
50 
51 /** Checks whether $(D T) is structurally an integer, i.e. whether it supports
52  * all of the operations an integer type should support.  Does not check the
53  * nominal type of $(D T).  In particular, for a mutable type $(D T) the
54  * following must compile:
55  *
56  * ---
57  * T n;
58  * n = 2;
59  * n <<= 1;
60  * n >>= 1;
61  * n += n;
62  * n += 2;
63  * n *= n;
64  * n *= 2;
65  * n /= n;
66  * n /= 2;
67  * n -= n;
68  * n -= 2;
69  * n %= 2;
70  * n %= n;
71  * bool foo = n < 2;
72  * bool bar = n == 2;
73  * bool goo = n < n + 1;
74  * bool tar = n == n;
75  * ---
76  *
77  * while for a non-mutable type, the above must compile for its unqualified,
78  * mutable variant.
79  *
80  * All built-in D integers and character types and $(XREF bigint, BigInt) are
81  * integer-like by this definition.
82  */
83 template isIntegerLike(T)
84 {
85     import std.traits : isMutable;
86     static if (isMutable!T)
87     {
88         import std.traits : isIntegral, isSomeChar, isArray, isFloatingPoint;
89         static if (isIntegral!T ||
90                    isSomeChar!T)
91         {
92             enum isIntegerLike = true;
93         }
94         else static if (isFloatingPoint!T ||
95                         is(T == bool) ||
96                         isArray!T)
97         {
98             enum isIntegerLike = false;
99         }
100         else
101         {
102             enum isIntegerLike = is(typeof(
103             {
104                 T n;
105                 n = 2;
106                 n = n;
107                 n <<= 1;
108                 n >>= 1;
109                 n += n;
110                 n += 2;
111                 n *= n;
112                 n *= 2;
113                 n /= n;
114                 n /= 2;
115                 n -= n;
116                 n -= 2;
117                 n %= 2;
118                 n %= n;
119                 // TODO: what about ^^= ?
120                 bool lt = n < 2; // less than
121                 bool eq = n == 2; // equal to literal
122                 bool ltg = n < n + 1;
123                 bool seq = n == n; // reflexive equal
124                 return n;
125             }));
126         }
127     }
128     else
129     {
130         import core.internal.traits : Unqual;
131         alias isIntegerLike = isIntegerLike!(Unqual!T);
132     }
133 }
134 
135 @safe pure nothrow @nogc unittest
136 {
137     import std.bigint : BigInt;
138     import std.meta : AliasSeq;
139     foreach (T; AliasSeq!(BigInt,
140                           long, ulong, int, uint,
141                           short, ushort, byte, ubyte,
142                           char, wchar, dchar))
143     {
144         static assert(isIntegerLike!T);
145         static assert(isIntegerLike!(const(T)));
146         static assert(isIntegerLike!(immutable(T)));
147     }
148 
149     foreach (T; AliasSeq!(real, double, float, bool))
150     {
151         static assert(!isIntegerLike!T);
152         static assert(!isIntegerLike!(const(T)));
153         static assert(!isIntegerLike!(immutable(T)));
154     }
155 }
156 
157 /** Checks if $(D T) has the basic properties of a rational type, i.e.  it has a
158  * numerator and a denominator.
159  */
160 enum isRational(T) = (is(typeof(T.init.numerator)) && // TODO: faster to use hasMember? TODO: check that member `isIntegerLike`?
161                       is(typeof(T.init.denominator))); // TODO: faster to use hasMember? TODO: check that member `isIntegerLike`?
162 
163 /** Returns a Common Integral Type between $(D I1) and $(D I2).  This is defined
164  * as the type returned by I1.init * I2.init.
165  */
166 private template CommonInteger(I1, I2)
167 if (isIntegerLike!I1 &&
168     isIntegerLike!I2)
169 {
170     import core.internal.traits : Unqual;
171     alias CommonInteger = typeof(Unqual!(I1).init *
172                                  Unqual!(I2).init);
173 }
174 
175 @safe pure nothrow @nogc unittest
176 {
177     import std.bigint : BigInt;
178     static assert(is(CommonInteger!(BigInt, int) == BigInt));
179     static assert(is(CommonInteger!(byte, int) == int));
180 }
181 
182 /** Returns a Common Rational Type between $(D R1) and $(D R2), which will be a
183  * Rational based on the CommonInteger of their underlying integer types (or
184  * just on the CommonInteger of ($D R1) and $(D R2), if they themselves are
185  * integers).
186  */
187 private template CommonRational(R1, R2) // TODO: avoid recursions below
188 {
189     static if (isRational!R1)
190     {
191         alias CommonRational = CommonRational!(typeof(R1.numerator), R2); // recurse. TODO: avoid
192     }
193     else static if (isRational!R2)
194     {
195         alias CommonRational = CommonRational!(R1, typeof(R2.numerator)); // recurse. TODO: avoid
196     }
197     else static if (is(CommonInteger!(R1, R2)))
198     {
199         alias CommonRational = Rational!(CommonInteger!(R1, R2));
200     }
201 }
202 
203 /** Implements rational numbers on top of whatever integer type is specified by
204  * the user.  The integer type used may be any type that behaves as an integer.
205  * Specifically, $(D isIntegerLike) must return true, the integer type must have
206  * value semantics, and the semantics of all integer operations must follow the
207  * normal rules of integer arithmetic.
208  *
209  * A regular integer can be converted to rational type simply by passing it as
210  * a single argument.  In this case the denominator will simply be set to 1.
211  *
212  * Examples:
213  * ---
214  * auto r1 = rational(BigInt("314159265"), BigInt("27182818"));
215  * auto r2 = rational(BigInt("8675309"), BigInt("362436"));
216  * r1 += r2;
217  * assert(r1 == rational(BigInt("174840986505151"),
218  *                       BigInt("4926015912324")));
219  *
220  * // Print result.  Prints:
221  * // "174840986505151/4926015912324"
222  * writeln(r1);
223  *
224  * // Print result in decimal form.  Prints:
225  * // "35.4934"
226  * writeln(cast(real) r1);
227  *
228  * auto r3 = rational(10);
229  * assert(r3.numerator == 10);
230  * assert(r3.denominator == 1);
231  * assert(r3 == 10);
232  * ---
233  */
234 Rational!(CommonInteger!(I1, I2)) rational(I1, I2)(I1 i1, I2 i2)
235 if (isIntegerLike!I1 &&
236     isIntegerLike!I2)
237 {
238     static if (is(typeof(typeof(return)(i1, i2))))
239     {
240         // Avoid initializing and then reassigning.
241         auto ret = typeof(return)(i1, i2);
242     }
243     else
244     {
245         /* Don't want to use void initialization b/c BigInts probably use
246          * assignment operator, copy c'tor, etc.
247          */
248         typeof(return) ret;
249         ret._num = i1;
250         ret._den = i2;
251     }
252     ret.simplify();
253     return ret;
254 }
255 /// ditto
256 Rational!(I) rational(I)(I val)
257 if (isIntegerLike!I)
258 {
259     return rational(val, 1);
260 }
261 
262 /** The struct that implements rational numbers.  All relevant operators
263  * (addition, subtraction, multiplication, division, exponentiation by a
264  * non-negative integer, equality and comparison) are overloaded.  The second
265  * operand for all binary operators except exponentiation may be either another
266  * $(D Rational) or another integer type.
267  */
268 struct Rational(SomeIntegral)
269 if (isIntegerLike!SomeIntegral)
270 {
271 public:
272 
273     // ----------------Multiplication operators----------------------------------
274     Rational!(SomeIntegral) opBinary(string op, Rhs)(const scope Rhs that) const
275     if (op == "*" && is(CommonRational!(SomeIntegral, Rhs)) && isRational!Rhs)
276     {
277         auto ret = CommonRational!(SomeIntegral, Rhs)(this.numerator, this.denominator);
278         return ret *= that;
279     }
280     /// ditto
281     Rational!(SomeIntegral) opBinary(string op, Rhs)(const scope Rhs that) const
282     if (op == "*" && is(CommonRational!(SomeIntegral, Rhs)) && isIntegerLike!Rhs)
283     {
284         const factor = gcf(this._den, that);
285         const adjusted_den = cast(SomeIntegral)(this._den / factor);
286         const adjusted_rhs = that / factor;
287         const long new_den = this._num * adjusted_rhs;
288         if (new_den > SomeIntegral.max)
289             throw new Exception("");
290         else
291             return typeof(this)(cast(SomeIntegral)new_den,
292                                 adjusted_den);
293     }
294 
295     auto opBinaryRight(string op, Rhs)(const scope Rhs that) const
296     if (op == "*" && is(CommonRational!(SomeIntegral, Rhs)) && isIntegerLike!Rhs)
297     {
298         return opBinary!(op, Rhs)(that); // commutative
299     }
300 
301     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
302     if (op == "*" && isRational!Rhs)
303     {
304         /* Cancel common factors first, then multiply.  This prevents
305          * overflows and is much more efficient when using BigInts. */
306         auto divisor = gcf(this._num, that._den);
307         this._num /= divisor;
308         const rhs_den = that._den / divisor;
309 
310         divisor = gcf(this._den, that._num); // reuse divisor
311         this._den /= divisor;
312         const rhs_num = that._num / divisor;
313 
314         this._num *= rhs_num;
315         this._den *= rhs_den;
316 
317         /* no simplify. already cancelled common factors before multiplying. */
318         fixSigns();
319 
320         return this;
321     }
322     /// ditto
323     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
324     if (op == "*" && isIntegerLike!Rhs)
325     {
326         const divisor = gcf(this._den, that);
327         this._den /= divisor;
328         this._num *= that / divisor;
329         /* no to simplify. already cancelled common factors before multiplying. */
330         fixSigns();
331         return this;
332     }
333 
334     typeof(this) opBinary(string op, Rhs)(const scope Rhs that) const
335     if (op == "/" &&
336         is(CommonRational!(int, Rhs)) &&
337         isRational!Rhs)
338     {
339         return typeof(return)(_num * that._den,
340                               _den * that._num);
341     }
342     // ditto
343     typeof(this) opBinary(string op, Rhs)(const scope Rhs that) const
344     if (op == "/" &&
345         is(CommonRational!(int, Rhs)) &&
346         isIntegerLike!(Rhs))
347     {
348         auto ret = CommonRational!(int, Rhs)(this.numerator, this.denominator);
349         return ret /= that;
350     }
351 
352     typeof(this) opBinaryRight(string op, Rhs)(const scope Rhs that) const
353     if (op == "/" &&
354         is(CommonRational!(int, Rhs)) &&
355         isIntegerLike!Rhs)
356     {
357         auto ret = CommonRational!(int, Rhs)(this.denominator, this.numerator);
358         return ret *= that;
359     }
360 
361     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
362     if (op == "/" &&
363         isIntegerLike!Rhs)
364     {
365         const divisor = gcf(this._num, that);
366         this._num /= divisor;
367         this._den *= that / divisor;
368 
369         /* no to simplify. already cancelled common factors before multiplying. */
370         fixSigns();
371         return this;
372     }
373 
374     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
375     if (op == "/" &&
376         isRational!Rhs)
377     {
378         return this *= that.inverse();
379     }
380 
381     // ---------------------addition operators-------------------------------------
382 
383     auto opBinary(string op, Rhs)(const scope Rhs that) const
384     if (op == "+" &&
385         (isRational!Rhs ||
386          isIntegerLike!Rhs))
387     {
388         auto ret = CommonRational!(typeof(this), Rhs)(this.numerator, this.denominator);
389         return ret += that;
390     }
391 
392     auto opBinaryRight(string op, Rhs)(const scope Rhs that) const
393     if (op == "+" &&
394         is(CommonRational!(SomeIntegral, Rhs)) &&
395         isIntegerLike!Rhs)
396     {
397         return opBinary!(op, Rhs)(that); // commutative
398     }
399 
400     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
401     if (op == "+" &&
402         isRational!Rhs)
403     {
404         if (this._den == that._den)
405         {
406             this._num += that._num;
407             simplify();
408             return this;
409         }
410 
411         SomeIntegral commonDenom = lcm(this._den, that._den);
412         this._num *= commonDenom / this._den;
413         this._num += (commonDenom / that._den) * that._num;
414         this._den = commonDenom;
415 
416         simplify();
417         return this;
418     }
419 
420     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
421     if (op == "+" &&
422         isIntegerLike!Rhs)
423     {
424         this._num += that * this._den;
425 
426         simplify();
427         return this;
428     }
429 
430     // -----------------------Subtraction operators-------------------------------
431     auto opBinary(string op, Rhs)(const scope Rhs that) const
432     if (op == "-" &&
433         is(CommonRational!(SomeIntegral, Rhs)))
434     {
435         auto ret = CommonRational!(typeof(this), Rhs)(this.numerator,
436                                                       this.denominator);
437         return ret -= that;
438     }
439 
440     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
441     if (op == "-" &&
442         isRational!Rhs)
443     {
444         if (this._den == that._den)
445         {
446             this._num -= that._num;
447             simplify();
448             return this;
449         }
450 
451         auto commonDenom = lcm(this._den, that._den);
452         this._num *= commonDenom / this._den;
453         this._num -= (commonDenom / that._den) * that._num;
454         this._den = commonDenom;
455 
456         simplify();
457         return this;
458     }
459 
460     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
461     if (op == "-" &&
462         isIntegerLike!Rhs)
463     {
464         this._num -= that * this._den;
465 
466         simplify();
467         return this;
468     }
469 
470     typeof(this) opBinaryRight(string op, Rhs)(const scope Rhs that) const
471     if (op == "-" &&
472         is(CommonInteger!(SomeIntegral, Rhs)) &&
473         isIntegerLike!Rhs)
474     {
475         Rational!(SomeIntegral) ret;
476         ret._den = this._den;
477         ret._num = (that * this._den) - this._num;
478 
479         ret.simplify();
480         return ret;
481     }
482 
483     // ----------------------Unary operators---------------------------------------
484     typeof(this) opUnary(string op)() const
485     if (op == "-" || op == "+")
486     {
487         mixin("return typeof(this)(" ~ op ~ "_num, _den);");
488     }
489 
490     // Can only handle integer powers if the result has to also be rational.
491     typeof(this) opOpAssign(string op, Rhs)(const scope Rhs that)
492     if (op == "^^" &&
493         isIntegerLike!Rhs)
494     {
495         if (that < 0)
496         {
497             this.invert();
498             _num ^^= that * -1;
499             _den ^^= that * -1;
500         }
501         else
502         {
503             _num ^^= that;
504             _den ^^= that;
505         }
506 
507         /* don't need to simplify here.  this is already simplified, meaning
508          * the numerator and denominator don't have any common factors.  raising
509          * both to a positive integer power won't create any.
510          */
511         return this;
512     }
513     /// ditto
514     auto opBinary(string op, Rhs)(const scope Rhs that) const
515     if (op == "^^" &&
516         isIntegerLike!Rhs &&
517         is(CommonRational!(SomeIntegral, Rhs)))
518     {
519         auto ret = CommonRational!(SomeIntegral, Rhs)(this.numerator, this.denominator);
520         ret ^^= that;
521         return ret;
522     }
523 
524     import std.traits : isAssignable;
525 
526     typeof(this) opAssign(Rhs)(const scope Rhs that)
527     if (isIntegerLike!Rhs &&
528         isAssignable!(SomeIntegral, Rhs))
529     {
530         this._num = that;
531         this._den = 1;
532         return this;
533     }
534 
535     typeof(this) opAssign(Rhs)(const scope Rhs that)
536     if (isRational!Rhs &&
537         isAssignable!(SomeIntegral, typeof(Rhs.numerator)))
538     {
539         this._num = that.numerator;
540         this._den = that.denominator;
541         return this;
542     }
543 
544     bool opEquals(Rhs)(const scope Rhs that) const
545     if (isRational!Rhs ||
546         isIntegerLike!Rhs)
547     {
548         static if (isRational!Rhs)
549         {
550             return (that._num == this._num &&
551                     that._den == this._den);
552         }
553         else
554         {
555             static assert(isIntegerLike!Rhs);
556             return (that == this._num &&
557                     this._den == 1);
558         }
559     }
560 
561     int opCmp(Rhs)(const scope Rhs that) const
562     if (isRational!Rhs)
563     {
564         if (opEquals(that))
565             return 0;
566 
567         /* Check a few obvious cases first, see if we can avoid having to use a
568          * common denominator.  These are basically speed hacks.
569          *
570          * Assumption:  When simplify() is called, rational will be written in
571          * canonical form, with any negative signs being only in the numerator.
572          */
573         if (this._num < 0 &&
574             that._num > 0)
575         {
576             return -1;
577         }
578         else if (this._num > 0 &&
579                  that._num < 0)
580         {
581             return 1;
582         }
583         else if (this._num >= that._num &&
584                  this._den <= that._den)
585         {
586             // We've already ruled out equality, so this must be > that.
587             return 1;
588         }
589         else if (that._num >= this._num &&
590                  that._den <= this._den)
591         {
592             return -1;
593         }
594 
595         // Can't do it without common denominator.  Argh.
596         auto commonDenom = lcm(this._den, that._den);
597         auto lhsNum = this._num * (commonDenom / this._den);
598         auto rhsNum = that._num * (commonDenom / that._den);
599 
600         if (lhsNum > rhsNum)
601             return 1;
602         else if (lhsNum < rhsNum)
603             return -1;
604 
605         /* We've checked for equality already.  If we get to this point,
606          * there's clearly something wrong.
607          */
608         assert(0);
609     }
610 
611     int opCmp(Rhs)(const scope Rhs that) const
612     if (isIntegerLike!Rhs)
613     {
614         if (opEquals(that))
615             return 0;
616 
617         // Again, check the obvious cases first.
618         if (that >= this._num)
619             return -1;
620 
621         const that_ = that * this._den;
622         if (that_ > this._num)
623             return -1;
624         else if (that_ < this._num)
625             return 1;
626 
627         // Already checked for equality.  If we get here, something's wrong.
628         assert(0);
629     }
630 
631     ///////////////////////////////////////////////////////////////////////////////
632 
633     /// Get inverse.
634     typeof(this) inverse() const
635     {
636         return typeof(return)(_den, _num);
637     }
638 
639     /// Invert `this`.
640     void invert()
641     {
642         import std.algorithm.mutation : swap;
643         swap(_den, _num);
644     }
645 
646     import std.traits : isFloatingPoint;
647 
648     ///Convert to floating point representation.
649     F opCast(F)() const
650     if (isFloatingPoint!F)
651     {
652         import std.traits : isIntegral;
653         // Do everything in real precision, then convert to F at the end.
654         static if (isIntegral!(SomeIntegral))
655         {
656             return cast(real) _num / _den;
657         }
658         else
659         {
660             Rational!SomeIntegral temp = this;
661             real expon = 1.0;
662             real ans = 0;
663             byte sign = 1;
664             if (temp._num < 0)
665             {
666                 temp._num *= -1;
667                 sign = -1;
668             }
669 
670             while (temp._num > 0)
671             {
672                 while (temp._num < temp._den)
673                 {
674 
675                     assert(temp._den > 0);
676 
677                     static if (is(typeof(temp._den & 1)))
678                     {
679                         // Try to make numbers smaller instead of bigger.
680                         if ((temp._den & 1) == 0)
681                             temp._den >>= 1;
682                         else
683                             temp._num <<= 1;
684                     }
685                     else
686                     {
687                         temp._num <<= 1;
688                     }
689 
690                     expon *= 0.5;
691 
692                     /* This checks for overflow in case we're working with a
693                      * user-defined fixed-precision integer.
694                      */
695                     import std.exception : enforce;
696                     import std.conv : text;
697                     enforce(temp._num > 0, text(
698                         "Overflow while converting ", typeof(this).stringof,
699                         " to ", F.stringof, "."));
700 
701                 }
702 
703                 auto intPart = temp._num / temp._den;
704 
705                 static if (is(SomeIntegral == struct) ||
706                            is(SomeIntegral == class))
707                 {
708                     import std.bigint : BigInt;
709                 }
710                 static if (is(SomeIntegral == BigInt))
711                 {
712                     /* This should really be a cast, but BigInt still has a few
713                      * issues.
714                      */
715                     long lIntPart = intPart.toLong();
716                 }
717                 else
718                 {
719                     long lIntPart = cast(long)intPart;
720                 }
721 
722                 // Test for changes.
723                 real oldAns = ans;
724                 ans += lIntPart * expon;
725                 if (ans == oldAns)  // Smaller than epsilon.
726                     return ans * sign;
727 
728                 // Subtract out int part.
729                 temp._num -= intPart * temp._den;
730             }
731 
732             return ans * sign;
733         }
734     }
735 
736     /** Casts $(D this) to an integer by truncating the fractional part.
737      * Equivalent to $(D integerPart), and then casting it to type $(D I).
738      */
739     I opCast(I)() const
740     if (isIntegerLike!I &&
741         is(typeof(cast(I) SomeIntegral.init)))
742     {
743         return cast(I) integerPart;
744     }
745 
746     ///Returns the numerator.
747     @property inout(SomeIntegral) numerator() inout
748     {
749         return _num;
750     }
751 
752     ///Returns the denominator.
753     @property inout(SomeIntegral) denominator() inout
754     {
755         return _den;
756     }
757 
758     /// Returns the integer part of this rational, with any remainder truncated.
759     @property SomeIntegral integerPart() const
760     {
761         return this.numerator / this.denominator;
762     }
763 
764     /// Returns the fractional part of this rational.
765     @property typeof(this) fractionPart() const
766     {
767         return this - integerPart;
768     }
769 
770     /// Returns a string representation of $(D this) in the form a/b.
771     string toString() const
772     {
773         import std.bigint : BigInt, toDecimalString;
774         static if (is(SomeIntegral == BigInt))
775         {
776             // Special case it for now.  This should be fixed later.
777             return toDecimalString(_num) ~ "/" ~ toDecimalString(_den);
778         }
779         else
780         {
781             return to!string(_num) ~ "/" ~ to!string(_den);
782         }
783     }
784 
785 private:
786     SomeIntegral _num;                    ///< Numerator.
787     SomeIntegral _den;                    ///< Denominator.
788 
789     void simplify()
790     {
791         if (_num == 0)
792         {
793             _den = 1;
794             return;
795         }
796 
797         const divisor = gcf(_num, _den);
798         _num /= divisor;
799         _den /= divisor;
800 
801         fixSigns();
802     }
803 
804     void fixSigns() scope
805     {
806         static if (!is(SomeIntegral == ulong) &&
807                    !is(SomeIntegral == uint) &&
808                    !is(SomeIntegral == ushort) &&
809                    !is(SomeIntegral == ubyte))
810         {
811             // Write in canonical form w.r.t. signs.
812             if (_den < 0)
813             {
814                 _den *= -1;
815                 _num *= -1;
816             }
817         }
818     }
819 }
820 
821 class OverflowException : Exception
822 {
823 @safe pure nothrow @nogc:
824     this(string msg) { super(msg); }
825 }
826 
827 pure unittest
828 {
829     import std.bigint : BigInt;
830     import std.math : isClose;
831 
832     // All reference values from the Maxima computer algebra system.
833     // Test c'tor and simplification first.
834     auto _num = BigInt("295147905179352825852");
835     auto _den = BigInt("147573952589676412920");
836     auto simpNum = BigInt("24595658764946068821");
837     auto simpDen = BigInt("12297829382473034410");
838     auto f1 = rational(_num, _den);
839     auto f2 = rational(simpNum, simpDen);
840     assert(f1 == f2);
841     // Check that signs of numerator/denominator are corrected
842     assert(rational(10, -3).numerator == -10);
843     assert(rational(7, -5).denominator == 5);
844 
845     // Test multiplication.
846     assert((rational(0, 1) * rational(1, 1)) == 0);
847     assert(rational(8, 42) * rational(cast(byte) 7, cast(byte) 68)
848            == rational(1, 51));
849     assert(rational(20_000L, 3_486_784_401U) * rational(3_486_784_401U, 1_000U)
850            == rational(20, 1));
851     auto f3 = rational(7, 57);
852     f3 *= rational(2, 78);
853     assert(f3 == rational(7, 2223));
854     f3 = 5 * f3;
855     assert(f3 == rational(35, 2223));
856     assert(f3 * 5UL == 5 * f3);
857 
858     /* Test division.  Since it's implemented in terms of multiplication,
859      * quick and dirty tests should be good enough.
860      */
861     assert(rational(7, 38) / rational(8, 79) == rational(553, 304));
862     assert(rational(7, 38) / rational(8, 79) == rational(553, 304));
863     auto f4 = rational(7, 38);
864     f4 /= rational(8UL, 79);
865     assert(f4 == rational(553, 304));
866     f4 = f4 / 2;
867     assert(f4 == rational(553, 608));
868     f4 = 2 / f4;
869     assert(f4 == rational(1216, 553));
870     assert(f4 * 2 == f4 * rational(2));
871     f4 = 2;
872     assert(f4 == 2);
873 
874     // Test addition.
875     assert(rational(1, 3) + rational(cast(byte) 2, cast(byte) 3) == rational(1, 1));
876     assert(rational(1, 3) + rational(1, 2L) == rational(5, 6));
877     auto f5 = rational( BigInt("314159265"), BigInt("27182818"));
878     auto f6 = rational( BigInt("8675309"), BigInt("362436"));
879     f5 += f6;
880     assert(f5 == rational( BigInt("174840986505151"), BigInt("4926015912324")));
881     assert(rational(1, 3) + 2UL == rational(7, 3));
882     assert(5UL + rational(1, 5) == rational(26, 5));
883 
884     // Test subtraction.
885     assert(rational(2, 3) - rational(1, 3) == rational(1, 3UL));
886     assert(rational(1UL, 2) - rational(1, 3) == rational(1, 6));
887     f5 = rational( BigInt("314159265"), BigInt("27182818"));
888     f5 -= f6;
889     assert(f5 == rational( BigInt("-60978359135611"), BigInt("4926015912324")));
890     assert(rational(4, 3) - 1 == rational(1, 3));
891     assert(1 - rational(1, 4) == rational(3, 4));
892 
893     // Test unary operators.
894     auto fExp = rational(2, 5);
895     assert(-fExp == rational(-2, 5));
896     assert(+fExp == rational(2, 5));
897 
898     // Test exponentiation.
899     fExp ^^= 3;
900     assert(fExp == rational(8, 125));
901     fExp = fExp ^^ 2;
902     assert(fExp == rational(64, 125 * 125));
903     assert(rational(2, 5) ^^ -2 == rational(25, 4));
904 
905     // Test decimal conversion.
906     assert(isClose(cast(real) f5, -12.37883925284411L));
907 
908     // Test comparison.
909     assert(rational(1UL, 6) < rational(1, 2));
910     assert(rational(cast(byte) 1, cast(byte) 2) > rational(1, 6));
911     assert(rational(-1, 7) < rational(7, 2));
912     assert(rational(7, 2) > rational(-1, 7));
913     assert(rational(7, 9) > rational(8, 11));
914     assert(rational(8, 11) < rational(7, 9));
915 
916     assert(rational(9, 10) < 1UL);
917     assert(1UL > rational(9, 10));
918     assert(10 > rational(9L, 10));
919     assert(2 > rational(5, 4));
920     assert(1 < rational(5U, 4));
921 
922     // Test creating rationals of value zero.
923     auto zero = rational(0, 8);
924     assert(zero == 0);
925     assert(zero == rational(0, 16));
926     assert(zero.numerator == 0);
927     assert(zero.denominator == 1);
928     auto one = zero + 1;
929     one -= one;
930     assert(one == zero);
931 
932     // Test integerPart, fraction part.
933     auto intFract = rational(5, 4);
934     assert(intFract.integerPart == 1);
935     assert(intFract.fractionPart == rational(1, 4));
936     assert(cast(long) intFract == 1);
937 
938     // Test whether CTFE works for primitive types.  Doesn't work yet.
939     version(none)
940     {
941         enum myRational = (((rational(1, 2) + rational(1, 4)) * 2 - rational(1, 4))
942                            / 2 + 1 * rational(1, 2) - 1) / rational(2, 5);
943         import std.stdio;
944         writeln(myRational);
945         static assert(myRational == rational(-15, 32));
946     }
947 }
948 
949 /** Convert a floating point number to a $(D Rational) based on integer type $(D
950  * SomeIntegral).  Allows an error tolerance of $(D epsilon).  (Default $(D epsilon) =
951  * 1e-8.)
952  *
953  * $(D epsilon) must be greater than 1.0L / long.max.
954  *
955  * Throws:  Exception on infinities, NaNs, numbers with absolute value
956  * larger than long.max and epsilons smaller than 1.0L / long.max.
957  *
958  * Examples:
959  * ---
960  * // Prints "22/7".
961  * writeln(toRational!int(PI, 1e-1));
962  * ---
963  */
964 Rational!(SomeIntegral) toRational(SomeIntegral)(real floatNum, real epsilon = 1e-8)
965 {
966     import std.math: isNaN;
967     import std.exception : enforce;
968     enforce(floatNum != real.infinity &&
969             floatNum != -real.infinity &&
970             !isNaN(floatNum),
971             "Can't convert NaNs and infinities to rational.");
972     enforce(floatNum < long.max &&
973             floatNum > -long.max,
974             "Rational conversions of very large numbers not yet implemented.");
975     enforce(1.0L / epsilon < long.max,
976             "Can't handle very small epsilons < long.max in toRational.");
977 
978     /* Handle this as a special case to make the rest of the code less
979      * complicated:
980      */
981     if (abs(floatNum) < epsilon)
982     {
983         Rational!SomeIntegral ret;
984         ret._num = 0;
985         ret._den = 1;
986         return ret;
987     }
988 
989     return toRationalImpl!(SomeIntegral)(floatNum, epsilon);
990 }
991 
992 private Rational!SomeIntegral toRationalImpl(SomeIntegral)(real floatNum, real epsilon)
993 {
994     import std.conv : roundTo;
995     import std.traits : isIntegral;
996 
997     real actualEpsilon;
998     Rational!SomeIntegral ret;
999 
1000     if (abs(floatNum) < 1)
1001     {
1002         real invFloatNum = 1.0L / floatNum;
1003         long intPart = roundTo!long(invFloatNum);
1004         actualEpsilon = floatNum - 1.0L / intPart;
1005 
1006         static if (isIntegral!(SomeIntegral))
1007         {
1008             ret._den = cast(SomeIntegral) intPart;
1009             ret._num = cast(SomeIntegral) 1;
1010         }
1011         else
1012         {
1013             ret._den = intPart;
1014             ret._num = 1;
1015         }
1016     }
1017     else
1018     {
1019         long intPart = roundTo!long(floatNum);
1020         actualEpsilon = floatNum - intPart;
1021 
1022         static if (isIntegral!(SomeIntegral))
1023         {
1024             ret._den = cast(SomeIntegral) 1;
1025             ret._num = cast(SomeIntegral) intPart;
1026         }
1027         else
1028         {
1029             ret._den = 1;
1030             ret._num = intPart;
1031         }
1032     }
1033 
1034     if (abs(actualEpsilon) <= epsilon)
1035         return ret;
1036 
1037     // Else get results from downstream recursions, add them to this result.
1038     return ret + toRationalImpl!(SomeIntegral)(actualEpsilon, epsilon);
1039 }
1040 
1041 unittest
1042 {
1043     import std.bigint : BigInt;
1044     import std.math : PI, E;
1045     // Start with simple cases.
1046     assert(toRational!int(0.5) == rational(1, 2));
1047     assert(toRational!BigInt(0.333333333333333L) == rational(BigInt(1), BigInt(3)));
1048     assert(toRational!int(2.470588235294118) == rational(cast(int) 42, cast(int) 17));
1049     assert(toRational!long(2.007874015748032) == rational(255L, 127L));
1050     assert(toRational!int( 3.0L / 7.0L) == rational(3, 7));
1051     assert(toRational!int( 7.0L / 3.0L) == rational(7, 3));
1052 
1053     // Now for some fun.
1054     real myEpsilon = 1e-8;
1055     auto piRational = toRational!long(PI, myEpsilon);
1056     assert(abs(cast(real) piRational - PI) < myEpsilon);
1057 
1058     auto eRational = toRational!long(E, myEpsilon);
1059     assert(abs(cast(real) eRational - E) < myEpsilon);
1060 }
1061 
1062 /** Find the Greatest Common Factor (GCF), aka Greatest Common Divisor (GCD), of
1063  * $(D m) and $(D n).
1064  */
1065 CommonInteger!(I1, I2) gcf(I1, I2)(I1 m, I2 n)
1066 if (isIntegerLike!I1 &&
1067     isIntegerLike!I2)
1068 {
1069     static if (is(I1 == const) || is(I1 == immutable) ||
1070                is(I2 == const) || is(I2 == immutable))
1071     {
1072         // Doesn't work with immutable(BigInt).
1073         import core.internal.traits : Unqual;
1074         return gcf!(Unqual!I1,
1075                     Unqual!I2)(m, n);
1076     }
1077     else
1078     {
1079         typeof(return) a = abs(m);
1080         typeof(return) b = abs(n);
1081 
1082         while (b)
1083         {
1084             auto t = b;
1085             b = a % b;
1086             a = t;
1087         }
1088 
1089         return a;
1090     }
1091 }
1092 
1093 pure unittest
1094 {
1095     import std.bigint : BigInt;
1096     assert(gcf(0, 0) == 0);
1097     assert(gcf(0, 1) == 1);
1098     assert(gcf(999, 0) == 999);
1099     assert(gcf(to!(immutable(int))(8), to!(const(int))(12)) == 4);
1100 
1101     // Values from the Maxima computer algebra system.
1102     assert(gcf(BigInt(314_156_535UL), BigInt(27_182_818_284UL)) == BigInt(3));
1103     assert(gcf(8675309, 362436) == 1);
1104     assert(gcf(BigInt("8589934596"), BigInt("295147905179352825852")) == 12);
1105 }
1106 
1107 /// Find the Least Common Multiple (LCM) of $(D a) and $(D b).
1108 CommonInteger!(I1, I2) lcm(I1, I2)(const scope I1 a, const scope I2 b)
1109 if (isIntegerLike!I1 &&
1110     isIntegerLike!I2)
1111 {
1112     const n1 = abs(a);
1113     const n2 = abs(b);
1114     if (n1 == n2)
1115         return n1;
1116     return (n1 / gcf(n1, n2)) * n2;
1117 }
1118 
1119 /// Returns the largest integer less than or equal to $(D r).
1120 SomeIntegral floor(SomeIntegral)(const scope Rational!SomeIntegral r)
1121 {
1122     SomeIntegral intPart = r.integerPart;
1123     if (r > 0 || intPart == r)
1124         return intPart;
1125     else
1126     {
1127         intPart -= 1;
1128         return intPart;
1129     }
1130 }
1131 
1132 @safe pure nothrow @nogc unittest
1133 {
1134     assert(floor(rational(1, 2)) == 0);
1135     assert(floor(rational(-1, 2)) == -1);
1136     assert(floor(rational(2)) == 2);
1137     assert(floor(rational(-2)) == -2);
1138     assert(floor(rational(-1, 2)) == -1);
1139 }
1140 
1141 /// Returns the smallest integer greater than or equal to $(D r).
1142 SomeIntegral ceil(SomeIntegral)(const scope Rational!SomeIntegral r)
1143 {
1144     SomeIntegral intPart = r.integerPart;
1145     if (intPart == r || r < 0)
1146         return intPart;
1147     else
1148     {
1149         intPart += 1;
1150         return intPart;
1151     }
1152 }
1153 
1154 @safe pure nothrow @nogc unittest
1155 {
1156     assert(ceil(rational(1, 2)) == 1);
1157     assert(ceil(rational(0)) == 0);
1158     assert(ceil(rational(-1, 2)) == 0);
1159     assert(ceil(rational(1)) == 1);
1160     assert(ceil(rational(-2)) == -2);
1161 }
1162 
1163 /** Round $(D r) to the nearest integer.  If the fractional part is exactly 1/2,
1164  * $(D r) will be rounded such that the absolute value is increased by rounding.
1165  */
1166 SomeIntegral round(SomeIntegral)(const scope Rational!SomeIntegral r)
1167 {
1168     auto intPart = r.integerPart;
1169     const fractPart = r.fractionPart;
1170 
1171     bool added;
1172     if (fractPart >= rational(1, 2))
1173     {
1174         added = true;
1175         intPart += 1;
1176     }
1177 
1178     import std.traits : isUnsigned;
1179 
1180     static if (!isUnsigned!SomeIntegral)
1181     {
1182         if (!added && fractPart <= rational(-1, 2))
1183             intPart -= 1;
1184     }
1185 
1186     return intPart;
1187 }
1188 
1189 @safe pure nothrow @nogc unittest
1190 {
1191     assert(round(rational(1, 3)) == 0);
1192     assert(round(rational(7, 2)) == 4);
1193     assert(round(rational(-3, 4)) == -1);
1194     assert(round(rational(8U, 15U)) == 1);
1195 }