fork(1) download
  1. import java.util.*;
  2. import java.lang.*;
  3. import java.io.*;
  4. import java.util.function.*;
  5. import java.awt.*;
  6.  
  7. class Util {
  8. public static IllegalArgumentException badArgf(String fmt, Object... args) {
  9. return new IllegalArgumentException(String.format(fmt, args));
  10. }
  11.  
  12. public static String trace(Exception e) {
  13. e.printStackTrace(new PrintWriter(sw));
  14. return sw.toString();
  15. }
  16. }
  17.  
  18. class Benchmark
  19. {
  20. public static class Result<T> {
  21. public final double time;
  22. public final T result;
  23.  
  24. Result(double time, T result) {
  25. this.time = time;
  26. this.result = result;
  27. }
  28. }
  29.  
  30. public static <T> Result<T> run(String title, Supplier<T> payload) {
  31. return run(title, payload, null);
  32. }
  33.  
  34. public static <T> Result<T> run(String title, Supplier<T> payload, Result reference) {
  35. long start = System.nanoTime();
  36. var result = payload.get();
  37. double time = (System.nanoTime() - start) * 1e-9;
  38. System.out.println(String.format("%s: %.2f с%s",
  39. title, time, reference != null ? String.format(" (%s)", judgement(time, reference.time)) : ""));
  40. return new Result<T>(time, result);
  41. }
  42.  
  43. static String judgement(double time, double refTime) {
  44. final double absThreshold = 0.07, relThreshold = .1;
  45.  
  46. return time <= absThreshold || refTime <= absThreshold ?
  47. String.format("мин. время %.2f с", absThreshold) :
  48. Math.max(time, refTime) > (1 + relThreshold) * Math.min(time, refTime) ?
  49. String.format("%s на %.0f%%",
  50. time < refTime ? "быстрее" : "медленнее",
  51. Math.abs((time < refTime ? refTime / time : time / refTime) - 1) * 100) :
  52. String.format("<%.0f%% разницы", relThreshold * 100);
  53. }
  54. }
  55.  
  56. class Main
  57. {
  58. static boolean verifyColors(int[] colors, int[] ref, String name, int[] orig) {
  59. final int MAX_ERROR = 0;
  60. for (int i = 0; i < colors.length; i++) {
  61. if ((colors[i] >> 24) != (ref[i] >> 24) ||
  62. Math.abs((colors[i] >> 16 & 0xFF) - (ref[i] >> 16 & 0xFF)) > MAX_ERROR ||
  63. Math.abs((colors[i] >> 8 & 0xFF) - (ref[i] >> 8 & 0xFF)) > MAX_ERROR ||
  64. Math.abs((colors[i] & 0xFF) - (ref[i] & 0xFF)) > MAX_ERROR) {
  65.  
  66. System.out.printf(
  67. "%s не соответствует референсу (#%d = %06X <-> %06X, ориг. %06X).\n",
  68. name, i, colors[i], ref[i], orig[i]);
  69. return false;
  70. }
  71. }
  72. return true;
  73. }
  74.  
  75. static void benchmark() {
  76. var rand = new Random(1);
  77. int[] colors = new int[10_000_000];
  78. for (int i = 0; i < colors.length; i++) {
  79. colors[i] = rand.nextInt(0x1_00_00_00);
  80. }
  81. final float alpha = Math.round(0.234f * 255) / 255f;
  82.  
  83. int[] resultColors0 = new int[colors.length],
  84. resultColors1 = new int[colors.length],
  85. resultColors2 = new int[colors.length];
  86.  
  87. final int TRIALS = 3, AMPLIFY = 9;
  88. for (int iTrial = 0; iTrial < TRIALS; iTrial++) {
  89. System.out.printf("%s--- ПОПЫТКА %d/%d ---\n", iTrial > 0 ? "\n" : "", 1 + iTrial, TRIALS);
  90.  
  91. var ref = Benchmark.run("RGBtoHSB + HSBtoRGB",
  92. () -> {
  93. final float alphaLocal = alpha;
  94. float[] hsb = new float[3];
  95. for (int iAmp = 0; iAmp < AMPLIFY; iAmp++) {
  96. for (int i = 0; i < colors.length; i++) {
  97. int irgb = colors[i];
  98. Color.RGBtoHSB(irgb >> 16 & 0xFF, irgb >> 8 & 0xFF, irgb & 0xFF, hsb);
  99. resultColors0[i] = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2] * alphaLocal);
  100. }
  101. }
  102. return resultColors0;
  103. });
  104.  
  105. String name1 = "(int) (component * alpha + .5f)";
  106. Benchmark.run(name1,
  107. () -> {
  108. final float alphaLocal = alpha;
  109. for (int iAmp = 0; iAmp < AMPLIFY; iAmp++) {
  110. for (int i = 0; i < colors.length; i++) {
  111. int irgb = colors[i];
  112. resultColors1[i] =
  113. (int) ((irgb >> 16 & 0xFF) * alphaLocal + .5f) << 16 |
  114. (int) ((irgb >> 8 & 0xFF) * alphaLocal + .5f) << 8 |
  115. (int) ((irgb & 0xFF) * alphaLocal + .5f) |
  116. 0xFF000000;
  117. }
  118. }
  119. return resultColors1;
  120. }, ref);
  121.  
  122. String name2 = "((component * alpha10 + 512) >> 10)";
  123. Benchmark.run(name2,
  124. () -> {
  125. final int alpha10 = (int) (alpha * 1024 + .5f);
  126.  
  127. for (int iAmp = 0; iAmp < AMPLIFY; iAmp++) {
  128. for (int i = 0; i < colors.length; i++) {
  129. int irgb = colors[i];
  130. resultColors2[i] =
  131. (((irgb >> 16 & 0xFF) * alpha10 + 512) >> 10) << 16 |
  132. (((irgb >> 8 & 0xFF) * alpha10 + 512) >> 10) << 8 |
  133. (((irgb & 0xFF) * alpha10 + 512) >> 10) |
  134. 0xFF000000;
  135. }
  136. }
  137. return resultColors2;
  138. }, ref);
  139.  
  140. if (iTrial == 0) {
  141. if (!verifyColors(resultColors1, resultColors0, name1, colors) |
  142. !verifyColors(resultColors2, resultColors0, name2, colors))
  143. return;
  144.  
  145. System.out.printf("Результат корректен (%06X, %06X, %06X, ...).\n",
  146. resultColors0[0], resultColors0[1], resultColors0[2]);
  147. }
  148. }
  149. }
  150.  
  151. public static void main (String[] args) throws java.lang.Exception
  152. {
  153. try {
  154. benchmark();
  155. } catch (Exception e) {
  156. System.out.println(Util.trace(e));
  157. }
  158. }
  159. }
Success #stdin #stdout 12.95s 199156KB
stdin
Standard input is empty
stdout
--- ПОПЫТКА 1/3 ---
RGBtoHSB + HSBtoRGB: 3.51 с
(int) (component * alpha + .5f): 0.62 с (быстрее на 465%)
((component * alpha10 + 512) >> 10): 0.10 с (быстрее на 3426%)
Результат корректен (FF2C0632, FF062B25, FF183B03, ...).

--- ПОПЫТКА 2/3 ---
RGBtoHSB + HSBtoRGB: 3.37 с
(int) (component * alpha + .5f): 0.59 с (быстрее на 467%)
((component * alpha10 + 512) >> 10): 0.09 с (быстрее на 3648%)

--- ПОПЫТКА 3/3 ---
RGBtoHSB + HSBtoRGB: 3.43 с
(int) (component * alpha + .5f): 0.82 с (быстрее на 318%)
((component * alpha10 + 512) >> 10): 0.08 с (быстрее на 4199%)