1 // Written in the D programming language.
2 /*
3 NYSL Version 0.9982
4 
5 A. This software is "Everyone'sWare". It means:
6   Anybody who has this software can use it as if he/she is
7   the author.
8 
9   A-1. Freeware. No fee is required.
10   A-2. You can freely redistribute this software.
11   A-3. You can freely modify this software. And the source
12       may be used in any software with no limitation.
13   A-4. When you release a modified version to public, you
14       must publish it with your name.
15 
16 B. The author is not responsible for any kind of damages or loss
17   while using or misusing this software, which is distributed
18   "AS IS". No warranty of any kind is expressed or implied.
19   You use AT YOUR OWN RISK.
20 
21 C. Copyrighted to Kazuki KOMATSU
22 
23 D. Above three clauses are applied both to source and binary
24   form of this software.
25 */
26 
27 /**
28 このモジュールでは、分数型を扱うことが出来ます。
29 */
30 module carbon.rational;
31 
32 import carbon.traits;
33 
34 import std.algorithm,
35        std.array,
36        std.bigint,
37        std.format,
38        std.functional,
39        std.stdio,
40        std.traits;
41 
42 /*
43 if T is like int, isLikeInt!T is true. Where "like int" type has operators same of int.
44 
45 Example:
46 ---
47 static assert(!isLikeInt!(byte));
48 static assert(!isLikeInt!(short));
49 static assert(isLikeInt!(int));
50 static assert(isLikeInt!(long));
51 static assert(!isLikeInt!(ubyte));
52 static assert(!isLikeInt!(ushort));
53 static assert(isLikeInt!(uint));
54 static assert(isLikeInt!(ulong));
55 
56 static assert(isLikeInt!(BigInt));
57 ---
58 */
59 private
60 enum bool isLikeInt(T) = 
61 is(typeof({
62     T a = 1;
63     a = 0;
64     a = a;
65 
66     ++a;
67     --a;
68     a++;
69     a--;
70     a = -a;
71     a = +a;
72 
73     a += a;
74     a -= a;
75     a *= a;
76     a /= a;
77     a %= a;
78     //a ^^= a;
79 
80     a += 1;
81     a -= 1;
82     a *= 1;
83     a /= 1;
84     a %= 1;
85     a ^^= 1;
86 
87     a = a + a;
88     a = a - a;
89     a = a * a;
90     a = a / a;
91     a = a % a;
92     //a = a ^^ a;
93 
94     a = a + 1;
95     a = a - 1;
96     a = a * 1;
97     a = a / 1;
98     a = a % 1;
99     a = a ^^ 1;
100 
101     bool b = a < 0;
102     b = a == 0;
103 }));
104 unittest{
105     debug scope(failure) writefln("unittest Failure :%s(%s)", __FILE__, __LINE__);
106     debug scope(success) {writefln("Unittest Success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
107 
108     static assert(!isLikeInt!(byte));
109     static assert(!isLikeInt!(short));
110     static assert(isLikeInt!(int));
111     static assert(isLikeInt!(long));
112     static assert(!isLikeInt!(ubyte));
113     static assert(!isLikeInt!(ushort));
114     static assert(isLikeInt!(uint));
115     static assert(isLikeInt!(ulong));
116 
117     static assert(isLikeInt!(BigInt));
118 }
119 
120 
121 private
122 template isLikeBuiltInInt(T)
123 {
124     alias checkCode = 
125     unaryFun!((T a){
126         T b = 1;
127         b = 0;
128         b = b;
129 
130         ++b;
131         --b;
132         b++;
133         b--;
134         b = cast(const)-b;
135         b = cast(const)+b;
136 
137         b += cast(const)b;
138         b -= cast(const)b;
139         b *= cast(const)b;
140         b /= cast(const)b;
141         b %= cast(const)b;
142         //b ^^= b;
143 
144         b += 1;
145         b -= 1;
146         b *= 1;
147         b /= 1;
148         b %= 1;
149         b ^^= 1;
150 
151         b = cast(const)b + cast(const)b;
152         b = cast(const)b - cast(const)b;
153         b = cast(const)b * cast(const)b;
154         b = cast(const)b / cast(const)b;
155         b = cast(const)b % cast(const)b;
156         //b = b ^^ b;
157 
158         b = cast(const)b + 1;
159         b = cast(const)b - 1;
160         b = cast(const)b * 1;
161         b = cast(const)b / 1;
162         b = cast(const)b % 1;
163         b = cast(const)b ^^ 1;
164 
165         bool c = cast(const)b < 0;
166         c = cast(const)b == 0;
167     });
168 
169 
170     enum isLikeBuiltInInt = FuncAttr.isPure!(() => checkCode(T.init))
171                          && FuncAttr.isNothrow!(() => checkCode(T.init))
172                          && isSafe!(() => checkCode(T.init));
173 }
174 unittest{
175     debug scope(failure) writefln("unittest Failure :%s(%s)", __FILE__, __LINE__);
176     debug scope(success) {writefln("Unittest Success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
177 
178     static assert(isLikeBuiltInInt!int);
179     static assert(isLikeBuiltInInt!long);
180 }
181 
182 
183 private
184 auto gcd(T, U)(T a, U b)
185 if(is(typeof(a + b)))
186 {
187     alias C = Unqual!(typeof(a + b));
188 
189     C _a = a < 0 ? a * -1 : a,
190       _b = b < 0 ? b * -1 : b;
191 
192     while(_a != 0 && _b != 0){
193         if(_a > _b)
194             _a %= _b;
195         else
196             _b %= _a;
197     }
198 
199     if(_a == 0)
200         return _b;
201     else
202         return _a;
203 }
204 
205 
206 private
207 auto lcm(T, U)(T a, U b)
208 {
209     return a / gcd(a, b) * b;
210 }
211 
212 
213 /**
214 This is the type that you can calculate fraction.
215 $(B Rational!T) has two integral $(B T) values.
216 
217 Example:
218 ---
219 auto r = rational(10, 2);       // If you called rational(n, d), value is reduced.
220 assert(r.num == 5);             // 10 / 2 => 5 / 1
221 assert(r.den == 1);
222 
223 assert(r == rational(5));       // rational(5) == rational(5, 1)
224 
225 assert(r == 5.over(1));          // UFCS : n.over(d) == n.rational(d) == rational(n, d)
226 
227 r *= -1.over(5);
228 assert(r.num == -1);            // If rational value is negative, numerator is always negative.
229 assert(r.den == 1);             // But denominator is always positive.
230 assert(r == rational(1, 1));    // (5 / 1) * (1 / 5) == (1 / 1)
231 assert(r == 1);                 // Can check equality to T by "==" operator.
232 assert(r > 2);                  // Also comparison operator.
233 
234 r1 = 2.over(5) + 3;              // You can use Rational!T like T.
235 
236 import std.bigint;
237 Rational!BigInt rb = 10.over(33);// You can use BigInt as T.
238 rb ^^= -10;
239 assert(rb == Rational!BigInt(BigInt(33)^^10, BigInt(10)^^10));
240 ---
241 
242 If $(B T) can be operated in $(B pure nothrow @safe function),
243 $(B Rational!T) can be too.
244 
245 Example:
246 -------------------------------------------------------
247 void foo() pure nothrow @safe
248 {
249     auto r = rational(1, 3);    //int is pure nothrow @safe type
250     r += 3.over(4);
251     ...
252 }
253 -------------------------------------------------------
254 
255 You can use $(B "%(...%)") format when formatted write.
256 Where inner format $(B "...") can be $(B T)'s format, first one is numerator's format, second is denominator's format.
257 
258 Example:
259 ---
260 import std.format;
261 
262 void main(){
263     auto writer = appender!string;
264 
265     formattedWrite(writer, "%(%04d / %04d%)", rational(10, 33));
266     assert(writer.data == "0010 / 0033");
267 
268     writer = appender!string;
269     formattedWrite(writer, "%(den : %2$s , num : %1$s%)", rational(10, 33));
270     assert(writer.data == "den : 33 , num : 10");
271 
272     writer = appender!string;
273     formattedWrite(writer, "%04d", rational(10, 30));
274     assert(writer.data == "0010/0030");
275 }
276 ---
277 */
278 struct Rational(T)
279 if(isLikeInt!T && !isFloatingPoint!T)
280 {
281   private:
282     T _num = 0;         //分子
283     T _den = 1;         //分母
284 
285 
286     debug(rational)
287     {
288         const invariant()
289         {
290             assert(_den != 0);
291         }
292     }
293 
294 
295     void reduce()
296     {
297         if(_num == 0){
298             if(_den < 0)
299                 _den = -1;
300             else
301                 _den = 1;
302         }else{
303             auto _gcd = gcd(_num, _den);
304             _num /= _gcd;
305             _den /= _gcd;
306         }
307 
308         if(_den < 0){
309             _num = -_num;
310             _den = -_den;
311         }
312     }
313 
314     
315   public:
316   version(none)
317   {
318     static typeof(this) init() @property
319     {
320         static if(is(typeof({typeof(this) r = typeof(this)(0, 1);})))
321             typeof(this) r = typeof(this)(0, 1);
322         else{
323             typeof(this) r;
324             ++r._den;
325         }
326         return r;
327     }
328   }
329 
330 
331     ///ditto
332     this(U)(in U n)
333     {
334         _num = n;
335         _den = 1;
336     }
337 
338 
339     ///ditto
340     this(U, V)(in U n, in V d, bool nonReduce = false)
341     if(isAssignable!(T, const(U)) && isAssignable!(T, const(V)))
342     {
343         _num = n;
344         _den = d;
345 
346         if(!nonReduce) reduce();
347     }
348 
349 
350     /// numerator
351     @property
352     inout(T) num() inout
353     {
354         return _num;
355     }
356 
357 
358     /// ditto
359     @property
360     void num(U)(in U u)
361     if(isAssignable!(T, const(U)))
362     {
363         _num =  u;
364         reduce();
365     }
366 
367 
368     /// denominator
369     @property
370     inout(T) den() inout
371     {
372         return _den;
373     }
374 
375 
376     /// ditto
377     @property
378     void den(U)(in U u)
379     if(isAssignable!(T, const(U)))
380     in{
381         assert(u != 0);
382     }
383     body{
384         _den = u;
385         reduce();
386     }
387 
388 
389     /// return reciprocal number
390     @property
391     typeof(this) reciprocal() const
392     {
393         return _num < 0 ? typeof(this)(-_den, -_num, false) : typeof(this)(_den , _num, false);
394     }
395 
396 
397     /// operator
398     void opAssign(U)(in U v)
399     if(!isRationalType!U && isAssignable!(T, U))
400     {
401         _den = 1;
402         _num = v;
403     }
404 
405 
406     /// ditto
407     void opAssign(U)(in Rational!U r)
408     if(isAssignable!(T, U))
409     {
410         _den = r._den;
411         _num = r._num;
412     }
413 
414 
415     /// ditto
416     typeof(this) opUnary(string op)() const
417     if(!find(["-", "+"], op).empty)
418     {
419         static if(op == "-")
420             return rational(-_num, _den);
421         else static if(op == "+")
422             return rational(_num, _den);
423     }
424 
425 
426     /// ditto
427     typeof(this) opUnary(string op)()
428     if(!find(["++", "--"], op).empty)
429     {
430         static if(op == "++")
431             _num += _den;
432         else static if(op == "--")
433             _num -= _den;
434 
435         return this;
436     }
437 
438 
439     ///ditto
440     bool opCast(U : bool)() const
441     {
442         return _num != 0;
443     }
444 
445 
446     ///ditto
447     U opCast(U : T)() const
448     {
449         return _num / _den;
450     }
451 
452 
453     /// ditto
454     U opCast(U)() const
455     if(isRationalType!U && is(typeof({auto e = U(_num, _den, true);})))
456     {
457         return U(_num, _den, true);
458     }
459 
460 
461     /// ditto
462     U opCast(U)() const
463     if(isRationalType!U && !is(typeof({auto e = U(_num, _den);})) && is(typeof({auto e = cast(typeof(U.init._num))_num;})))
464     {
465         alias E = typeof(U.init._num);
466         return U(cast(E)_num, cast(E)_den, true);
467     }
468 
469 
470     /// ditto
471     auto opBinary(string op, U)(in Rational!U r) const
472     if(!find(["+", "-", "*", "/", "%"], op).empty)
473     {
474        static if(op == "+"){
475             auto gcd1 = gcd(_den, r._den);
476             return rational(_num * (r._den / gcd1) + r._num * (_den / gcd1), _den / gcd1 * r._den);
477         }
478         else static if(op == "-"){
479             auto gcd1 = gcd(_den, r._den);
480             return rational(_num * (r._den / gcd1) - r._num * (_den / gcd1), _den / gcd1 * r._den);
481         }
482         else static if(op == "*"){
483             auto gcd1 = gcd(_num, r._den);
484             auto gcd2 = gcd(r._num, _den);
485             return rational((_num/gcd1) * (r._num / gcd2), (_den/gcd2) * (r._den / gcd1), true);
486         }
487         else static if(op == "/"){
488             auto gcd1 = gcd(_num, r._num);
489             auto gcd2 = gcd(r._den, _den);
490             if(r._num < 0)
491                 gcd1 = -gcd1;
492             return rational((_num/gcd1) * (r._den / gcd2), (_den/gcd2) * (r._num / gcd1), true);
493         }
494         else static if(op == "%"){
495             auto gcd1 = gcd(_den, r._den);
496             return rational((_num * (r._den / gcd1)) % (r._num * (_den / gcd1)), _den / gcd1 * r._den);
497         }
498     }
499 
500 
501     /// ditto
502     auto opBinary(string op, U)(in U v) const
503     if(!isRationalType!U && isLikeInt!U && !find(["+", "-", "*", "/", "%", "^^"], op).empty)
504     {
505         static if(op == "+")
506             return rational(_num + _den * v, _den);
507         else static if(op == "-")
508             return rational(_num - _den * v, _den);
509         else static if(op == "*")
510             return rational(_num * v, _den);
511         else static if(op == "/")
512             return rational(_num, _den * v);
513         else static if(op == "%")
514             return rational(_num % (v * _den), _den);
515         else static if(op == "^^"){
516             if(v >= 0)
517                 return rational(_num ^^ v, _den ^^ v);
518             else{
519                 if(_num >= 0)
520                     return rational(_den ^^ (-v), _num ^^ (-v));
521                 else
522                     return rational((-_den) ^^ (-v), (-_num) ^^ (-v));
523             }
524         }else
525             static assert(0);
526     }
527 
528 
529     /// ditto
530     auto opBinaryRight(string op, U)(in U v) const
531     if(!isRationalType!U && isLikeInt!U && !find(["+", "-", "*", "/", "%"], op).empty)
532     {
533         static if(op == "+")
534             return rational(_num + _den * v, _den);
535         else static if(op == "-")
536             return rational(_den * v - num, _den);
537         else static if(op == "*")
538             return rational(_num * v, _den);
539         else static if(op == "/")
540             return rational(v * _den, _num);
541         else static if(op == "%")
542             return rational((v * _den) % _num, _den);
543     }
544 
545 
546     /// ditto
547     void opOpAssign(string op, U)(in Rational!U r)
548     if(!find(["+", "-", "*", "/", "%"], op).empty)
549     in{
550         static if(op == "/")
551             assert(r._num != 0);
552     }
553     body{
554         static if(op == "+"){
555             auto gcd1 = gcd(_den, r._den);
556             _num = _num * (r._den / gcd1) + r._num * (_den / gcd1);
557             _den = _den / gcd1 * r._den;
558             reduce();
559         }
560         else static if(op == "-"){
561             auto gcd1 = gcd(_den, r._den);
562             _num = _num * (r._den / gcd1) - r._num * (_den / gcd1);
563             _den = _den / gcd1 * r._den;
564             reduce();
565         }
566         else static if(op == "*"){
567             auto gcd1 = gcd(_num, r._den);
568             auto gcd2 = gcd(r._num, _den);
569             _num = (_num / gcd1) * (r._num / gcd2);
570             _den = (_den / gcd2) * (r._den / gcd1);
571         }
572         else static if(op == "/"){
573             auto gcd1 = gcd(_num, r._num);
574             auto gcd2 = gcd(r._den, _den);
575 
576             if(r._num >= 0){
577                 _num = (_num / gcd1) * (r._den / gcd2);
578                 _den = (_den / gcd2) * (r._num / gcd1);
579             }else{
580                 _num = -(_num / gcd1) * (r._den / gcd2);
581                 _den = -(_den / gcd2) * (r._num / gcd1);
582             }
583         }
584         else static if(op == "%"){
585             auto gcd1 = gcd(_den, r._den);
586             _num = (_num * (r._den / gcd1)) % (r._num * (_den / gcd1));
587             _den = _den / gcd1 * r._den;
588             reduce();
589         }
590     }
591 
592 
593     /// ditto
594     void opOpAssign(string op, U)(const U v)
595     if(!isRationalType!U && isLikeInt!U && !find(["+", "-", "*", "/", "%", "^^"], op).empty)
596     in{
597         static if(op == "^^")
598             assert(!(v < 0 && _num == 0));
599     }
600     body{
601         static if(op == "+"){
602             _num += _den * v;
603         }else static if(op == "-"){
604             _num -= _den * v;
605         }else static if(op == "*"){
606             _num *= v;
607             reduce();
608         }else static if(op == "/"){
609             _den *= v;
610             reduce();
611         }else static if(op == "%"){
612             _num %= _den * v;
613             reduce();
614         }else static if(op == "^^"){
615             if(v >= 0){
616                 _num ^^= v;
617                 _den ^^= v;
618             }else{
619                 if(_num >= 0){
620                     auto tmp = _num;
621                     _num = _den ^^ (-v);
622                     _den = tmp ^^ (-v);
623                 }else{
624                     auto tmp = -_num;
625                     _num = (-_den) ^^ (-v);
626                     _den = (tmp) ^^ (-v);
627                 }
628             }
629         }
630     }
631 
632 
633     /// ditto
634     auto opCmp(U)(auto ref const U r) const
635     if(!isRationalType!U)
636     {
637         return _num - r * _den;
638     }
639 
640 
641     /// ditto
642     auto opCmp(U)(auto ref const Rational!U r) const
643     {
644         auto _gcd = gcd(_den, r._den);
645         return (_num * (r._den / _gcd)) - (r._num * (_den / _gcd));
646     }
647 
648 
649     /// ditto
650     bool opEquals(U)(auto ref const U v) const
651     if(!isRationalType!U)
652     {
653         return _den == 1 && _num == v;
654     }
655 
656 
657     /// ditto
658     bool opEquals(U)(auto ref const Rational!U r) const
659     {
660         return (_num == r._num) && (_den == r._den);
661     }
662 
663 
664     /// ditto
665     void toString(scope void delegate(const(char)[]) sink, FormatSpec!char fmt) const
666     {
667         if(fmt.nested.length != 0){
668             formattedWrite(sink, fmt.nested, _num, _den);
669         }else{
670             formatValue(sink, _num, fmt);
671             sink("/");
672             formatValue(sink, _den, fmt);
673         }
674     }
675 }
676 
677 
678 ///ditto
679 Rational!(Unqual!(CommonType!(T, U))) rational(T, U)(T num, U den) pure nothrow @safe if(isLikeBuiltInInt!(Unqual!(CommonType!(T, U))))
680 {
681     return Rational!(Unqual!(CommonType!(T, U)))(num, den, false);
682 }
683 
684 
685 ///ditto
686 Rational!(Unqual!(CommonType!(T, U))) rational(T, U)(T num, U den) if(!isLikeBuiltInInt!(Unqual!(CommonType!(T, U))))
687 {
688     return Rational!(Unqual!(CommonType!(T, U)))(num, den, false);
689 }
690 
691 
692 ///ditto
693 Rational!(Unqual!T) rational(T)(T num) pure nothrow @safe if(isLikeBuiltInInt!(Unqual!T))
694 {
695     return Rational!(Unqual!T)(num, 1);
696 }
697 
698 
699 ///ditto
700 Rational!(Unqual!T) rational(T)(T num) if(!isLikeBuiltInInt!(Unqual!T))
701 {
702     return Rational!(Unqual!T)(num, 1);
703 }
704 
705 
706 private
707 Rational!(Unqual!(CommonType!(T, U))) rational(T, U)(T num, U den, bool nonReduce) pure nothrow @safe if(isLikeBuiltInInt!(Unqual!(CommonType!(T, U))))
708 {
709     return Rational!(Unqual!(CommonType!(T, U)))(num, den, nonReduce);
710 }
711 
712 
713 private
714 Rational!(Unqual!(CommonType!(T, U))) rational(T, U)(T num, U den, bool nonReduce) if(!isLikeBuiltInInt!(Unqual!(CommonType!(T, U))))
715 {
716     return Rational!(Unqual!(CommonType!(T, U)))(num, den, nonReduce);
717 }
718 
719 
720 ///ditto
721 alias over = rational;
722 
723 
724 ///
725 unittest{
726     debug scope(failure) writefln("unittest Failure :%s(%s)", __FILE__, __LINE__);
727     debug scope(success) {writefln("Unittest Success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
728 
729     import std.stdio;
730 
731     static void foo(T)()
732     {
733         alias Rational!T R;
734         alias R r;
735 
736         assert(R.init == r(0, 1));
737         assert(R.init.den != 0);
738 
739         assert(r(0, -3) == r(0, 1));
740 
741       static if(isIntegral!T)   // int, long
742         static assert(r(2, 15) == r(4, 5) % r(1, 6));   //CTFEable
743 
744         assert(3.over(2) == r(3, 2));    //num.over(den)
745 
746         //opUnary and cast test
747         assert(-r(5) == r(-5, 1));
748         assert(+r(5) == r(5));
749         assert(++r(5, 13) == r(18, 13));
750         assert(--r(5, 13) == r(-8, 13));
751         assert(!r(0));
752         assert(r(1));
753         assert(cast(T)r(10, 3) == r(10, 3).num / r(10, 3).den);
754 
755         //opBinary test
756         assert(r(5, 6) + r(3, 8) == r(29, 24));
757         assert(r(-1, 3) + r(3, 2) == r(7, 6));
758         assert(r(1, 3) - r(4, 5) == r(-7, 15));
759         assert(r(-1, 3) - r(-4, 5) == r(7, 15));
760         assert(r(5, 6) * r(3, 8) == r(5, 16));
761         assert(r(-1, 3) * r(3, 2) == r(-1, 2));
762         assert(r(1, 3) / r(4, 5) == r(5, 12));
763         assert(r(-1, 3) / r(-4, 5) == r(5, 12));
764         assert(r(1, 3) % r(4, 5) == r(5, 15));
765         assert(r(-1, 3) % r(-4, 5) == r(-5, 15));
766 
767         assert(r(5, 6) + 3 == r(23, 6));
768         assert(r(-1, 3) + 3 == r(8, 3));
769         assert(r(1, 3) - 3 == r(-8, 3));
770         assert(r(-1, 3) - 3 == r(-10, 3));
771         assert(r(5, 6) * 3 == r(5, 2));
772         assert(r(-1, 3) * 3 == r(-1, 1));
773         assert(r(1, 3) / 3 == r(1, 9));
774         assert(r(-1, 3) / 3 == r(-1, 9));
775         assert(r(1, 3) % 3 == r(1, 3));
776         assert(r(-1, 3) % 3 == r(-1, 3));
777         assert(r(2, 3) ^^ 3 == r(8, 27));
778         assert(r(2, 3) ^^ 4 == r(16, 81));
779         assert(r(-2, 3) ^^ 3 == -r(8, 27));
780         assert(r(-2, 3) ^^ 4 == r(16, 81));
781         assert(r(2, 3) ^^ -3 == r(27, 8));
782         assert(r(2, 3) ^^ -4 == r(81, 16));
783         assert(r(-2, 3) ^^ -3 == -r(27, 8));
784         assert(r(-2, 3) ^^ -4 == r(81, 16));
785         assert(r(-1, 3) ^^ -3 == r(-27, 1));
786 
787         assert(3 + r(5, 6) == r(23, 6));
788         assert(3 + r(-1, 3) == r(8, 3));
789         assert(3 - r(1, 3) == r(8, 3));
790         assert(3 - r(-1, 3) == r(10, 3));
791         assert(3 * r(5, 6) == r(5, 2));
792         assert(3 * r(-1, 3) == r(-1, 1));
793         assert(3 / r(1, 3) == r(9, 1));
794         assert(3 / r(-1, 3) == r(-9, 1));
795         assert(3 % r(2, 3) == r(1, 3));
796         assert(3 % r(-2, 3) == r(1, 3));
797 
798         {
799             R r1 = 3;
800             assert(r1 == r(3, 1));
801         }
802 
803         auto r1 = r(5, 6);
804         r1 += r(3, 8);
805         assert(r1 == r(29, 24));
806         r1 += r(3, 2);
807         assert(r1 == r(65, 24));
808 
809         r1 = r(1, 3);
810         r1 -= r(4, 5);
811         assert(r1 == r(-7, 15));
812         r1 -= r(-4, 5);
813         assert(r1 == r(1, 3));
814 
815         r1 = r(5, 6);
816         r1 *= r(3, 8);
817         assert(r1 == r(5, 16));
818         r1 *= r(3, 2);
819         assert(r1 == r(15, 32));
820 
821         r1 = r(1, 3);
822         r1 /= r(4, 5);
823         assert(r1 == r(5, 12));
824         r1 /= r(-4, 5);
825         assert(r1 == r(-25, 48));
826 
827         r1 = r(4, 3);       //r(20, 15)
828         r1 %= r(4, 5);      //r(12, 15)
829         assert(r1 == r(8, 15));
830         r1 %= r(-2, 5);     //r(-6, 15)
831         assert(r1 == r(2, 15));
832 
833         
834         r1 = r(-5, 6);
835         r1 += 3;
836         assert(r1 == r(13, 6));
837         r1 += -3;
838         assert(r1 == r(-5, 6));
839 
840         r1 = r(-1, 3);
841         r1 -= 3;
842         assert(r1 == r(-10, 3));
843         r1 -= -3;
844         assert(r1 == r(-1, 3));
845 
846         r1 = r(-5, 6);
847         r1 *= 3;
848         assert(r1 == r(-5, 2));
849         r1 *= -3;
850         assert(r1 == r(15, 2));
851 
852         r1 = r(-1, 3);
853         r1 /= 4;
854         assert(r1 == r(-1, 12));
855         r1 /= -4;
856         assert(r1 == r(1, 48));
857 
858         r1 = r(17, 2);      //r(51, 6)
859         r1 %= 3;            //r(18, 6)
860         assert(r1 == r(5, 2)); //r(25, 10)
861         r1 = r(-25, 10);    //r(-25, 10)
862         r1 %= r(2, 5);      //r(6, 10)
863         assert(r1 == r(-1, 10));
864 
865         r1 = r(2, 3);
866         r1 ^^= 3;
867         assert(r1 == r(8, 27));
868 
869         r1 = r(2, 3);
870         r1 ^^= 4;
871         assert(r1 == r(16, 81));
872 
873         r1 = -r(2, 3);
874         r1 ^^= 3;
875         assert(r1 == -r(8, 27));
876 
877         r1 = -r(2, 3);
878         r1 ^^= 4;
879         assert(r1 == r(16, 81));
880 
881         r1 = r(2, 3);
882         r1 ^^= -3;
883         assert(r1 == r(27, 8));
884 
885         r1 = r(2, 3);
886         r1 ^^= -4;
887         assert(r1 == r(81, 16));
888 
889         r1 = -r(2, 3);
890         r1 ^^= -3;
891         assert(r1 == -r(27, 8));
892 
893         r1 = -r(2, 3);
894         r1 ^^= -4;
895         assert(r1 == r(81, 16));
896 
897         r1 = r(-1, 3);
898         r1 ^^= 3;
899         assert(r1 == r(-1, 27));
900         r1 ^^= -2;
901         assert(r1 == r(729, 1));
902 
903         assert(r1 == 729);
904         assert(r1 < 799);
905         assert(r1 < r(700*8, 3));
906         assert(r1 > r(700*2, 3));
907         assert(r1 == r(729, 1));
908         assert(r1.reciprocal == r(1, 729));
909     }
910 
911     foo!int();
912     foo!long();
913     foo!BigInt();
914 
915     // CTFE test
916     static assert(is(typeof({
917         enum bar = {
918             foo!int();
919             return true;
920         }();
921     })));
922 
923     static assert(is(typeof({
924         enum bar = {
925             foo!long();
926             return true;
927         }();
928     })));
929 
930     // pure nothrow @safe test
931     static assert(FuncAttr.isPure!(foo!int)
932                && FuncAttr.isNothrow!(foo!int)
933                && std.traits.isSafe!(foo!int));
934 
935     static assert(FuncAttr.isPure!(foo!long)
936                && FuncAttr.isNothrow!(foo!long)
937                && std.traits.isSafe!(foo!long));
938 
939     auto r1 = rational(729, 1);
940 
941     auto writer = appender!string;
942     formattedWrite(writer, "%(%08d / %04d%)", r1);
943     assert(writer.data == "00000729 / 0001");
944 
945     writer = appender!string;
946     formattedWrite(writer, "%(%2$s/%1$s%)", r1);
947     assert(writer.data == "1/729");
948 
949     writer = appender!string;
950     formattedWrite(writer, "%08d", r1);
951     assert(writer.data == "00000729/00000001");
952 
953 
954     // like literal
955     assert(-1.over(5) == rational(-1, 5));
956     assert(-1.rational(5) == rational(-1, 5));
957 }
958 
959 
960 /**
961 true if T is rational
962 */
963 template isRationalType(T){
964     static if(is(T U == Rational!U))
965         enum bool isRationalType = true;
966     else
967         enum bool isRationalType = false;
968 }
969 
970 
971 unittest
972 {
973     debug scope(failure) writefln("unittest Failure :%s(%s)", __FILE__, __LINE__);
974     debug scope(success) {writefln("Unittest Success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
975 
976     static assert(isRationalType!(Rational!int));
977     static assert(isRationalType!(Rational!uint));
978     static assert(isRationalType!(Rational!long));
979     static assert(isRationalType!(Rational!ulong));
980     static assert(isRationalType!(Rational!BigInt));
981 }