1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.math;
18
19 import static com.google.common.math.MathTesting.ALL_INTEGER_CANDIDATES;
20 import static com.google.common.math.MathTesting.ALL_ROUNDING_MODES;
21 import static com.google.common.math.MathTesting.ALL_SAFE_ROUNDING_MODES;
22 import static com.google.common.math.MathTesting.EXPONENTS;
23 import static com.google.common.math.MathTesting.NEGATIVE_INTEGER_CANDIDATES;
24 import static com.google.common.math.MathTesting.NONZERO_INTEGER_CANDIDATES;
25 import static com.google.common.math.MathTesting.POSITIVE_INTEGER_CANDIDATES;
26 import static com.google.common.math.TestPlatform.intsCanGoOutOfRange;
27 import static java.math.BigInteger.valueOf;
28 import static java.math.RoundingMode.UNNECESSARY;
29
30 import com.google.common.annotations.GwtCompatible;
31
32 import junit.framework.TestCase;
33
34 import java.math.BigDecimal;
35 import java.math.BigInteger;
36 import java.math.RoundingMode;
37
38
39
40
41
42
43 @GwtCompatible(emulated = true)
44 public class IntMathTest extends TestCase {
45
46 public void testLessThanBranchFree() {
47 for (int x : ALL_INTEGER_CANDIDATES) {
48 for (int y : ALL_INTEGER_CANDIDATES) {
49 if (LongMath.fitsInInt((long) x - y)) {
50 int expected = (x < y) ? 1 : 0;
51 int actual = IntMath.lessThanBranchFree(x, y);
52 assertEquals(expected, actual);
53 }
54 }
55 }
56 }
57
58 public void testLog2ZeroAlwaysThrows() {
59 for (RoundingMode mode : ALL_ROUNDING_MODES) {
60 try {
61 IntMath.log2(0, mode);
62 fail("Expected IllegalArgumentException");
63 } catch (IllegalArgumentException expected) {}
64 }
65 }
66
67 public void testLog2NegativeAlwaysThrows() {
68 for (int x : NEGATIVE_INTEGER_CANDIDATES) {
69 for (RoundingMode mode : ALL_ROUNDING_MODES) {
70 try {
71 IntMath.log2(x, mode);
72 fail("Expected IllegalArgumentException");
73 } catch (IllegalArgumentException expected) {}
74 }
75 }
76 }
77
78
79 public void testLog2MatchesBigInteger() {
80 for (int x : POSITIVE_INTEGER_CANDIDATES) {
81 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
82 assertEquals(BigIntegerMath.log2(valueOf(x), mode), IntMath.log2(x, mode));
83 }
84 }
85 }
86
87
88 public void testLog2Exact() {
89 for (int x : POSITIVE_INTEGER_CANDIDATES) {
90
91 boolean isPowerOf2 = IntMath.isPowerOfTwo(x);
92 try {
93 assertEquals(x, 1 << IntMath.log2(x, UNNECESSARY));
94 assertTrue(isPowerOf2);
95 } catch (ArithmeticException e) {
96 assertFalse(isPowerOf2);
97 }
98 }
99 }
100
101
102
103
104
105
106
107
108
109
110
111 public void testDivNonZero() {
112 for (int p : NONZERO_INTEGER_CANDIDATES) {
113 for (int q : NONZERO_INTEGER_CANDIDATES) {
114 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) {
115
116
117 if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) {
118 continue;
119 }
120 int expected =
121 new BigDecimal(valueOf(p)).divide(new BigDecimal(valueOf(q)), 0, mode).intValue();
122 assertEquals(p + "/" + q, force32(expected), IntMath.divide(p, q, mode));
123 }
124 }
125 }
126 }
127
128 public void testDivNonZeroExact() {
129 for (int p : NONZERO_INTEGER_CANDIDATES) {
130 for (int q : NONZERO_INTEGER_CANDIDATES) {
131
132 if (p == -2147483648 && q == -1 && intsCanGoOutOfRange()) {
133 continue;
134 }
135 boolean dividesEvenly = (p % q) == 0;
136 try {
137 assertEquals(p + "/" + q, p, IntMath.divide(p, q, UNNECESSARY) * q);
138 assertTrue(p + "/" + q + " not expected to divide evenly", dividesEvenly);
139 } catch (ArithmeticException e) {
140 assertFalse(p + "/" + q + " expected to divide evenly", dividesEvenly);
141 }
142 }
143 }
144 }
145
146 public void testZeroDivIsAlwaysZero() {
147 for (int q : NONZERO_INTEGER_CANDIDATES) {
148 for (RoundingMode mode : ALL_ROUNDING_MODES) {
149 assertEquals(0, IntMath.divide(0, q, mode));
150 }
151 }
152 }
153
154 public void testDivByZeroAlwaysFails() {
155 for (int p : ALL_INTEGER_CANDIDATES) {
156 for (RoundingMode mode : ALL_ROUNDING_MODES) {
157 try {
158 IntMath.divide(p, 0, mode);
159 fail("Expected ArithmeticException");
160 } catch (ArithmeticException expected) {}
161 }
162 }
163 }
164
165 public void testMod() {
166 for (int x : ALL_INTEGER_CANDIDATES) {
167 for (int m : POSITIVE_INTEGER_CANDIDATES) {
168 assertEquals(valueOf(x).mod(valueOf(m)).intValue(), IntMath.mod(x, m));
169 }
170 }
171 }
172
173 public void testModNegativeModulusFails() {
174 for (int x : POSITIVE_INTEGER_CANDIDATES) {
175 for (int m : NEGATIVE_INTEGER_CANDIDATES) {
176 try {
177 IntMath.mod(x, m);
178 fail("Expected ArithmeticException");
179 } catch (ArithmeticException expected) {}
180 }
181 }
182 }
183
184 public void testModZeroModulusFails() {
185 for (int x : ALL_INTEGER_CANDIDATES) {
186 try {
187 IntMath.mod(x, 0);
188 fail("Expected ArithmeticException");
189 } catch (ArithmeticException expected) {}
190 }
191 }
192
193 public void testGCD() {
194 for (int a : POSITIVE_INTEGER_CANDIDATES) {
195 for (int b : POSITIVE_INTEGER_CANDIDATES) {
196 assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(IntMath.gcd(a, b)));
197 }
198 }
199 }
200
201 public void testGCDZero() {
202 for (int a : POSITIVE_INTEGER_CANDIDATES) {
203 assertEquals(a, IntMath.gcd(a, 0));
204 assertEquals(a, IntMath.gcd(0, a));
205 }
206 assertEquals(0, IntMath.gcd(0, 0));
207 }
208
209 public void testGCDNegativePositiveThrows() {
210 for (int a : NEGATIVE_INTEGER_CANDIDATES) {
211 try {
212 IntMath.gcd(a, 3);
213 fail("Expected IllegalArgumentException");
214 } catch (IllegalArgumentException expected) {}
215 try {
216 IntMath.gcd(3, a);
217 fail("Expected IllegalArgumentException");
218 } catch (IllegalArgumentException expected) {}
219 }
220 }
221
222 public void testGCDNegativeZeroThrows() {
223 for (int a : NEGATIVE_INTEGER_CANDIDATES) {
224 try {
225 IntMath.gcd(a, 0);
226 fail("Expected IllegalArgumentException");
227 } catch (IllegalArgumentException expected) {}
228 try {
229 IntMath.gcd(0, a);
230 fail("Expected IllegalArgumentException");
231 } catch (IllegalArgumentException expected) {}
232 }
233 }
234
235 public void testCheckedAdd() {
236 for (int a : ALL_INTEGER_CANDIDATES) {
237 for (int b : ALL_INTEGER_CANDIDATES) {
238 BigInteger expectedResult = valueOf(a).add(valueOf(b));
239 boolean expectedSuccess = fitsInInt(expectedResult);
240 try {
241 assertEquals(a + b, IntMath.checkedAdd(a, b));
242 assertTrue(expectedSuccess);
243 } catch (ArithmeticException e) {
244 assertFalse(expectedSuccess);
245 }
246 }
247 }
248 }
249
250 public void testCheckedSubtract() {
251 for (int a : ALL_INTEGER_CANDIDATES) {
252 for (int b : ALL_INTEGER_CANDIDATES) {
253 BigInteger expectedResult = valueOf(a).subtract(valueOf(b));
254 boolean expectedSuccess = fitsInInt(expectedResult);
255 try {
256 assertEquals(a - b, IntMath.checkedSubtract(a, b));
257 assertTrue(expectedSuccess);
258 } catch (ArithmeticException e) {
259 assertFalse(expectedSuccess);
260 }
261 }
262 }
263 }
264
265 public void testCheckedMultiply() {
266 for (int a : ALL_INTEGER_CANDIDATES) {
267 for (int b : ALL_INTEGER_CANDIDATES) {
268 BigInteger expectedResult = valueOf(a).multiply(valueOf(b));
269 boolean expectedSuccess = fitsInInt(expectedResult);
270 try {
271 assertEquals(a * b, IntMath.checkedMultiply(a, b));
272 assertTrue(expectedSuccess);
273 } catch (ArithmeticException e) {
274 assertFalse(expectedSuccess);
275 }
276 }
277 }
278 }
279
280 public void testCheckedPow() {
281 for (int b : ALL_INTEGER_CANDIDATES) {
282 for (int k : EXPONENTS) {
283 BigInteger expectedResult = valueOf(b).pow(k);
284 boolean expectedSuccess = fitsInInt(expectedResult);
285 try {
286 assertEquals(b + "^" + k, force32(expectedResult.intValue()), IntMath.checkedPow(b, k));
287 assertTrue(b + "^" + k + " should have succeeded", expectedSuccess);
288 } catch (ArithmeticException e) {
289 assertFalse(b + "^" + k + " should have failed", expectedSuccess);
290 }
291 }
292 }
293 }
294
295
296 public void testFactorial() {
297 for (int n = 0; n <= 50; n++) {
298 BigInteger expectedBig = BigIntegerMath.factorial(n);
299 int expectedInt = fitsInInt(expectedBig) ? expectedBig.intValue() : Integer.MAX_VALUE;
300 assertEquals(expectedInt, IntMath.factorial(n));
301 }
302 }
303
304 public void testFactorialNegative() {
305 for (int n : NEGATIVE_INTEGER_CANDIDATES) {
306 try {
307 IntMath.factorial(n);
308 fail("Expected IllegalArgumentException");
309 } catch (IllegalArgumentException expected) {}
310 }
311 }
312
313
314
315
316
317
318
319 private static void assertMean(int expectedMean, int x, int y) {
320 assertEquals("The expectedMean should be the same as computeMeanSafely",
321 expectedMean, computeMeanSafely(x, y));
322 assertMean(x, y);
323 }
324
325
326
327
328
329 private static void assertMean(int x, int y) {
330 int expectedMean = computeMeanSafely(x, y);
331 assertEquals(expectedMean, IntMath.mean(x, y));
332 assertEquals("The mean of x and y should equal the mean of y and x",
333 expectedMean, IntMath.mean(y, x));
334 }
335
336
337
338
339
340 private static int computeMeanSafely(int x, int y) {
341 BigInteger bigX = BigInteger.valueOf(x);
342 BigInteger bigY = BigInteger.valueOf(y);
343 BigDecimal bigMean = new BigDecimal(bigX.add(bigY))
344 .divide(BigDecimal.valueOf(2), BigDecimal.ROUND_FLOOR);
345
346 return Integer.parseInt(bigMean.toString());
347 }
348
349 private static boolean fitsInInt(BigInteger big) {
350 return big.bitLength() <= 31;
351 }
352
353 private static int force32(int value) {
354
355 return value & 0xffffffff;
356 }
357 }
358