/* * Copyright (C) 2006 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. */ /** * Test arithmetic operations. */ public class IntMath { static void shiftTest1() { System.out.println("IntMath.shiftTest1"); final int[] mBytes = { 0x11, 0x22, 0x33, 0x44, 0x88, 0x99, 0xaa, 0xbb }; long l; int i1, i2; i1 = mBytes[0] | mBytes[1] << 8 | mBytes[2] << 16 | mBytes[3] << 24; i2 = mBytes[4] | mBytes[5] << 8 | mBytes[6] << 16 | mBytes[7] << 24; l = i1 | ((long)i2 << 32); Main.assertTrue(i1 == 0x44332211); Main.assertTrue(i2 == 0xbbaa9988); Main.assertTrue(l == 0xbbaa998844332211L); l = (long)mBytes[0] | (long)mBytes[1] << 8 | (long)mBytes[2] << 16 | (long)mBytes[3] << 24 | (long)mBytes[4] << 32 | (long)mBytes[5] << 40 | (long)mBytes[6] << 48 | (long)mBytes[7] << 56; Main.assertTrue(l == 0xbbaa998844332211L); } static void shiftTest2() { System.out.println("IntMath.shiftTest2"); long a = 0x11; long b = 0x22; long c = 0x33; long d = 0x44; long e = 0x55; long f = 0x66; long g = 0x77; long h = 0x88; long result = ((a << 56) | (b << 48) | (c << 40) | (d << 32) | (e << 24) | (f << 16) | (g << 8) | h); Main.assertTrue(result == 0x1122334455667788L); } static void unsignedShiftTest() { System.out.println("IntMath.unsignedShiftTest"); byte b = -4; short s = -4; char c = 0xfffc; int i = -4; b >>>= 4; s >>>= 4; c >>>= 4; i >>>= 4; Main.assertTrue((int) b == -1); Main.assertTrue((int) s == -1); Main.assertTrue((int) c == 0x0fff); Main.assertTrue(i == 268435455); } static void shiftTest3(int thirtyTwo) { System.out.println("IntMath.shiftTest3"); int one = thirtyTwo / 32; int sixteen = thirtyTwo / 2; int thirtyThree = thirtyTwo + 1; int sixtyFour = thirtyTwo * 2; Main.assertTrue(1 << thirtyTwo == 1); Main.assertTrue((1 << sixteen) << sixteen == 0); Main.assertTrue(1 << thirtyThree == 2); Main.assertTrue(1 << -one == -2147483648); Main.assertTrue(1 << -thirtyTwo == 1); Main.assertTrue(1 << -thirtyThree == -2147483648); Main.assertTrue(1 << thirtyThree == 2); Main.assertTrue(1 >> thirtyTwo == 1); Main.assertTrue((1 >> sixteen) >> sixteen == 0); Main.assertTrue(1 >> thirtyThree == 0); Main.assertTrue(1 >> -one == 0); Main.assertTrue(1 >> -thirtyTwo == 1); Main.assertTrue(1 >> -thirtyThree == 0); Main.assertTrue(-4 >> thirtyThree == -2); Main.assertTrue(1 >>> thirtyTwo == 1); Main.assertTrue((1 >>> sixteen) >>> sixteen == 0); Main.assertTrue(1 >>> thirtyThree == 0); Main.assertTrue(1 >>> -one == 0); Main.assertTrue(1 >>> -thirtyTwo == 1); Main.assertTrue(1 >>> -thirtyThree == 0); Main.assertTrue(-4 >>> thirtyThree == 2147483646); } static void convTest() { System.out.println("IntMath.convTest"); float f; double d; int i; long l; /* int --> long */ i = 7654; l = (long) i; Main.assertTrue(l == 7654L); i = -7654; l = (long) i; Main.assertTrue(l == -7654L); /* long --> int (with truncation) */ l = 5678956789L; i = (int) l; Main.assertTrue(i == 1383989493); l = -5678956789L; i = (int) l; Main.assertTrue(i == -1383989493); } static void charSubTest() { System.out.println("IntMath.charSubTest"); char char1 = 0x00e9; char char2 = 0xffff; int i; /* chars are unsigned-expanded to ints before subtraction */ i = char1 - char2; Main.assertTrue(i == 0xffff00ea); } /* * We pass in the arguments and return the results so the compiler * doesn't do the math for us. (x=70000, y=-3) */ static int[] intOperTest(int x, int y) { System.out.println("IntMath.intOperTest"); int[] results = new int[10]; /* this seems to generate "op-int" instructions */ results[0] = x + y; results[1] = x - y; results[2] = x * y; results[3] = x * x; results[4] = x / y; results[5] = x % -y; results[6] = x & y; results[7] = x | y; results[8] = x ^ y; /* this seems to generate "op-int/2addr" instructions */ results[9] = x + ((((((((x + y) - y) * y) / y) % y) & y) | y) ^ y); return results; } static void intOperCheck(int[] results) { System.out.println("IntMath.intOperCheck"); /* check this edge case while we're here (div-int/2addr) */ int minInt = -2147483648; int negOne = -results[5]; int plusOne = 1; int result = (((minInt + plusOne) - plusOne) / negOne) / negOne; Main.assertTrue(result == minInt); Main.assertTrue(results[0] == 69997); Main.assertTrue(results[1] == 70003); Main.assertTrue(results[2] == -210000); Main.assertTrue(results[3] == 605032704); // overflow / truncate Main.assertTrue(results[4] == -23333); Main.assertTrue(results[5] == 1); Main.assertTrue(results[6] == 70000); Main.assertTrue(results[7] == -3); Main.assertTrue(results[8] == -70003); Main.assertTrue(results[9] == 70000); } /* * More operations, this time with 16-bit constants. (x=77777) */ static int[] lit16Test(int x) { System.out.println("IntMath.lit16Test"); int[] results = new int[8]; /* try to generate op-int/lit16" instructions */ results[0] = x + 1000; results[1] = 1000 - x; results[2] = x * 1000; results[3] = x / 1000; results[4] = x % 1000; results[5] = x & 1000; results[6] = x | -1000; results[7] = x ^ -1000; return results; } static void lit16Check(int[] results) { Main.assertTrue(results[0] == 78777); Main.assertTrue(results[1] == -76777); Main.assertTrue(results[2] == 77777000); Main.assertTrue(results[3] == 77); Main.assertTrue(results[4] == 777); Main.assertTrue(results[5] == 960); Main.assertTrue(results[6] == -39); Main.assertTrue(results[7] == -76855); } /* * More operations, this time with 8-bit constants. (x=-55555) */ static int[] lit8Test(int x) { System.out.println("IntMath.lit8Test"); int[] results = new int[8]; /* try to generate op-int/lit8" instructions */ results[0] = x + 10; results[1] = 10 - x; results[2] = x * 10; results[3] = x / 10; results[4] = x % 10; results[5] = x & 10; results[6] = x | -10; results[7] = x ^ -10; return results; } static void lit8Check(int[] results) { //for (int i = 0; i < results.length; i++) // System.out.println(" " + i + ": " + results[i]); /* check this edge case while we're here (div-int/lit8) */ int minInt = -2147483648; int result = minInt / -1; Main.assertTrue(result == minInt); Main.assertTrue(results[0] == -55545); Main.assertTrue(results[1] == 55565); Main.assertTrue(results[2] == -555550); Main.assertTrue(results[3] == -5555); Main.assertTrue(results[4] == -5); Main.assertTrue(results[5] == 8); Main.assertTrue(results[6] == -1); Main.assertTrue(results[7] == 55563); } /* * Make sure special-cased literal division matches * normal division. */ static void divLiteralTestBody(int start, int count) { int normal = 0; int special = 0; for (int i = 0; i < count; i++) { for (int j = 3; j < 16; j++) { switch(j) { case 3: normal = (start+i) / j; special = (start+i) / 3; break; case 4: normal = (start+i) / j; special = (start+i) / 4; break; case 5: normal = (start+i) / j; special = (start+i) / 5; break; case 6: normal = (start+i) / j; special = (start+i) / 6; break; case 7: normal = (start+i) / j; special = (start+i) / 7; break; case 8: normal = (start+i) / j; special = (start+i) / 8; break; case 9: normal = (start+i) / j; special = (start+i) / 9; break; case 10: normal = (start+i) / j; special = (start+i) / 10; break; case 11: normal = (start+i) / j; special = (start+i) / 11; break; case 12: normal = (start+i) / j; special = (start+i) / 12; break; case 13: normal = (start+i) / j; special = (start+i) / 13; break; case 14: normal = (start+i) / j; special = (start+i) / 14; break; case 15: normal = (start+i) / j; special = (start+i) / 15; break; } Main.assertTrue(normal == special); } } } static void divLiteralTest() { System.out.println("IntMath.divLiteralTest"); divLiteralTestBody(-1000, 2000); divLiteralTestBody(0x7fffffff-2000, 2000); divLiteralTestBody(0xfff0ffff, 2000); } /* * Shift some data. (value=0xff00aa01, dist=8) */ static int[] intShiftTest(int value, int dist) { System.out.println("IntMath.intShiftTest"); int results[] = new int[4]; results[0] = value << dist; results[1] = value >> dist; results[2] = value >>> dist; results[3] = (((value << dist) >> dist) >>> dist) << dist; return results; } static void intShiftCheck(int[] results) { System.out.println("IntMath.intShiftCheck"); Main.assertTrue(results[0] == 0x00aa0100); Main.assertTrue(results[1] == 0xffff00aa); Main.assertTrue(results[2] == 0x00ff00aa); Main.assertTrue(results[3] == 0xaa00); } /* * We pass in the arguments and return the results so the compiler * doesn't do the math for us. (x=70000000000, y=-3) */ static long[] longOperTest(long x, long y) { System.out.println("IntMath.longOperTest"); long[] results = new long[10]; /* this seems to generate "op-long" instructions */ results[0] = x + y; results[1] = x - y; results[2] = x * y; results[3] = x * x; results[4] = x / y; results[5] = x % -y; results[6] = x & y; results[7] = x | y; results[8] = x ^ y; /* this seems to generate "op-long/2addr" instructions */ results[9] = x + ((((((((x + y) - y) * y) / y) % y) & y) | y) ^ y); return results; } static void longOperCheck(long[] results) { System.out.println("IntMath.longOperCheck"); /* check this edge case while we're here (div-long/2addr) */ long minLong = -9223372036854775808L; long negOne = -results[5]; long plusOne = 1; long result = (((minLong + plusOne) - plusOne) / negOne) / negOne; Main.assertTrue(result == minLong); Main.assertTrue(results[0] == 69999999997L); Main.assertTrue(results[1] == 70000000003L); Main.assertTrue(results[2] == -210000000000L); Main.assertTrue(results[3] == -6833923606740729856L); // overflow Main.assertTrue(results[4] == -23333333333L); Main.assertTrue(results[5] == 1); Main.assertTrue(results[6] == 70000000000L); Main.assertTrue(results[7] == -3); Main.assertTrue(results[8] == -70000000003L); Main.assertTrue(results[9] == 70000000000L); Main.assertTrue(results.length == 10); } /* * Shift some data. (value=0xd5aa96deff00aa01, dist=8) */ static long[] longShiftTest(long value, int dist) { System.out.println("IntMath.longShiftTest"); long results[] = new long[4]; results[0] = value << dist; results[1] = value >> dist; results[2] = value >>> dist; results[3] = (((value << dist) >> dist) >>> dist) << dist; return results; } static long longShiftCheck(long[] results) { System.out.println("IntMath.longShiftCheck"); Main.assertTrue(results[0] == 0x96deff00aa010000L); Main.assertTrue(results[1] == 0xffffd5aa96deff00L); Main.assertTrue(results[2] == 0x0000d5aa96deff00L); Main.assertTrue(results[3] == 0xffff96deff000000L); Main.assertTrue(results.length == 4); return results[0]; // test return-long } /* * Try to cause some unary operations. */ static int unopTest(int x) { x = -x; x ^= 0xffffffff; return x; } static void unopCheck(int result) { Main.assertTrue(result == 37); } static class Shorty { public short mShort; public char mChar; public byte mByte; }; /* * Truncate an int. */ static Shorty truncateTest(int x) { System.out.println("IntMath.truncateTest"); Shorty shorts = new Shorty(); shorts.mShort = (short) x; shorts.mChar = (char) x; shorts.mByte = (byte) x; return shorts; } static void truncateCheck(Shorty shorts) { Main.assertTrue(shorts.mShort == -5597); // 0xea23 Main.assertTrue(shorts.mChar == 59939); // 0xea23 Main.assertTrue(shorts.mByte == 35); // 0x23 } /* * Verify that we get a divide-by-zero exception. */ static void divideByZero(int z) { System.out.println("IntMath.divideByZero"); try { int x = 100 / z; Main.assertTrue(false); } catch (ArithmeticException ae) { } try { int x = 100 % z; Main.assertTrue(false); } catch (ArithmeticException ae) { } try { long x = 100L / z; Main.assertTrue(false); } catch (ArithmeticException ae) { } try { long x = 100L % z; Main.assertTrue(false); } catch (ArithmeticException ae) { } } /* * Check an edge condition: dividing the most-negative integer by -1 * returns the most-negative integer, and doesn't cause an exception. * * Pass in -1, -1L. */ static void bigDivideOverflow(int idiv, long ldiv) { System.out.println("IntMath.bigDivideOverflow"); int mostNegInt = (int) 0x80000000; long mostNegLong = (long) 0x8000000000000000L; int intDivResult = mostNegInt / idiv; int intModResult = mostNegInt % idiv; long longDivResult = mostNegLong / ldiv; long longModResult = mostNegLong % ldiv; Main.assertTrue(intDivResult == mostNegInt); Main.assertTrue(intModResult == 0); Main.assertTrue(longDivResult == mostNegLong); Main.assertTrue(longModResult == 0); } /* * Check "const" instructions. We use negative values to ensure that * sign-extension is happening. */ static void checkConsts(byte small, short medium, int large, long huge) { System.out.println("IntMath.checkConsts"); Main.assertTrue(small == 1); // const/4 Main.assertTrue(medium == -256); // const/16 Main.assertTrue(medium == -256L); // const-wide/16 Main.assertTrue(large == -88888); // const Main.assertTrue(large == -88888L); // const-wide/32 Main.assertTrue(huge == 0x9922334455667788L); // const-wide } /* * Test some java.lang.Math functions. * * The method arguments are positive values. */ static void jlmTests(int ii, long ll) { System.out.println("IntMath.jlmTests"); Main.assertTrue(Math.abs(ii) == ii); Main.assertTrue(Math.abs(-ii) == ii); Main.assertTrue(Math.min(ii, -5) == -5); Main.assertTrue(Math.max(ii, -5) == ii); Main.assertTrue(Math.abs(ll) == ll); Main.assertTrue(Math.abs(-ll) == ll); Main.assertTrue(Math.min(ll, -5L) == -5L); Main.assertTrue(Math.max(ll, -5L) == ll); } public static void run() { shiftTest1(); shiftTest2(); unsignedShiftTest(); shiftTest3(32); convTest(); charSubTest(); int[] intResults; long[] longResults; intResults = intOperTest(70000, -3); intOperCheck(intResults); longResults = longOperTest(70000000000L, -3L); longOperCheck(longResults); intResults = lit16Test(77777); lit16Check(intResults); intResults = lit8Test(-55555); lit8Check(intResults); divLiteralTest(); intResults = intShiftTest(0xff00aa01, 8); intShiftCheck(intResults); longResults = longShiftTest(0xd5aa96deff00aa01L, 16); long longRet = longShiftCheck(longResults); Main.assertTrue(longRet == 0x96deff00aa010000L); Shorty shorts = truncateTest(-16717277); // 0xff00ea23 truncateCheck(shorts); divideByZero(0); bigDivideOverflow(-1, -1L); checkConsts((byte) 1, (short) -256, -88888, 0x9922334455667788L); unopCheck(unopTest(38)); jlmTests(12345, 0x1122334455667788L); } }