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

Meta