| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // A test for BoundedRationals package. |
| |
| package com.android.calculator2; |
| |
| import com.hp.creals.CR; |
| import com.hp.creals.UnaryCRFunction; |
| |
| import junit.framework.AssertionFailedError; |
| import junit.framework.TestCase; |
| |
| import java.math.BigInteger; |
| |
| public class BRTest extends TestCase { |
| private static void check(boolean x, String s) { |
| if (!x) throw new AssertionFailedError(s); |
| } |
| final static int TEST_PREC = -100; // 100 bits to the right of |
| // binary point. |
| private static void checkEq(BoundedRational x, CR y, String s) { |
| check(x.CRValue().compareTo(y, TEST_PREC) == 0, s); |
| } |
| private static void checkWeakEq(BoundedRational x, CR y, String s) { |
| if (x != null) checkEq(x, y, s); |
| } |
| |
| private final static UnaryCRFunction ASIN = UnaryCRFunction.asinFunction; |
| private final static UnaryCRFunction ACOS = UnaryCRFunction.acosFunction; |
| private final static UnaryCRFunction ATAN = UnaryCRFunction.atanFunction; |
| private final static UnaryCRFunction TAN = UnaryCRFunction.tanFunction; |
| private final static BoundedRational BR_0 = new BoundedRational(0); |
| private final static BoundedRational BR_M1 = new BoundedRational(-1); |
| private final static BoundedRational BR_2 = new BoundedRational(2); |
| private final static BoundedRational BR_M2 = new BoundedRational(-2); |
| private final static BoundedRational BR_15 = new BoundedRational(15); |
| private final static BoundedRational BR_390 = new BoundedRational(390); |
| private final static BoundedRational BR_M390 = new BoundedRational(-390); |
| private final static CR CR_1 = CR.valueOf(1); |
| |
| private final static CR RADIANS_PER_DEGREE = CR.PI.divide(CR.valueOf(180)); |
| private final static CR DEGREES_PER_RADIAN = CR.valueOf(180).divide(CR.PI); |
| private final static CR LN10 = CR.valueOf(10).ln(); |
| |
| private static CR toRadians(CR x) { |
| return x.multiply(RADIANS_PER_DEGREE); |
| } |
| |
| private static CR fromRadians(CR x) { |
| return x.multiply(DEGREES_PER_RADIAN); |
| } |
| |
| // We assume that x is simple enough that we don't overflow bounds. |
| private static void checkBR(BoundedRational x) { |
| check(x != null, "test data should not be null"); |
| CR xAsCR = x.CRValue(); |
| checkEq(BoundedRational.add(x, BoundedRational.ONE), xAsCR.add(CR_1), |
| "add 1:" + x); |
| checkEq(BoundedRational.subtract(x, BoundedRational.MINUS_THIRTY), |
| xAsCR.subtract(CR.valueOf(-30)), "sub -30:" + x); |
| checkEq(BoundedRational.multiply(x, BR_15), |
| xAsCR.multiply(CR.valueOf(15)), "multiply 15:" + x); |
| checkEq(BoundedRational.divide(x, BR_15), |
| xAsCR.divide(CR.valueOf(15)), "divide 15:" + x); |
| checkWeakEq(BoundedRational.sin(x), xAsCR.sin(), "sin:" + x); |
| checkWeakEq(BoundedRational.cos(x), xAsCR.cos(), "cos:" + x); |
| checkWeakEq(BoundedRational.tan(x), TAN.execute(xAsCR), "tan:" + x); |
| checkWeakEq(BoundedRational.degreeSin(x), toRadians(xAsCR).sin(), |
| "degree sin:" + x); |
| checkWeakEq(BoundedRational.degreeCos(x), toRadians(xAsCR).cos(), |
| "degree cos:" + x); |
| BigInteger big_x = BoundedRational.asBigInteger(x); |
| long long_x = (big_x == null? 0 : big_x.longValue()); |
| try { |
| checkWeakEq(BoundedRational.degreeTan(x), |
| TAN.execute(toRadians(xAsCR)), "degree tan:" + x); |
| check((long_x - 90) % 180 != 0, "missed undefined tan: " + x); |
| } catch (ArithmeticException ignored) { |
| check((long_x - 90) % 180 == 0, "exception on defined tan: " + x); |
| } |
| if (x.compareTo(BoundedRational.ONE) <= 0 |
| && x.compareTo(BoundedRational.MINUS_ONE) >= 0) { |
| checkWeakEq(BoundedRational.asin(x), ASIN.execute(xAsCR), |
| "asin:" + x); |
| checkWeakEq(BoundedRational.acos(x), ACOS.execute(xAsCR), |
| "acos:" + x); |
| checkWeakEq(BoundedRational.degreeAsin(x), |
| fromRadians(ASIN.execute(xAsCR)), "degree asin:" + x); |
| checkWeakEq(BoundedRational.degreeAcos(x), |
| fromRadians(ACOS.execute(xAsCR)), "degree acos:" + x); |
| } |
| checkWeakEq(BoundedRational.atan(x), fromRadians(ATAN.execute(xAsCR)), |
| "atan:" + x); |
| checkWeakEq(BoundedRational.degreeAtan(x), |
| fromRadians(ATAN.execute(xAsCR)), "degree atan:" + x); |
| if (x.signum() > 0) { |
| checkWeakEq(BoundedRational.ln(x), xAsCR.ln(), "ln:" + x); |
| checkWeakEq(BoundedRational.log(x), xAsCR.ln().divide(LN10), |
| "log:" + x); |
| checkWeakEq(BoundedRational.sqrt(x), xAsCR.sqrt(), "sqrt:" + x); |
| checkEq(BoundedRational.pow(x, BR_15), |
| xAsCR.ln().multiply(CR.valueOf(15)).exp(), |
| "pow(x,15):" + x); |
| } |
| } |
| |
| public void testBR() { |
| checkEq(BR_0, CR.valueOf(0), "0"); |
| checkEq(BR_390, CR.valueOf(390), "390"); |
| checkEq(BR_15, CR.valueOf(15), "15"); |
| checkEq(BR_M390, CR.valueOf(-390), "-390"); |
| checkEq(BR_M1, CR.valueOf(-1), "-1"); |
| checkEq(BR_2, CR.valueOf(2), "2"); |
| checkEq(BR_M2, CR.valueOf(-2), "-2"); |
| check(BR_0.signum() == 0, "signum(0)"); |
| check(BR_M1.signum() == -1, "signum(-1)"); |
| check(BR_2.signum() == 1, "signum(2)"); |
| // We check values that include all interesting degree values. |
| BoundedRational r = BR_M390; |
| while (!r.equals(BR_390)) { |
| check(r != null, "loop counter overflowed!"); |
| checkBR(r); |
| r = BoundedRational.add(r, BR_15); |
| } |
| checkBR(BoundedRational.HALF); |
| checkBR(BoundedRational.MINUS_HALF); |
| checkBR(BoundedRational.ONE); |
| checkBR(BoundedRational.MINUS_ONE); |
| checkBR(new BoundedRational(1000)); |
| checkBR(new BoundedRational(100)); |
| checkBR(new BoundedRational(4,9)); |
| check(BoundedRational.sqrt(new BoundedRational(4,9)) != null, |
| "sqrt(4/9) is null"); |
| checkBR(BoundedRational.negate(new BoundedRational(4,9))); |
| checkBR(new BoundedRational(5,9)); |
| checkBR(new BoundedRational(5,10)); |
| checkBR(new BoundedRational(5,10)); |
| checkBR(new BoundedRational(4,13)); |
| checkBR(new BoundedRational(36)); |
| checkBR(BoundedRational.negate(new BoundedRational(36))); |
| check(BoundedRational.pow(null, BR_15) == null, "pow(null, 15)"); |
| } |
| |
| public void testBRexceptions() { |
| try { |
| BoundedRational.ln(BR_M1); |
| check(false, "ln(-1)"); |
| } catch (ArithmeticException ignored) {} |
| try { |
| BoundedRational.log(BR_M2); |
| check(false, "log(-2)"); |
| } catch (ArithmeticException ignored) {} |
| try { |
| BoundedRational.sqrt(BR_M1); |
| check(false, "sqrt(-1)"); |
| } catch (ArithmeticException ignored) {} |
| try { |
| BoundedRational.asin(BR_M2); |
| check(false, "asin(-2)"); |
| } catch (ArithmeticException ignored) {} |
| try { |
| BoundedRational.degreeAcos(BR_2); |
| check(false, "degree acos(2)"); |
| } catch (ArithmeticException ignored) {} |
| } |
| |
| public void testBROverflow() { |
| BoundedRational sum = new BoundedRational(0); |
| long i; |
| for (i = 1; i < 1000; ++i) { |
| sum = BoundedRational.add(sum, |
| BoundedRational.inverse(new BoundedRational(i))); |
| if (sum == null) break; |
| } |
| // Experimentally, this overflows at 139, which seems |
| // plausible based on the Wolfram Alpha result. |
| // This test is robust against minor changes in MAX_SIZE. |
| check(i > 100, "Harmonic series overflowed at " + i); |
| check(i < 1000, "Harmonic series didn't overflow"); |
| } |
| } |