java - Why does reversing a loop make it slower? -
i have following code circular shift of bits in array:
private static void method1(byte[] bytes) { byte previousbyte = bytes[0]; bytes[0] = (byte) (((bytes[0] & 0xff) >> 1) | ((bytes[bytes.length - 1] & 0xff) << 7)); (int = 1; < bytes.length; i++) { byte tmp = bytes[i]; bytes[i] = (byte) (((bytes[i] & 0xff) >> 1) | ((previousbyte & 0xff) << 7)); previousbyte = tmp; } }
then thought it's easier , more readable go backwards this:
private static void method2(byte[] bytes) { byte lastbyte = bytes[bytes.length-1]; (int = bytes.length-1; > 0; i--) { bytes[i] = (byte) (((bytes[i] & 0xff) >> 1) | ((bytes[i-1] & 0xff) << 7)); } bytes[0] = (byte) (((bytes[0] & 0xff) >> 1) | ((lastbyte & 0xff) << 7)); }
but noticed second 1 (method2) slower first 1 (method1)! noticed difference because i'm calling method thousands of times. did test make sure , here average result 20 tests of calling each method 3000 times (and number of bytes 1 million):
method1 average : 4s 572ms method2 average : 5s 630ms
so question is: why first 1 faster second?
here testing code make sure i'm not doing wrong testing:
import java.math.biginteger; public class bitshifttests { public static void main(string[] args) { int numoftests = 20; int numberofshifts = 3000; byte[] numbers = new byte[1000000]; (int = 0; < numbers.length; i++) { numbers[i] = (byte) (i % 255); } system.out.println("testing method1..."); biginteger method1sum = new biginteger("00000000", 2); (int = 1; <= numoftests; i++) { long total = 0l; (int j = 0; j < numberofshifts; j++) { long starttime = system.nanotime(); method1(numbers); long endtime = system.nanotime(); total = total + (endtime - starttime); } method1sum = method1sum.add(new biginteger(long.tostring(total), 10)); system.out.println(string.format("%-2d: %s", i, gettime(total))); } system.out.println("testing method2..."); biginteger method2sum = new biginteger("00000000", 2); (int = 1; <= numoftests; i++) { long total = 0l; (int j = 0; j < numberofshifts; j++) { long starttime = system.nanotime(); method2(numbers); long endtime = system.nanotime(); total = total + (endtime - starttime); } method2sum = method2sum.add(new biginteger(long.tostring(total), 10)); system.out.println(string.format("%-2d: %s", i, gettime(total))); } system.out.println("method1 average : " + gettime(method1sum.longvalue() / numoftests)); system.out.println("method2 average : " + gettime(method2sum.longvalue() / numoftests)); } private static void method1(byte[] bytes) { byte previousbyte = bytes[0]; bytes[0] = (byte) (((bytes[0] & 0xff) >> 1) | ((bytes[bytes.length - 1] & 0xff) << 7)); (int = 1; < bytes.length; i++) { byte tmp = bytes[i]; bytes[i] = (byte) (((bytes[i] & 0xff) >> 1) | ((previousbyte & 0xff) << 7)); previousbyte = tmp; } } private static void method2(byte[] bytes) { byte lastbyte = bytes[bytes.length-1]; (int = bytes.length-1; > 0; i--) { bytes[i] = (byte) (((bytes[i] & 0xff) >> 1) | ((bytes[i-1] & 0xff) << 7)); } bytes[0] = (byte) (((bytes[0] & 0xff) >> 1) | ((lastbyte & 0xff) << 7)); } private static string gettime(long nanosecs) { int minutes = (int) (nanosecs / 60000000000.0); int seconds = (int) (nanosecs / 1000000000.0) - (minutes * 60); int millisecs = (int) (((nanosecs / 1000000000.0) - (seconds + minutes * 60)) * 1000); int nanosecs = (int) nanosecs - (millisecs * 1000000000); if (minutes == 0 && seconds == 0 && millisecs == 0) { return nanosecs + "ns"; } if (minutes == 0 && seconds == 0) { return millisecs + "ms"; } if (minutes == 0 && millisecs == 0) { return seconds + "s"; } if (seconds == 0 && millisecs == 0) { return minutes + "min"; } if (minutes == 0) { return seconds + "s " + millisecs + "ms"; } if (seconds == 0) { return minutes + "min " + millisecs + "ms"; } if (millisecs == 0) { return minutes + "min " + seconds + "s"; } return minutes + "min " + seconds + "s " + millisecs + "ms"; } }
update:
looks reason i'm accessing 2 different indices in each loop in second method, while accessing 1 index in first method. has nothing reversing loop.
thanks @rm5248 , @ben, choose both of answers if could, chose earlier one.
i did quick test on this, , seems though reason second method goes slower because algorithm changed little bit. in first, you're keeping 1 value in local variable, while you're not in second. because of that, java has go array twice in order variable out. theoretically, shouldn't different, think has how arrays implemented in java(i suspect if tried in c times closer).
for reference, here's implementation(i think same thing, may not):
private static void method2(byte[] bytes) { byte prevbyte = bytes[bytes.length-1]; (int = bytes.length-1; > 0; i--) { byte tmp = bytes[i]; bytes[i] = (byte) (((bytes[i] & 0xff) >> 1) | ((prevbyte & 0xff) << 7)); prevbyte = tmp; } bytes[0] = (byte) (((bytes[0] & 0xff) >> 1) | ((bytes[bytes.length-1] & 0xff) << 7)); }
here average times got:
method1 average : 6s 555ms method2 average : 6s 726ms
Comments
Post a Comment