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