1 module deimos.gmp.operators; 2 3 import deimos.gmp.gmp; 4 import deimos.gmp.integer; 5 6 import std.string; 7 import std.stdio; 8 import core.stdc.config : c_long, c_ulong; 9 10 static import core.stdc.stdio; 11 12 debug int TestCount = 0; 13 14 enum DefaultBase = 10; 15 16 struct Integer 17 { 18 mpz_t value; 19 20 void init(){ 21 mpz_init(&value); 22 } 23 24 this(in c_long v){ 25 mpz_init_set_si(&value, v); 26 } 27 this(in c_ulong v){ 28 mpz_init_set_ui(&value, v); 29 } 30 this(in double v){ 31 mpz_init_set_d(&value, v); 32 } 33 this(in string v){ 34 mpz_init_set_str(&value, toStringz(v), DefaultBase); 35 } 36 this()(auto ref const Integer v){ 37 mpz_init_set(&value, &v.value); 38 } 39 40 ~this(){ 41 mpz_clear(&value); 42 } 43 this(this){ 44 mpz_t tmp; 45 mpz_init_set(&tmp, &value); 46 value = tmp; 47 } 48 49 Integer opAssign()(auto ref const Integer v) out(result) { 50 assert(mpz_cmp(&result.value, &v.value) == 0); 51 }body{ 52 mpz_set(&value, &v.value); 53 return this; 54 } 55 56 ref Integer opOpAssign(string op)(in c_ulong v) 57 if (op == "+") { 58 mpz_add_ui(&value, &value, v); 59 return this; 60 } 61 ref Integer opOpAssign(string op)(auto ref const Integer v) 62 if (op == "+"){ 63 mpz_add(&value, &value, &v.value); 64 return this; 65 } 66 ref Integer opOpAssign(string op)(in c_ulong v) 67 if (op == "-"){ 68 mpz_sub_ui(&value, &value, v); 69 return this; 70 } 71 ref Integer opOpAssign(string op)(auto ref const Integer v) 72 if (op == "-"){ 73 mpz_sub(&value, &value, &v.value); 74 return this; 75 } 76 ref Integer opOpAssign(string op)(in c_ulong v) 77 if (op == "*"){ 78 mpz_mul_ui(&value, &value, v); 79 return this; 80 } 81 ref Integer opOpAssign(string op)(in c_long v) 82 if (op == "*"){ 83 mpz_mul_si(&value, &value, v); 84 return this; 85 } 86 ref Integer opOpAssign(string op)(auto ref const Integer v) 87 if (op == "*"){ 88 mpz_mul(&value, &value, &v.value); 89 return this; 90 } 91 ref Integer opOpAssign(string op)(in c_ulong v) 92 if (op == "/"){ 93 mpz_fdiv_q_ui(&value, &value, v); 94 return this; 95 } 96 ref Integer opOpAssign(string op)(auto ref const Integer v) 97 if (op == "/"){ 98 mpz_fdiv_q(&value, &value, &v.value); 99 return this; 100 } 101 ref Integer opOpAssign(string op)(in c_ulong v) 102 if (op == "%"){ 103 mpz_mod_ui(&value, &value, v); 104 return this; 105 } 106 ref Integer opOpAssign(string op)(auto ref const Integer v) 107 if (op == "%"){ 108 mpz_mod(&value, &value, &v.value); 109 return this; 110 } 111 ref Integer opOpAssign(string op)(in c_ulong v) 112 if (op == "^^"){ 113 mpz_pow_ui(&value, &value, v); 114 return this; 115 } 116 ref Integer opOpAssign(string op)(auto ref const Integer v) 117 if (op == "&"){ 118 mpz_and(&value, &value, &v.value); 119 return this; 120 } 121 ref Integer opOpAssign(string op)(auto ref const Integer v) 122 if (op == "|"){ 123 mpz_ior(&value, &value, &v.value); 124 return this; 125 } 126 ref Integer opOpAssign(string op)(auto ref const Integer v) 127 if (op == "^"){ 128 mpz_xor(&value, &value, &v.value); 129 return this; 130 } 131 132 Integer opUnary(string op)() 133 if (op == "-"){ 134 Integer res = this; 135 mpz_neg(&res.value, &value); 136 return res; 137 } 138 ref Integer opUnary(string op)() 139 if (op == "--"){ 140 mpz_sub_ui(&value, &value, 1UL); 141 return this; 142 } 143 ref Integer opUnary(string op)() 144 if (op == "++"){ 145 mpz_add_ui(&value, &value, 1UL); 146 return this; 147 } 148 mpz_t opUnary(string op)() const 149 if (op == "*"){ 150 return *&value; 151 } 152 153 Integer opBinary(string op)(in c_ulong v) 154 if (op == "+"){ 155 Integer ret = this; 156 mpz_add_ui(&ret.value, &value, v); 157 return ret; 158 } 159 Integer opBinary(string op)(auto ref const Integer v) 160 if (op == "+"){ 161 Integer ret = this; 162 mpz_add(&ret.value, &value, &v.value); 163 return ret; 164 } 165 Integer opBinary(string op)(in c_ulong v) 166 if (op == "-"){ 167 Integer ret = this; 168 mpz_sub_ui(&ret.value, &value, v); 169 return ret; 170 } 171 Integer opBinaryRight(string op)(in c_ulong v) 172 if (op == "-"){ 173 Integer ret = this; 174 mpz_ui_sub(&ret.value, v, &value); 175 return ret; 176 } 177 Integer opBinary(string op)(auto ref const Integer v) 178 if (op == "-"){ 179 Integer ret = this; 180 mpz_sub(&ret.value, &value, &v.value); 181 return ret; 182 } 183 Integer opBinary(string op)(in c_ulong v) 184 if (op == "*"){ 185 Integer ret = this; 186 mpz_mul_ui(&ret.value, &value, v); 187 return ret; 188 } 189 Integer opBinary(string op)(in c_long v) 190 if (op == "*"){ 191 Integer ret = this; 192 mpz_mul_si(&ret.value, &value, v); 193 return ret; 194 } 195 Integer opBinary(string op)(auto ref const Integer v) 196 if (op == "*"){ 197 Integer ret = this; 198 mpz_mul(&ret.value, &value, &v.value); 199 return ret; 200 } 201 ref Integer abs() { 202 mpz_abs(&value, &value); 203 return this; 204 } 205 Integer opBinary(string op)(in c_ulong v) 206 if (op == "/"){ 207 Integer ret = this; 208 mpz_fdiv_q_ui(&ret.value, &value, v); 209 return ret; 210 } 211 Integer opBinary(string op)(auto ref const Integer v) 212 if (op == "/"){ 213 Integer ret = this; 214 mpz_fdiv_q(&ret.value, &value, &v.value); 215 return ret; 216 } 217 Integer opBinary(string op)(in c_ulong v) 218 if (op == "%"){ 219 Integer ret = this; 220 mpz_mod_ui(&ret.value, &value, v); 221 return ret; 222 } 223 Integer opBinary(string op)(auto ref const Integer v) 224 if (op == "%"){ 225 Integer ret = this; 226 mpz_mod(&ret.value, &value, &v.value); 227 return ret; 228 } 229 Integer opBinary(string op)(in c_ulong v) 230 if (op == "^^"){ 231 Integer ret = this; 232 mpz_pow_ui(&ret.value, &value, v); 233 return ret; 234 } 235 Integer opBinary(string op)(auto ref const Integer v) 236 if (op == "&"){ 237 Integer ret = this; 238 mpz_and(&ret.value, &value, &v.value); 239 } 240 Integer opBinary(string op)(auto ref const Integer v) 241 if (op == "|"){ 242 Integer ret = this; 243 mpz_ior(&ret.value, &value, &v.value); 244 } 245 Integer opBinary(string op)(auto ref const Integer v) 246 if (op == "^"){ 247 Integer ret = this; 248 mpz_xor(&ret.value, &value, &v.value); 249 } 250 251 c_ulong opCast(T : c_ulong)() const { 252 return mpz_get_ui(&value); 253 } 254 c_long opCast(T : c_long)() const { 255 return mpz_get_si(&value); 256 } 257 double opCast(T : double)() const { 258 return mpz_get_d(&value); 259 } 260 string opCast(T : string)() const { 261 return toString(mpz_get_str(null, DefaultBase, &value)); 262 } 263 mpz_ptr opCast(T : mpz_ptr)() const { 264 return cast(mpz_ptr)&value; 265 } 266 267 bool opEquals(in c_ulong v) const { 268 return mpz_cmp_ui(&value, v) == 0; 269 } 270 bool opEquals(in c_long v) const { 271 return mpz_cmp_si(&value, v) == 0; 272 } 273 bool opEquals(in double v) const { 274 return mpz_cmp_d(&value, v) == 0; 275 } 276 bool opEquals()(auto ref const Integer v) const { 277 return mpz_cmp(&value, &v.value) == 0; 278 } 279 280 int opCmp(in c_ulong v) const { 281 return mpz_cmp_ui(&value, v); 282 } 283 int opCmp(in c_long v) const { 284 return mpz_cmp_si(&value, v); 285 } 286 int opCmp(in double v) const { 287 return mpz_cmp_d(&value, v); 288 } 289 int opCmp()(auto ref const Integer v) const { 290 return mpz_cmp(&value, &v.value); 291 } 292 293 void print() const { 294 mpz_out_str(core.stdc.stdio.stdout, DefaultBase, &value); 295 } 296 void println() const{ 297 print(); 298 core.stdc.stdio.printf("\n"); 299 } 300 } 301 302 //Addition 303 unittest{ 304 pragma(msg, "Compiling Test: Addition"); 305 debug writeln("Running Test: Addition"); 306 Integer x = 4L; 307 Integer y = 10UL; 308 auto z = x; 309 auto ans = x + 12 + y + 5 + z; 310 assert(ans == 4UL + 12 + 10 + 5 + 4); 311 ans += x; 312 ans += 5UL; 313 assert(ans == 4UL + 12 + 10 + 5 + 4 + 4 + 5); 314 ans++; 315 assert(ans == 4UL + 12 + 10 + 5 + 4 + 4 + 5 + 1); 316 debug ++TestCount; 317 } 318 319 //Subtraction 320 unittest{ 321 pragma(msg, "Compiling Test: Subtraction"); 322 debug writeln("Running Test: Subtraction"); 323 Integer x = 100L; 324 auto y = Integer(9.8); //9 325 Integer z = c_ulong.max; 326 auto ans = z - x - 200 - y; 327 assert(ans == c_ulong.max - 100 - 200 - 9); 328 ans -= Integer(4.3); 329 ans -= 100000UL; 330 assert(ans == c_ulong.max - 100 - 200 - 9 - 4 - 100000); 331 debug ++TestCount; 332 } 333 334 //Multiplication 335 unittest{ 336 pragma(msg, "Compiling Test: Multiplication"); 337 debug writeln("Running Test: Multiplication"); 338 auto x = Integer("10"); 339 Integer y = 20UL; 340 Integer z = -320L; 341 auto ans = x * y * z; 342 assert(ans == -10L * 20 * 320); 343 ans *= 3L; 344 ans *= Integer(100UL); 345 assert(ans == -10L * 20 * 320 * 3 * 100); 346 debug ++TestCount; 347 } 348 349 //Division 350 unittest{ 351 pragma(msg, "Compiling Test: Division"); 352 debug writeln("Running Test: Division"); 353 auto x = Integer(100UL); 354 Integer y = 10UL; 355 Integer z = -1L; 356 auto ans = (x / y) / z; 357 assert(ans == (100L / 10) / (-1)); 358 ans /= 5L; 359 ans /= Integer(2.3); 360 assert(ans == -1L); 361 debug ++TestCount; 362 } 363 364 //Fermats Little Theorem 365 unittest{ 366 //calculate a mersenne prime, M(p) = 2 ^ p - 1 367 Integer M(in c_ulong p) { 368 Integer x = 2UL; 369 x ^^= p; 370 return x - 1; 371 } 372 373 pragma(msg, "Compiling Test: Fermats Little Theorem"); 374 debug writeln("Running Test: Fermats Little Theorem"); 375 /* 376 Fermats little theorem: a ^ p ≡ a (mod p) ∀ prime p 377 check Fermats little theorem for a ≤ 100000 and all mersene primes M(p) : p ≤ 127 378 */ 379 foreach (const c_ulong i; [2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127]) 380 { 381 for (c_ulong j = 2; j <= 100000; j++){ 382 Integer p = M(i); 383 Integer a = j; 384 Integer lhs = 0L; 385 mpz_powm( 386 cast(mpz_ptr)lhs, 387 cast(mpz_ptr)a, 388 cast(mpz_ptr)p, 389 cast(mpz_ptr)p); 390 //lhs = a^p (mod p) 391 assert(lhs == a % p); 392 } 393 } 394 debug ++TestCount; 395 } 396 397 //Euler's Sum of Powers Conjecture counter example 398 unittest{ 399 400 pragma(msg, "Compiling Test: Euler's Sum of Powers Conjecture counter example"); 401 debug writeln("Running Test: Euler's Sum of Powers Conjecture counter example"); 402 403 /* 404 a^5 + b^5 + c^5 + d^5 = e^5 405 Lander & Parkin, 1966 found the first counter example: 406 27^5 + 84^5 + 110^5 + 133^5 = 144^5 407 this test is going to search for this counter example by 408 brute force for all positive a, b, c, d ≤ 200 409 */ 410 411 enum LIMIT = 200; 412 enum POWER = 5; 413 414 bool found = false; 415 416 Integer r1; 417 r1.init(); 418 outermost: for (c_ulong a = 1; a <= LIMIT; a++){ 419 for (c_ulong b = a; b <= LIMIT; b++){ 420 for (c_ulong c = b; c <= LIMIT; c++){ 421 for (c_ulong d = c; d <= LIMIT; d++){ 422 r1 = (Integer(a) ^^ POWER) + 423 (Integer(b) ^^ POWER) + 424 (Integer(c) ^^ POWER) + 425 (Integer(d) ^^ POWER); 426 Integer rem = 0L; 427 mpz_rootrem(cast(mpz_ptr)r1, 428 cast(mpz_ptr)rem, 429 cast(mpz_ptr)r1, 430 POWER); 431 if (rem == 0UL){ 432 debug printf("Counter Example Found: %lu^5 + %lu^5 + %lu^5 + %lu^5 = %lu^5\n", 433 a, b, c, d, cast(c_ulong)r1); 434 found = true; 435 break outermost; 436 } 437 } 438 } 439 } 440 } 441 assert(found); 442 debug ++TestCount; 443 } 444 445 unittest{ 446 debug writeln("Number of Tests Run: ", TestCount); 447 }