// "if" is 5% faster than "bitwise" public class HueBenchmark { public static final int METHOD_BITWISE = 0; public static final int METHOD_IF = 1; public static final String[] methodNames = new String[] { "bitwise", "if" }; public static void main(String[] args) { int method = METHOD_IF; int iterations = 500; int width = 640; int height = 480; int[] input = new int[width * height]; float[] output = new float[width * height]; int[] colors = new int[iterations]; int x = 0; for (int i = 0; i < input.length; i++) { x += 1337; x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; input[i] = x; } for (int i = 0; i < colors.length; i++) { x += 1337; x = ((x >> 16) ^ x) * 0x45d9f3b; x = ((x >> 16) ^ x) * 0x45d9f3b; x = (x >> 16) ^ x; colors[i] = x; } long startTime = System.nanoTime(); switch (method) { case METHOD_BITWISE: for (int i = 0; i < iterations; i++) computeHueBitwise(output, input, width, height, colors[i]); break; case METHOD_IF: for (int i = 0; i < iterations; i++) computeHueIf(output, input, width, height, colors[i]); break; } long endTime = System.nanoTime(); System.out.println( HueBenchmark.class.getSimpleName() + "\n" + "Method: " + methodNames[method] + "\n" + "Area: " + width + "x" + height + "\n" + "Iterations: " + iterations + "\n" + "Time: " + (double)(endTime - startTime) / 1E6 + "ms" ); } static final int[] MAX_CH_LUT = new int[] {16, 8, 0, 0, 16, 8, 16}; public static void computeHueBitwise(float[] output, int[] input, int width, int height, int targetColor) { int area = width * height; // calculate target hue float targetHue = 0f; { int r = (targetColor >> 16) & 0xff; int g = (targetColor >> 8) & 0xff; int b = targetColor & 0xff; int hueType = (-((r - g) >> 31)) | (-((g - b) >> 31) << 1) | (-((b - r) >> 31) << 2); // prevent divide by zero if (hueType == 0) { for (int i = 0; i < area; i++) output[i] = 0f; return; } float dMaxMin = Math.max(Math.max(r, g), b) - Math.min(Math.min(r, g), b); int maxChannel = MAX_CH_LUT[hueType]; float dAlt = ((targetColor >> ((maxChannel + 16) % 24)) & 0xff) - ((targetColor >> ((maxChannel + 8) % 24)) & 0xff); targetHue = (4f - (float)maxChannel * 0.25f) + dAlt / dMaxMin; } for (int i = 0; i < area; i++) { int rgb = input[i]; int r = (rgb >> 16) & 0xff; int g = (rgb >> 8) & 0xff; int b = rgb & 0xff; int hueType = (-((r - g) >> 31)) | (-((g - b) >> 31) << 1) | (-((b - r) >> 31) << 2); int maxChannel = MAX_CH_LUT[hueType]; int mask = (hueType - 1) >> 31; float dAlt = ~mask & (((rgb >> ((maxChannel + 16) % 24)) & 0xff) - ((rgb >> ((maxChannel + 8) % 24)) & 0xff)); float dMaxMin = -mask + Math.max(Math.max(r, g), b) - Math.min(Math.min(r, g), b); float hue = (4f - (float)maxChannel * 0.25f) + dAlt / dMaxMin; output[i] = (((hue - targetHue) + 6f) % 6f); } } public static void computeHueIf(float[] output, int[] input, int width, int height, int targetColor) { int area = width * height; // calculate target hue float targetHue = 0f; { int r = (targetColor >> 16) & 0xff; int g = (targetColor >> 8) & 0xff; int b = targetColor & 0xff; float max = Math.max(Math.max(r, g), b); float dMaxMin = max - Math.min(Math.min(r, g), b); // prevent divide by zero if (dMaxMin == 0f) { for (int i = 0; i < area; i++) output[i] = 0f; return; } if (max == (float)r) { targetHue = (g - b) / dMaxMin; } else if (max == (float)g) { targetHue = 2f + (b - r) / dMaxMin; } else { targetHue = 4f + (r - g) / dMaxMin; } } for (int i = 0; i < area; i++) { int rgb = input[i]; int r = (rgb >> 16) & 0xff; int g = (rgb >> 8) & 0xff; int b = rgb & 0xff; float hue = targetHue; float max = Math.max(Math.max(r, g), b); float dMaxMin = max - Math.min(Math.min(r, g), b); if (dMaxMin != 0f) { if (max == (float)r) { hue = (g - b) / dMaxMin; } else if (max == (float)g) { hue = 2f + (b - r) / dMaxMin; } else { hue = 4f + (r - g) / dMaxMin; } } output[i] = (((hue - targetHue) + 6f) % 6f); } } }