001package stdlib; 002import java.util.function.*; 003 004public class DoublingTest { 005 private static double time; 006 private static long ops; 007 /** 008 * During a doubling test, the provided code may call {@code incOps} and/or {@code addOps}. 009 * If either is called, then the number of operations so recorded will be reported by {@code run}. 010 */ 011 public static void incOps () { ops++; } 012 /** 013 * During a doubling test, the provided code may call {@code incOps} and/or {@code addOps}. 014 * If either is called, then the number of operations so recorded will be reported by {@code run}. 015 */ 016 public static void addOps (int count) { 017 if (count < 1) throw new IllegalArgumentException (); 018 ops += count; 019 } 020 /** 021 * See fully parameterized {@code run} for a description. 022 * In this abbreviated form, {@code numTestsPerValue} is 1. 023 * {@code setup} does nothing, therefore no value is provided to {@code timed}. 024 */ 025 public static void run (int initialValue, int numValues, Consumer<Integer> timed) { 026 run (initialValue, numValues, 1, x -> {}, timed); 027 } 028 /** 029 * See fully parameterized {@code run} for a description. 030 * In this abbreviated form, {@code numTestsPerValue} is 1. 031 * No value is passed from {@code setup} to {@code timed}. 032 */ 033 public static void run (int initialValue, int numValues, Consumer<Integer> setup, Consumer<Integer> timed) { 034 run (initialValue, numValues, 1, setup, timed); 035 } 036 /** 037 * See fully parameterized {@code run} for a description. 038 * In this abbreviated form, no value is passed from {@code setup} to {@code timed}. 039 */ 040 public static void run (int initialValue, int numValues, int numTestsPerValue, Consumer<Integer> setup, Consumer<Integer> timed) { 041 run (initialValue, numValues, numTestsPerValue, (Integer x) -> { setup.accept (x); return null; }, (x,t) -> timed.accept (x)); 042 } 043 /** 044 * See fully parameterized {@code run} for a description. 045 * In this abbreviated form, {@code numTestsPerValue} is 1. 046 */ 047 public static <T> void run (int initialValue, int numValues, Function<Integer,T> setup, BiConsumer<Integer,T> timed) { 048 run (initialValue, numValues, 1, setup, timed); 049 } 050 /** 051 * See fully parameterized {@code run} for a description. 052 * In this abbreviated form, the integer value is not passed to {@code timed}. 053 */ 054 public static <T> void run (int initialValue, int numValues, int numTestsPerValue, Function<Integer,T> setup, Consumer<T> timed) { 055 run (initialValue, numValues, numTestsPerValue, setup, (x,t) -> timed.accept (t)); 056 } 057 /** 058 * See fully parameterized {@code run} for a description. 059 * In this abbreviated form, {@code numTestsPerValue} is 1. 060 * The integer value is not passed to {@code timed}. 061 */ 062 public static <T> void run (int initialValue, int numValues, Function<Integer,T> setup, Consumer<T> timed) { 063 run (initialValue, numValues, 1, setup, timed); 064 } 065 /** 066 * Run the function {@code timed} with increasing large values for the first integer parameter (N). 067 * Running time is reported to the console. 068 * Initial value of N is given by {@code initialValue}. 069 * N doubles each time the test is run. 070 * The number of different values for N is given by {@code numValues}. 071 * If {@code numTestsPerValue} is larger than one, then the test will be run multiple times for each N, and the average time reported. 072 * The {@code setup} function is called before {@code timed}, and the result (of type T) is provided to {@code timed} as the second parameter. 073 * {@code setup} is called once before each call to {@code timed}. 074 */ 075 public static <T> void run (int initialValue, int numValues, int numTestsPerValue, Function<Integer,T> setup, BiConsumer<Integer,T> timed) { 076 int value = initialValue; 077 runOnce (value, numTestsPerValue, setup, timed); 078 if (ops != 0) { 079 System.out.format("N=%,13d, ops=%,13d, seconds=%5.3f\n", value, ops/numTestsPerValue, time/numTestsPerValue); 080 } else { 081 System.out.format("N=%,13d, seconds=%5.3f\n", value, time/numTestsPerValue); 082 } 083 double prevOps = ops; 084 double prevTime = time; 085 for (int i=1; i<numValues; i++) { 086 value *= 2; 087 runOnce (value, numTestsPerValue, setup, timed); 088 if (ops != 0) { 089 System.out.format("N=%,13d, ops=%,13d ratio=%5.1f, seconds=%5.3f ratio=%5.3f\n", value, ops/numTestsPerValue, ops/prevOps, time/numTestsPerValue, time/prevTime); 090 } else { 091 System.out.format("N=%,13d, seconds=%5.3f ratio=%5.3f\n", value, time/numTestsPerValue, time/prevTime); 092 } 093 prevOps = ops; 094 prevTime = time; 095 } 096 } 097 private static <T> void runOnce (int value, int numTestsPerValue, Function<Integer,T> setup, BiConsumer<Integer,T> timed) { 098 ops = 0; 099 time = 0; 100 for (int testNum = 0; testNum < numTestsPerValue; testNum++) { 101 T setupResult = setup.apply (value); 102 Stopwatch sw = new Stopwatch (); 103 timed.accept (value, setupResult); 104 time += sw.elapsedTime (); 105 } 106 } 107 108 // Now repeat everything with Long, rather than Integer 109 110 /** 111 * See fully parameterized {@code runLong} for a description. 112 * In this abbreviated form, {@code numTestsPerValue} is 1. 113 * {@code setup} does nothing, therefore no value is provided to {@code timed}. 114 */ 115 public static void runLong (long initialValue, int numValues, Consumer<Long> timed) { 116 runLong (initialValue, numValues, 1, x -> {}, timed); 117 } 118 /** 119 * See fully parameterized {@code runLong} for a description. 120 * In this abbreviated form, {@code numTestsPerValue} is 1. 121 * No value is passed from {@code setup} to {@code timed}. 122 */ 123 public static void runLong (long initialValue, int numValues, Consumer<Long> setup, Consumer<Long> timed) { 124 runLong (initialValue, numValues, 1, setup, timed); 125 } 126 /** 127 * See fully parameterized {@code runLong} for a description. 128 * In this abbreviated form, no value is passed from {@code setup} to {@code timed}. 129 */ 130 public static void runLong (long initialValue, int numValues, int numTestsPerValue, Consumer<Long> setup, Consumer<Long> timed) { 131 runLong (initialValue, numValues, numTestsPerValue, (Long x) -> { setup.accept (x); return null; }, (x,t) -> timed.accept (x)); 132 } 133 /** 134 * See fully parameterized {@code runLong} for a description. 135 * In this abbreviated form, {@code numTestsPerValue} is 1. 136 */ 137 public static <T> void runLong (long initialValue, int numValues, Function<Long,T> setup, BiConsumer<Long,T> timed) { 138 runLong (initialValue, numValues, 1, setup, timed); 139 } 140 /** 141 * See fully parameterized {@code runLong} for a description. 142 * In this abbreviated form, the integer value is not passed to {@code timed}. 143 */ 144 public static <T> void runLong (long initialValue, int numValues, int numTestsPerValue, Function<Long,T> setup, Consumer<T> timed) { 145 runLong (initialValue, numValues, numTestsPerValue, setup, (x,t) -> timed.accept (t)); 146 } 147 /** 148 * See fully parameterized {@code runLong} for a description. 149 * In this abbreviated form, {@code numTestsPerValue} is 1. 150 * The integer value is not passed to {@code timed}. 151 */ 152 public static <T> void runLong (long initialValue, int numValues, Function<Long,T> setup, Consumer<T> timed) { 153 runLong (initialValue, numValues, 1, setup, timed); 154 } 155 /** 156 * Run the function {@code timed} with increasing large values for the first integer parameter (N). 157 * Running time is reported to the console. 158 * Initial value of N is given by {@code initialValue}. 159 * N doubles each time the test is runLong. 160 * The number of different values for N is given by {@code numValues}. 161 * If {@code numTestsPerValue} is larger than one, then the test will be runLong multiple times for each N, and the average time reported. 162 * The {@code setup} function is called before {@code timed}, and the result (of type T) is provided to {@code timed} as the second parameter. 163 * {@code setup} is called once before each call to {@code timed}. 164 */ 165 public static <T> void runLong (long initialValue, int numValues, int numTestsPerValue, Function<Long,T> setup, BiConsumer<Long,T> timed) { 166 long value = initialValue; 167 runOnce (value, numTestsPerValue, setup, timed); 168 if (ops != 0) { 169 System.out.format("N=%,13d, ops=%,13d, seconds=%5.3f\n", value, ops/numTestsPerValue, time/numTestsPerValue); 170 } else { 171 System.out.format("N=%,13d, seconds=%5.3f\n", value, time/numTestsPerValue); 172 } 173 double prevOps = ops; 174 double prevTime = time; 175 for (int i=1; i<numValues; i++) { 176 value *= 2; 177 runOnce (value, numTestsPerValue, setup, timed); 178 if (ops != 0) { 179 System.out.format("N=%,13d, ops=%,13d ratio=%5.1f, seconds=%5.3f ratio=%5.3f\n", value, ops/numTestsPerValue, ops/prevOps, time/numTestsPerValue, time/prevTime); 180 } else { 181 System.out.format("N=%,13d, seconds=%5.3f ratio=%5.3f\n", value, time/numTestsPerValue, time/prevTime); 182 } 183 prevOps = ops; 184 prevTime = time; 185 } 186 } 187 private static <T> void runOnce (long value, int numTestsPerValue, Function<Long,T> setup, BiConsumer<Long,T> timed) { 188 ops = 0; 189 time = 0; 190 for (int testNum = 0; testNum < numTestsPerValue; testNum++) { 191 T setupResult = setup.apply (value); 192 Stopwatch sw = new Stopwatch (); 193 timed.accept (value, setupResult); 194 time += sw.elapsedTime (); 195 } 196 } 197}