1 /* 2 * Copyright (C) 2011 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.math; 18 19 import static com.google.common.math.MathTesting.ALL_LONG_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.NEGATIVE_INTEGER_CANDIDATES; 23 import static com.google.common.math.MathTesting.NEGATIVE_LONG_CANDIDATES; 24 import static com.google.common.math.MathTesting.POSITIVE_LONG_CANDIDATES; 25 import static java.math.BigInteger.valueOf; 26 import static java.math.RoundingMode.UNNECESSARY; 27 28 import com.google.common.annotations.GwtCompatible; 29 30 import junit.framework.TestCase; 31 32 import java.math.BigDecimal; 33 import java.math.BigInteger; 34 import java.math.RoundingMode; 35 36 /** 37 * Tests for LongMath. 38 * 39 * @author Louis Wasserman 40 */ 41 @GwtCompatible(emulated = true) 42 public class LongMathTest extends TestCase { 43 44 public void testLessThanBranchFree() { 45 for (long x : ALL_LONG_CANDIDATES) { 46 for (long y : ALL_LONG_CANDIDATES) { 47 BigInteger difference = BigInteger.valueOf(x).subtract(BigInteger.valueOf(y)); 48 if (fitsInLong(difference)) { 49 int expected = (x < y) ? 1 : 0; 50 int actual = LongMath.lessThanBranchFree(x, y); 51 assertEquals(expected, actual); 52 } 53 } 54 } 55 } 56 57 // Throws an ArithmeticException if "the simple implementation" of binomial coefficients overflows 58 59 public void testLog2ZeroAlwaysThrows() { 60 for (RoundingMode mode : ALL_ROUNDING_MODES) { 61 try { 62 LongMath.log2(0L, mode); 63 fail("Expected IllegalArgumentException"); 64 } catch (IllegalArgumentException expected) {} 65 } 66 } 67 68 public void testLog2NegativeAlwaysThrows() { 69 for (long x : NEGATIVE_LONG_CANDIDATES) { 70 for (RoundingMode mode : ALL_ROUNDING_MODES) { 71 try { 72 LongMath.log2(x, mode); 73 fail("Expected IllegalArgumentException"); 74 } catch (IllegalArgumentException expected) {} 75 } 76 } 77 } 78 79 /* Relies on the correctness of BigIntegerMath.log2 for all modes except UNNECESSARY. */ 80 public void testLog2MatchesBigInteger() { 81 for (long x : POSITIVE_LONG_CANDIDATES) { 82 for (RoundingMode mode : ALL_SAFE_ROUNDING_MODES) { 83 // The BigInteger implementation is tested separately, use it as the reference. 84 assertEquals(BigIntegerMath.log2(valueOf(x), mode), LongMath.log2(x, mode)); 85 } 86 } 87 } 88 89 /* Relies on the correctness of isPowerOfTwo(long). */ 90 public void testLog2Exact() { 91 for (long x : POSITIVE_LONG_CANDIDATES) { 92 // We only expect an exception if x was not a power of 2. 93 boolean isPowerOf2 = LongMath.isPowerOfTwo(x); 94 try { 95 assertEquals(x, 1L << LongMath.log2(x, UNNECESSARY)); 96 assertTrue(isPowerOf2); 97 } catch (ArithmeticException e) { 98 assertFalse(isPowerOf2); 99 } 100 } 101 } 102 103 // Relies on the correctness of BigIntegerMath.log10 for all modes except UNNECESSARY. 104 105 // Relies on the correctness of log10(long, FLOOR) and of pow(long, int). 106 107 // Relies on the correctness of BigIntegerMath.sqrt for all modes except UNNECESSARY. 108 109 /* Relies on the correctness of sqrt(long, FLOOR). */ 110 111 public void testGCDExhaustive() { 112 for (long a : POSITIVE_LONG_CANDIDATES) { 113 for (long b : POSITIVE_LONG_CANDIDATES) { 114 assertEquals(valueOf(a).gcd(valueOf(b)), valueOf(LongMath.gcd(a, b))); 115 } 116 } 117 } 118 119 // Depends on the correctness of BigIntegerMath.factorial. 120 121 // Depends on the correctness of BigIntegerMath.binomial. 122 public void testBinomial() { 123 for (int n = 0; n <= 70; n++) { 124 for (int k = 0; k <= n; k++) { 125 BigInteger expectedBig = BigIntegerMath.binomial(n, k); 126 long expectedLong = fitsInLong(expectedBig) ? expectedBig.longValue() : Long.MAX_VALUE; 127 assertEquals(expectedLong, LongMath.binomial(n, k)); 128 } 129 } 130 } 131 132 public void testBinomialOutside() { 133 for (int n = 0; n <= 50; n++) { 134 try { 135 LongMath.binomial(n, -1); 136 fail("Expected IllegalArgumentException"); 137 } catch (IllegalArgumentException expected) {} 138 try { 139 LongMath.binomial(n, n + 1); 140 fail("Expected IllegalArgumentException"); 141 } catch (IllegalArgumentException expected) {} 142 } 143 } 144 145 public void testBinomialNegative() { 146 for (int n : NEGATIVE_INTEGER_CANDIDATES) { 147 try { 148 LongMath.binomial(n, 0); 149 fail("Expected IllegalArgumentException"); 150 } catch (IllegalArgumentException expected) {} 151 } 152 } 153 154 public void testSqrtOfLongIsAtMostFloorSqrtMaxLong() { 155 long sqrtMaxLong = (long) Math.sqrt(Long.MAX_VALUE); 156 assertTrue(sqrtMaxLong <= LongMath.FLOOR_SQRT_MAX_LONG); 157 } 158 159 /** 160 * Helper method that asserts the arithmetic mean of x and y is equal 161 * to the expectedMean. 162 */ 163 private static void assertMean(long expectedMean, long x, long y) { 164 assertEquals("The expectedMean should be the same as computeMeanSafely", 165 expectedMean, computeMeanSafely(x, y)); 166 assertMean(x, y); 167 } 168 169 /** 170 * Helper method that asserts the arithmetic mean of x and y is equal 171 *to the result of computeMeanSafely. 172 */ 173 private static void assertMean(long x, long y) { 174 long expectedMean = computeMeanSafely(x, y); 175 assertEquals(expectedMean, LongMath.mean(x, y)); 176 assertEquals("The mean of x and y should equal the mean of y and x", 177 expectedMean, LongMath.mean(y, x)); 178 } 179 180 /** 181 * Computes the mean in a way that is obvious and resilient to 182 * overflow by using BigInteger arithmetic. 183 */ 184 private static long computeMeanSafely(long x, long y) { 185 BigInteger bigX = BigInteger.valueOf(x); 186 BigInteger bigY = BigInteger.valueOf(y); 187 BigDecimal bigMean = new BigDecimal(bigX.add(bigY)) 188 .divide(BigDecimal.valueOf(2), BigDecimal.ROUND_FLOOR); 189 // parseInt blows up on overflow as opposed to intValue() which does not. 190 return Long.parseLong(bigMean.toString()); 191 } 192 193 private static boolean fitsInLong(BigInteger big) { 194 return big.bitLength() <= 63; 195 } 196 } 197 198