over

This is the type that you can calculate fraction. Rational!T has two integral T values.

alias over = rational

Examples

auto r = rational(10, 2);       // If you called rational(n, d), value is reduced.
assert(r.num == 5);             // 10 / 2 => 5 / 1
assert(r.den == 1);

assert(r == rational(5));       // rational(5) == rational(5, 1)

assert(r == 5.over(1));          // UFCS : n.over(d) == n.rational(d) == rational(n, d)

r *= -1.over(5);
assert(r.num == -1);            // If rational value is negative, numerator is always negative.
assert(r.den == 1);             // But denominator is always positive.
assert(r == rational(1, 1));    // (5 / 1) * (1 / 5) == (1 / 1)
assert(r == 1);                 // Can check equality to T by "==" operator.
assert(r > 2);                  // Also comparison operator.

r1 = 2.over(5) + 3;              // You can use Rational!T like T.

import std.bigint;
Rational!BigInt rb = 10.over(33);// You can use BigInt as T.
rb ^^= -10;
assert(rb == Rational!BigInt(BigInt(33)^^10, BigInt(10)^^10));

If T can be operated in pure nothrow @safe function, Rational!T can be too.

void foo() pure nothrow @safe
{
    auto r = rational(1, 3);    //int is pure nothrow @safe type
    r += 3.over(4);
    ...
}

You can use "%(...%)" format when formatted write. Where inner format "..." can be T's format, first one is numerator's format, second is denominator's format.

import std.format;

void main(){
    auto writer = appender!string;

    formattedWrite(writer, "%(%04d / %04d%)", rational(10, 33));
    assert(writer.data == "0010 / 0033");

    writer = appender!string;
    formattedWrite(writer, "%(den : %2$s , num : %1$s%)", rational(10, 33));
    assert(writer.data == "den : 33 , num : 10");

    writer = appender!string;
    formattedWrite(writer, "%04d", rational(10, 30));
    assert(writer.data == "0010/0030");
}
1 debug scope(failure) writefln("unittest Failure :%s(%s)", __FILE__, __LINE__);
2 debug scope(success) {writefln("Unittest Success :%s(%s)", __FILE__, __LINE__); stdout.flush();}
3 
4 import std.stdio;
5 
6 static void foo(T)()
7 {
8     alias Rational!T R;
9     alias R r;
10 
11     assert(R.init == r(0, 1));
12     assert(R.init.den != 0);
13 
14     assert(r(0, -3) == r(0, 1));
15 
16   static if(isIntegral!T)   // int, long
17     static assert(r(2, 15) == r(4, 5) % r(1, 6));   //CTFEable
18 
19     assert(3.over(2) == r(3, 2));    //num.over(den)
20 
21     //opUnary and cast test
22     assert(-r(5) == r(-5, 1));
23     assert(+r(5) == r(5));
24     assert(++r(5, 13) == r(18, 13));
25     assert(--r(5, 13) == r(-8, 13));
26     assert(!r(0));
27     assert(r(1));
28     assert(cast(T)r(10, 3) == r(10, 3).num / r(10, 3).den);
29 
30     //opBinary test
31     assert(r(5, 6) + r(3, 8) == r(29, 24));
32     assert(r(-1, 3) + r(3, 2) == r(7, 6));
33     assert(r(1, 3) - r(4, 5) == r(-7, 15));
34     assert(r(-1, 3) - r(-4, 5) == r(7, 15));
35     assert(r(5, 6) * r(3, 8) == r(5, 16));
36     assert(r(-1, 3) * r(3, 2) == r(-1, 2));
37     assert(r(1, 3) / r(4, 5) == r(5, 12));
38     assert(r(-1, 3) / r(-4, 5) == r(5, 12));
39     assert(r(1, 3) % r(4, 5) == r(5, 15));
40     assert(r(-1, 3) % r(-4, 5) == r(-5, 15));
41 
42     assert(r(5, 6) + 3 == r(23, 6));
43     assert(r(-1, 3) + 3 == r(8, 3));
44     assert(r(1, 3) - 3 == r(-8, 3));
45     assert(r(-1, 3) - 3 == r(-10, 3));
46     assert(r(5, 6) * 3 == r(5, 2));
47     assert(r(-1, 3) * 3 == r(-1, 1));
48     assert(r(1, 3) / 3 == r(1, 9));
49     assert(r(-1, 3) / 3 == r(-1, 9));
50     assert(r(1, 3) % 3 == r(1, 3));
51     assert(r(-1, 3) % 3 == r(-1, 3));
52     assert(r(2, 3) ^^ 3 == r(8, 27));
53     assert(r(2, 3) ^^ 4 == r(16, 81));
54     assert(r(-2, 3) ^^ 3 == -r(8, 27));
55     assert(r(-2, 3) ^^ 4 == r(16, 81));
56     assert(r(2, 3) ^^ -3 == r(27, 8));
57     assert(r(2, 3) ^^ -4 == r(81, 16));
58     assert(r(-2, 3) ^^ -3 == -r(27, 8));
59     assert(r(-2, 3) ^^ -4 == r(81, 16));
60     assert(r(-1, 3) ^^ -3 == r(-27, 1));
61 
62     assert(3 + r(5, 6) == r(23, 6));
63     assert(3 + r(-1, 3) == r(8, 3));
64     assert(3 - r(1, 3) == r(8, 3));
65     assert(3 - r(-1, 3) == r(10, 3));
66     assert(3 * r(5, 6) == r(5, 2));
67     assert(3 * r(-1, 3) == r(-1, 1));
68     assert(3 / r(1, 3) == r(9, 1));
69     assert(3 / r(-1, 3) == r(-9, 1));
70     assert(3 % r(2, 3) == r(1, 3));
71     assert(3 % r(-2, 3) == r(1, 3));
72 
73     {
74         R r1 = 3;
75         assert(r1 == r(3, 1));
76     }
77 
78     auto r1 = r(5, 6);
79     r1 += r(3, 8);
80     assert(r1 == r(29, 24));
81     r1 += r(3, 2);
82     assert(r1 == r(65, 24));
83 
84     r1 = r(1, 3);
85     r1 -= r(4, 5);
86     assert(r1 == r(-7, 15));
87     r1 -= r(-4, 5);
88     assert(r1 == r(1, 3));
89 
90     r1 = r(5, 6);
91     r1 *= r(3, 8);
92     assert(r1 == r(5, 16));
93     r1 *= r(3, 2);
94     assert(r1 == r(15, 32));
95 
96     r1 = r(1, 3);
97     r1 /= r(4, 5);
98     assert(r1 == r(5, 12));
99     r1 /= r(-4, 5);
100     assert(r1 == r(-25, 48));
101 
102     r1 = r(4, 3);       //r(20, 15)
103     r1 %= r(4, 5);      //r(12, 15)
104     assert(r1 == r(8, 15));
105     r1 %= r(-2, 5);     //r(-6, 15)
106     assert(r1 == r(2, 15));
107 
108 
109     r1 = r(-5, 6);
110     r1 += 3;
111     assert(r1 == r(13, 6));
112     r1 += -3;
113     assert(r1 == r(-5, 6));
114 
115     r1 = r(-1, 3);
116     r1 -= 3;
117     assert(r1 == r(-10, 3));
118     r1 -= -3;
119     assert(r1 == r(-1, 3));
120 
121     r1 = r(-5, 6);
122     r1 *= 3;
123     assert(r1 == r(-5, 2));
124     r1 *= -3;
125     assert(r1 == r(15, 2));
126 
127     r1 = r(-1, 3);
128     r1 /= 4;
129     assert(r1 == r(-1, 12));
130     r1 /= -4;
131     assert(r1 == r(1, 48));
132 
133     r1 = r(17, 2);      //r(51, 6)
134     r1 %= 3;            //r(18, 6)
135     assert(r1 == r(5, 2)); //r(25, 10)
136     r1 = r(-25, 10);    //r(-25, 10)
137     r1 %= r(2, 5);      //r(6, 10)
138     assert(r1 == r(-1, 10));
139 
140     r1 = r(2, 3);
141     r1 ^^= 3;
142     assert(r1 == r(8, 27));
143 
144     r1 = r(2, 3);
145     r1 ^^= 4;
146     assert(r1 == r(16, 81));
147 
148     r1 = -r(2, 3);
149     r1 ^^= 3;
150     assert(r1 == -r(8, 27));
151 
152     r1 = -r(2, 3);
153     r1 ^^= 4;
154     assert(r1 == r(16, 81));
155 
156     r1 = r(2, 3);
157     r1 ^^= -3;
158     assert(r1 == r(27, 8));
159 
160     r1 = r(2, 3);
161     r1 ^^= -4;
162     assert(r1 == r(81, 16));
163 
164     r1 = -r(2, 3);
165     r1 ^^= -3;
166     assert(r1 == -r(27, 8));
167 
168     r1 = -r(2, 3);
169     r1 ^^= -4;
170     assert(r1 == r(81, 16));
171 
172     r1 = r(-1, 3);
173     r1 ^^= 3;
174     assert(r1 == r(-1, 27));
175     r1 ^^= -2;
176     assert(r1 == r(729, 1));
177 
178     assert(r1 == 729);
179     assert(r1 < 799);
180     assert(r1 < r(700*8, 3));
181     assert(r1 > r(700*2, 3));
182     assert(r1 == r(729, 1));
183     assert(r1.reciprocal == r(1, 729));
184 }
185 
186 foo!int();
187 foo!long();
188 foo!BigInt();
189 
190 // CTFE test
191 static assert(is(typeof({
192     enum bar = {
193         foo!int();
194         return true;
195     }();
196 })));
197 
198 static assert(is(typeof({
199     enum bar = {
200         foo!long();
201         return true;
202     }();
203 })));
204 
205 // pure nothrow @safe test
206 static assert(FuncAttr.isPure!(foo!int)
207            && FuncAttr.isNothrow!(foo!int)
208            && std.traits.isSafe!(foo!int));
209 
210 static assert(FuncAttr.isPure!(foo!long)
211            && FuncAttr.isNothrow!(foo!long)
212            && std.traits.isSafe!(foo!long));
213 
214 auto r1 = rational(729, 1);
215 
216 auto writer = appender!string;
217 formattedWrite(writer, "%(%08d / %04d%)", r1);
218 assert(writer.data == "00000729 / 0001");
219 
220 writer = appender!string;
221 formattedWrite(writer, "%(%2$s/%1$s%)", r1);
222 assert(writer.data == "1/729");
223 
224 writer = appender!string;
225 formattedWrite(writer, "%08d", r1);
226 assert(writer.data == "00000729/00000001");
227 
228 
229 // like literal
230 assert(-1.over(5) == rational(-1, 5));
231 assert(-1.rational(5) == rational(-1, 5));

Meta