OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 import "package:expect/expect.dart"; |
| 6 |
| 7 import "dart:math" show pow; |
| 8 |
| 9 var smallNumber = 1234567890; // is 31-bit integer. |
| 10 var mediumNumber = 1234567890123456; // is 53-bit integer |
| 11 var bigNumber = 590295810358705600000; // is > 64-bit integer, exact as double. |
| 12 |
| 13 testModPow() { |
| 14 test(x, e, m, expectedResult) { |
| 15 // Check that expected result is correct, using an unoptimized version. |
| 16 assert(() { |
| 17 if (1 is double) return true; // Don't have bignums. |
| 18 slowModPow(x, e, m) { |
| 19 var r = 1; |
| 20 while (e > 0) { |
| 21 if (e.isOdd) r = (r * x) % m; |
| 22 e >>= 1; |
| 23 x = (x * x) % m; |
| 24 } |
| 25 return r; |
| 26 } |
| 27 return slowModPow(x, e, m) == expectedResult; |
| 28 }); |
| 29 var result = x.modPow(e, m); |
| 30 Expect.equals(expectedResult, result, "$x.modPow($e, $m)"); |
| 31 } |
| 32 |
| 33 test(10, 20, 1, 0); |
| 34 test(1234567890, 1000000001, 19, 11); |
| 35 test(1234567890, 19, 1000000001, 122998977); |
| 36 test(19, 1234567890, 1000000001, 619059596); |
| 37 test(19, 1000000001, 1234567890, 84910879); |
| 38 test(1000000001, 19, 1234567890, 872984351); |
| 39 test(1000000001, 1234567890, 19, 0); |
| 40 test(12345678901234567890, 10000000000000000001, 19, 2); |
| 41 test(12345678901234567890, 19, 10000000000000000001, 3239137215315834625); |
| 42 test(19, 12345678901234567890, 10000000000000000001, 4544207837373941034); |
| 43 test(19, 10000000000000000001, 12345678901234567890, 11135411705397624859); |
| 44 test(10000000000000000001, 19, 12345678901234567890, 2034013733189773841); |
| 45 test(10000000000000000001, 12345678901234567890, 19, 1); |
| 46 test(12345678901234567890, 19, 10000000000000000001, 3239137215315834625); |
| 47 test(12345678901234567890, 10000000000000000001, 19, 2); |
| 48 test(123456789012345678901234567890, |
| 49 123456789012345678901234567891, |
| 50 123456789012345678901234567899, |
| 51 116401406051033429924651549616); |
| 52 test(123456789012345678901234567890, |
| 53 123456789012345678901234567899, |
| 54 123456789012345678901234567891, |
| 55 123456789012345678901234567890); |
| 56 test(123456789012345678901234567899, |
| 57 123456789012345678901234567890, |
| 58 123456789012345678901234567891, |
| 59 35088523091000351053091545070); |
| 60 test(123456789012345678901234567899, |
| 61 123456789012345678901234567891, |
| 62 123456789012345678901234567890, |
| 63 18310047270234132455316941949); |
| 64 test(123456789012345678901234567891, |
| 65 123456789012345678901234567899, |
| 66 123456789012345678901234567890, |
| 67 1); |
| 68 test(123456789012345678901234567891, |
| 69 123456789012345678901234567890, |
| 70 123456789012345678901234567899, |
| 71 40128068573873018143207285483); |
| 72 |
| 73 } |
| 74 |
| 75 testModInverse() { |
| 76 test(x, m, expectedResult) { |
| 77 //print("$x op $m == $expectedResult"); |
| 78 // Check that expectedResult is an inverse. |
| 79 assert(expectedResult < m); |
| 80 // The 1 % m handles the m = 1 special case. |
| 81 // This test may overflow if we don't have bignums, so only run on VM. |
| 82 assert(1 is double || (((x % m) * expectedResult) - 1) % m == 0); |
| 83 |
| 84 var result = x.modInverse(m); |
| 85 Expect.equals(expectedResult, result, "$x modinv $m"); |
| 86 |
| 87 if (x > m) { |
| 88 x = x % m; |
| 89 var result = x.modInverse(m); |
| 90 Expect.equals(expectedResult, result, "$x modinv $m"); |
| 91 } |
| 92 } |
| 93 |
| 94 testThrows(x, m) { |
| 95 // Throws if not co-prime, which is a symmetric property. |
| 96 Expect.throws(() => x.modInverse(m), null, "$x modinv $m"); |
| 97 Expect.throws(() => m.modInverse(x), null, "$m modinv $x"); |
| 98 } |
| 99 |
| 100 test(1, 1, 0); |
| 101 |
| 102 testThrows(0, 1000000001); |
| 103 testThrows(2, 4); |
| 104 testThrows(99, 9); |
| 105 testThrows(19, 1000000001); |
| 106 testThrows(123456789012345678901234567890, 123456789012345678901234567899); |
| 107 |
| 108 // Co-prime numbers |
| 109 test(1234567890, 19, 11); |
| 110 test(1234567890, 1000000001, 189108911); |
| 111 test(19, 1234567890, 519818059); |
| 112 test(1000000001, 1234567890, 1001100101); |
| 113 |
| 114 test(12345, 12346, 12345); |
| 115 test(12345, 12346, 12345); |
| 116 |
| 117 test(smallNumber, 137, 42); |
| 118 test(137, smallNumber, 856087223); |
| 119 test(mediumNumber, 137, 77); |
| 120 test(137, mediumNumber, 540686667207353); |
| 121 test(bigNumber, 137, 128); /// bignum: ok |
| 122 // Bigger numbers as modulo is tested in big_integer_arith_vm_test.dart. |
| 123 // Big doubles are not co-prime, so there is nothing to test for dart2js. |
| 124 } |
| 125 |
| 126 testGcd() { |
| 127 // Call testFunc with all combinations and orders of plus/minus |
| 128 // value and other. |
| 129 callCombos(value, other, testFunc) { |
| 130 testFunc(value, other); |
| 131 testFunc(value, -other); |
| 132 testFunc(-value, other); |
| 133 testFunc(-value, -other); |
| 134 if (value == other) return; |
| 135 testFunc(other, value); |
| 136 testFunc(other, -value); |
| 137 testFunc(-other, value); |
| 138 testFunc(-other, -value); |
| 139 } |
| 140 |
| 141 // Test that gcd of value and other (non-negative) is expectedResult. |
| 142 // Tests all combinations of positive and negative values and order of |
| 143 // operands, so use positive values and order is not important. |
| 144 test(value, other, [expectedResult]) { |
| 145 assert(value % expectedResult == 0); // Check for bug in test. |
| 146 assert(other % expectedResult == 0); |
| 147 callCombos(value, other, (a, b) { |
| 148 var result = a.gcd(b); |
| 149 /// Check that the result is a divisor. |
| 150 Expect.equals(0, a % result, "$result | $a"); |
| 151 Expect.equals(0, b % result, "$result | $b"); |
| 152 // Check for bug in test. If assert fails, the expected value is too low, |
| 153 // and the gcd call has found a greater common divisor. |
| 154 assert(result >= expectedResult); |
| 155 Expect.equals(expectedResult, result, "$a.gcd($b)"); |
| 156 }); |
| 157 } |
| 158 |
| 159 // Test that gcd of value and other (non-negative) throws. |
| 160 testThrows(value, other) { |
| 161 callCombos(value, other, (a, b) { |
| 162 Expect.throws(() => a.gcd(b), null, "$a.gcd($b)"); |
| 163 }); |
| 164 } |
| 165 |
| 166 // Throws if either operand is zero, and if both operands are zero. |
| 167 testThrows(0, 1000); |
| 168 testThrows(0, 0); |
| 169 |
| 170 // Format: |
| 171 // test(value1, value2, expectedResult); |
| 172 test(1, 1, 1); // both are 1 |
| 173 test(1, 2, 1); // one is 1 |
| 174 test(3, 5, 1); // coprime. |
| 175 test(37, 37, 37); // Same larger prime. |
| 176 |
| 177 test(9999, 7272, 909); // Larger numbers |
| 178 |
| 179 // Multiplying both operands by a number multiplies result by same number. |
| 180 test(693, 609, 21); |
| 181 test(693 << 5, 609 << 5, 21 << 5); |
| 182 test(693 * 937, 609 * 937, 21 * 937); |
| 183 test(693 * pow(2, 32), 609 * pow(2, 32), 21 * pow(2, 32)); |
| 184 test(693 * pow(2, 52), 609 * pow(2, 52), 21 * pow(2, 52)); |
| 185 test(693 * pow(2, 53), 609 * pow(2, 53), 21 * pow(2, 53)); // Regression. |
| 186 test(693 * pow(2, 99), 609 * pow(2, 99), 21 * pow(2, 99)); |
| 187 |
| 188 test(1234567890, 19, 1); |
| 189 test(1234567890, 1000000001, 1); |
| 190 test(19, 1000000001, 19); |
| 191 |
| 192 test(0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF); |
| 193 test(0x3FFFFFFF, 0x40000000, 1); |
| 194 |
| 195 test(pow(2, 54), pow(2, 53), pow(2, 53)); |
| 196 |
| 197 test((pow(2, 52) - 1) * pow(2, 14), |
| 198 (pow(2, 26) - 1) * pow(2, 22), |
| 199 (pow(2, 26) - 1) * pow(2, 14)); |
| 200 } |
| 201 |
| 202 main() { |
| 203 testModPow(); /// modPow: ok |
| 204 testModInverse(); |
| 205 testGcd(); |
| 206 } |
| 207 |
OLD | NEW |