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));
This is the type that you can calculate fraction. Rational!T has two integral T values.