1 /* 2 * Copyright (C) 2015 The Android Open Source Project 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 // A test for BoundedRationals package. 18 19 package com.android.calculator2; 20 21 import com.hp.creals.CR; 22 import com.hp.creals.UnaryCRFunction; 23 24 import junit.framework.AssertionFailedError; 25 import junit.framework.TestCase; 26 27 import java.math.BigInteger; 28 29 public class BRTest extends TestCase { check(boolean x, String s)30 private static void check(boolean x, String s) { 31 if (!x) throw new AssertionFailedError(s); 32 } 33 final static int TEST_PREC = -100; // 100 bits to the right of 34 // binary point. checkEq(BoundedRational x, CR y, String s)35 private static void checkEq(BoundedRational x, CR y, String s) { 36 check(x.CRValue().compareTo(y, TEST_PREC) == 0, s); 37 } checkWeakEq(BoundedRational x, CR y, String s)38 private static void checkWeakEq(BoundedRational x, CR y, String s) { 39 if (x != null) checkEq(x, y, s); 40 } 41 42 private final static UnaryCRFunction ASIN = UnaryCRFunction.asinFunction; 43 private final static UnaryCRFunction ACOS = UnaryCRFunction.acosFunction; 44 private final static UnaryCRFunction ATAN = UnaryCRFunction.atanFunction; 45 private final static UnaryCRFunction TAN = UnaryCRFunction.tanFunction; 46 private final static BoundedRational BR_0 = new BoundedRational(0); 47 private final static BoundedRational BR_M1 = new BoundedRational(-1); 48 private final static BoundedRational BR_2 = new BoundedRational(2); 49 private final static BoundedRational BR_M2 = new BoundedRational(-2); 50 private final static BoundedRational BR_15 = new BoundedRational(15); 51 private final static BoundedRational BR_390 = new BoundedRational(390); 52 private final static BoundedRational BR_M390 = new BoundedRational(-390); 53 private final static CR CR_1 = CR.valueOf(1); 54 55 private final static CR RADIANS_PER_DEGREE = CR.PI.divide(CR.valueOf(180)); 56 private final static CR DEGREES_PER_RADIAN = CR.valueOf(180).divide(CR.PI); 57 private final static CR LN10 = CR.valueOf(10).ln(); 58 toRadians(CR x)59 private static CR toRadians(CR x) { 60 return x.multiply(RADIANS_PER_DEGREE); 61 } 62 fromRadians(CR x)63 private static CR fromRadians(CR x) { 64 return x.multiply(DEGREES_PER_RADIAN); 65 } 66 67 // We assume that x is simple enough that we don't overflow bounds. checkBR(BoundedRational x)68 private static void checkBR(BoundedRational x) { 69 check(x != null, "test data should not be null"); 70 CR xAsCR = x.CRValue(); 71 checkEq(BoundedRational.add(x, BoundedRational.ONE), xAsCR.add(CR_1), 72 "add 1:" + x); 73 checkEq(BoundedRational.subtract(x, BoundedRational.MINUS_THIRTY), 74 xAsCR.subtract(CR.valueOf(-30)), "sub -30:" + x); 75 checkEq(BoundedRational.multiply(x, BR_15), 76 xAsCR.multiply(CR.valueOf(15)), "multiply 15:" + x); 77 checkEq(BoundedRational.divide(x, BR_15), 78 xAsCR.divide(CR.valueOf(15)), "divide 15:" + x); 79 checkWeakEq(BoundedRational.sin(x), xAsCR.sin(), "sin:" + x); 80 checkWeakEq(BoundedRational.cos(x), xAsCR.cos(), "cos:" + x); 81 checkWeakEq(BoundedRational.tan(x), TAN.execute(xAsCR), "tan:" + x); 82 checkWeakEq(BoundedRational.degreeSin(x), toRadians(xAsCR).sin(), 83 "degree sin:" + x); 84 checkWeakEq(BoundedRational.degreeCos(x), toRadians(xAsCR).cos(), 85 "degree cos:" + x); 86 BigInteger big_x = BoundedRational.asBigInteger(x); 87 long long_x = (big_x == null? 0 : big_x.longValue()); 88 try { 89 checkWeakEq(BoundedRational.degreeTan(x), 90 TAN.execute(toRadians(xAsCR)), "degree tan:" + x); 91 check((long_x - 90) % 180 != 0, "missed undefined tan: " + x); 92 } catch (ArithmeticException ignored) { 93 check((long_x - 90) % 180 == 0, "exception on defined tan: " + x); 94 } 95 if (x.compareTo(BoundedRational.THIRTY) <= 0 96 && x.compareTo(BoundedRational.MINUS_THIRTY) >= 0) { 97 checkWeakEq(BoundedRational.exp(x), xAsCR.exp(), "exp:" + x); 98 checkWeakEq(BoundedRational.pow(BR_15, x), 99 CR.valueOf(15).ln().multiply(xAsCR).exp(), 100 "pow(15,x):" + x); 101 } 102 if (x.compareTo(BoundedRational.ONE) <= 0 103 && x.compareTo(BoundedRational.MINUS_ONE) >= 0) { 104 checkWeakEq(BoundedRational.asin(x), ASIN.execute(xAsCR), 105 "asin:" + x); 106 checkWeakEq(BoundedRational.acos(x), ACOS.execute(xAsCR), 107 "acos:" + x); 108 checkWeakEq(BoundedRational.degreeAsin(x), 109 fromRadians(ASIN.execute(xAsCR)), "degree asin:" + x); 110 checkWeakEq(BoundedRational.degreeAcos(x), 111 fromRadians(ACOS.execute(xAsCR)), "degree acos:" + x); 112 } 113 checkWeakEq(BoundedRational.atan(x), fromRadians(ATAN.execute(xAsCR)), 114 "atan:" + x); 115 checkWeakEq(BoundedRational.degreeAtan(x), 116 fromRadians(ATAN.execute(xAsCR)), "degree atan:" + x); 117 if (x.signum() > 0) { 118 checkWeakEq(BoundedRational.ln(x), xAsCR.ln(), "ln:" + x); 119 checkWeakEq(BoundedRational.log(x), xAsCR.ln().divide(LN10), 120 "log:" + x); 121 checkWeakEq(BoundedRational.sqrt(x), xAsCR.sqrt(), "sqrt:" + x); 122 checkEq(BoundedRational.pow(x, BR_15), 123 xAsCR.ln().multiply(CR.valueOf(15)).exp(), 124 "pow(x,15):" + x); 125 } 126 } 127 testBR()128 public void testBR() { 129 BoundedRational b = new BoundedRational(4,-6); 130 check(b.toString().equals("4/-6"), "toString(4/-6)"); 131 check(b.toNiceString().equals("-2/3"),"toNiceString(4/-6)"); 132 checkEq(BR_0, CR.valueOf(0), "0"); 133 checkEq(BR_390, CR.valueOf(390), "390"); 134 checkEq(BR_15, CR.valueOf(15), "15"); 135 checkEq(BR_M390, CR.valueOf(-390), "-390"); 136 checkEq(BR_M1, CR.valueOf(-1), "-1"); 137 checkEq(BR_2, CR.valueOf(2), "2"); 138 checkEq(BR_M2, CR.valueOf(-2), "-2"); 139 check(BR_0.signum() == 0, "signum(0)"); 140 check(BR_M1.signum() == -1, "signum(-1)"); 141 check(BR_2.signum() == 1, "signum(2)"); 142 check(BoundedRational.asBigInteger(BR_390).intValue() == 390, "390.asBigInteger()"); 143 check(BoundedRational.asBigInteger(BoundedRational.HALF) == null, "1/2.asBigInteger()"); 144 check(BoundedRational.asBigInteger(BoundedRational.MINUS_HALF) == null, 145 "-1/2.asBigInteger()"); 146 check(BoundedRational.asBigInteger(new BoundedRational(15, -5)).intValue() == -3, 147 "-15/5.asBigInteger()"); 148 check(BoundedRational.digitsRequired(BoundedRational.ZERO) == 0, "digitsRequired(0)"); 149 check(BoundedRational.digitsRequired(BoundedRational.HALF) == 1, "digitsRequired(1/2)"); 150 check(BoundedRational.digitsRequired(BoundedRational.MINUS_HALF) == 1, 151 "digitsRequired(-1/2)"); 152 check(BoundedRational.digitsRequired(new BoundedRational(1,-2)) == 1, 153 "digitsRequired(1/-2)"); 154 check(BoundedRational.fact(BoundedRational.ZERO).equals(BoundedRational.ONE), "0!"); 155 check(BoundedRational.fact(BoundedRational.ONE).equals(BoundedRational.ONE), "1!"); 156 check(BoundedRational.fact(BoundedRational.TWO).equals(BoundedRational.TWO), "2!"); 157 check(BoundedRational.fact(BR_15).equals(new BoundedRational(1307674368000L)), "15!"); 158 // We check values that include all interesting degree values. 159 BoundedRational r = BR_M390; 160 while (!r.equals(BR_390)) { 161 check(r != null, "loop counter overflowed!"); 162 checkBR(r); 163 r = BoundedRational.add(r, BR_15); 164 } 165 checkBR(BoundedRational.HALF); 166 checkBR(BoundedRational.MINUS_HALF); 167 checkBR(BoundedRational.ONE); 168 checkBR(BoundedRational.MINUS_ONE); 169 checkBR(new BoundedRational(1000)); 170 checkBR(new BoundedRational(100)); 171 checkBR(new BoundedRational(4,9)); 172 check(BoundedRational.sqrt(new BoundedRational(4,9)) != null, 173 "sqrt(4/9) is null"); 174 checkBR(BoundedRational.negate(new BoundedRational(4,9))); 175 checkBR(new BoundedRational(5,9)); 176 checkBR(new BoundedRational(5,10)); 177 checkBR(new BoundedRational(5,10)); 178 checkBR(new BoundedRational(4,13)); 179 checkBR(new BoundedRational(36)); 180 checkBR(BoundedRational.negate(new BoundedRational(36))); 181 check(BoundedRational.pow(null, BR_15) == null, "pow(null, 15)"); 182 } 183 testBRexceptions()184 public void testBRexceptions() { 185 try { 186 BoundedRational.ln(BR_M1); 187 check(false, "ln(-1)"); 188 } catch (ArithmeticException ignored) {} 189 try { 190 BoundedRational.log(BR_M2); 191 check(false, "log(-2)"); 192 } catch (ArithmeticException ignored) {} 193 try { 194 BoundedRational.sqrt(BR_M1); 195 check(false, "sqrt(-1)"); 196 } catch (ArithmeticException ignored) {} 197 try { 198 BoundedRational.asin(BR_M2); 199 check(false, "asin(-2)"); 200 } catch (ArithmeticException ignored) {} 201 try { 202 BoundedRational.degreeAcos(BR_2); 203 check(false, "degree acos(2)"); 204 } catch (ArithmeticException ignored) {} 205 } 206 testBROverflow()207 public void testBROverflow() { 208 BoundedRational sum = new BoundedRational(0); 209 long i; 210 for (i = 1; i < 1000; ++i) { 211 sum = BoundedRational.add(sum, 212 BoundedRational.inverse(new BoundedRational(i))); 213 if (sum == null) break; 214 } 215 // Experimentally, this overflows at 139, which seems 216 // plausible based on the Wolfram Alpha result. 217 // This test is robust against minor changes in MAX_SIZE. 218 check(i > 100, "Harmonic series overflowed at " + i); 219 check(i < 1000, "Harmonic series didn't overflow"); 220 } 221 } 222