1 package org.djutils.complex.demo;
2
3 import org.djutils.complex.Complex;
4
5
6
7
8
9
10
11
12
13
14
15 public final class PerformanceTests
16 {
17
18
19
20 private PerformanceTests()
21 {
22
23 }
24
25
26
27
28
29 public static void main(final String[] args)
30 {
31
32 Math.atan2(0.5, 1.5);
33 Math.hypot(1.2, 3.4);
34 Complex.hypot(1.2, 3.4);
35 Math.sin(0.8);
36 Math.cos(0.6);
37 Math.sqrt(2.3);
38
39 int iterations = 100000000;
40 long startNanos = System.nanoTime();
41 for (int i = 0; i < iterations; i++)
42 {
43 @SuppressWarnings("unused")
44 double x = 0.1 + i / 1000.0;
45 @SuppressWarnings("unused")
46 double y = -0.5 + i / 2000.0;
47 }
48 long nowNanos = System.nanoTime();
49 long baseNanos = nowNanos - startNanos;
50 System.out.println(String.format(" base loop: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
51 baseNanos / 1000000000.0, 1.0 * baseNanos / iterations));
52
53 startNanos = System.nanoTime();
54 for (int i = 0; i < iterations; i++)
55 {
56 double x = 0.1 + i / 1000.0;
57 double y = -0.5 + i / 2000.0;
58 Math.atan2(y, x);
59 }
60 nowNanos = System.nanoTime();
61 long durationNanos = nowNanos - startNanos - baseNanos;
62 System.out.println(String.format(" Math.atan2: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
63 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
64
65 startNanos = System.nanoTime();
66 for (int i = 0; i < iterations; i++)
67 {
68 double x = 0.1 + i / 1000.0;
69 double y = -0.5 + i / 2000.0;
70 Math.hypot(y, x);
71 }
72 nowNanos = System.nanoTime();
73 durationNanos = nowNanos - startNanos - baseNanos;
74 System.out.println(String.format(" Math.hypot: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
75 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
76
77 startNanos = System.nanoTime();
78 for (int i = 0; i < iterations; i++)
79 {
80 double x = 0.1 + i / 1000.0;
81 double y = -0.5 + i / 2000.0;
82 PerformanceTests.hypotA(y, x);
83 }
84 nowNanos = System.nanoTime();
85 durationNanos = nowNanos - startNanos - baseNanos;
86 System.out.println(String.format("PerformanceTests.hypotA: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
87 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
88
89 startNanos = System.nanoTime();
90 for (int i = 0; i < iterations; i++)
91 {
92 double x = 0.1 + i / 1000.0;
93 double y = -0.5 + i / 2000.0;
94 PerformanceTests.hypotB(y, x);
95 }
96 nowNanos = System.nanoTime();
97 durationNanos = nowNanos - startNanos - baseNanos;
98 System.out.println(String.format("PerformanceTests.hypotB: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
99 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
100
101 startNanos = System.nanoTime();
102 for (int i = 0; i < iterations; i++)
103 {
104 double x = 0.1 + i / 1000.0;
105 double y = -0.5 + i / 2000.0;
106 PerformanceTests.hypotC(y, x);
107 }
108 nowNanos = System.nanoTime();
109 durationNanos = nowNanos - startNanos - baseNanos;
110 System.out.println(String.format("PerformanceTests.hypotC: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
111 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
112
113 startNanos = System.nanoTime();
114 for (int i = 0; i < iterations; i++)
115 {
116 double x = 0.1 + i / 1000.0;
117 double y = -0.5 + i / 2000.0;
118 Complex.hypot(y, x);
119 }
120 nowNanos = System.nanoTime();
121 durationNanos = nowNanos - startNanos - baseNanos;
122 System.out.println(String.format(" Complex.hypot: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
123 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
124
125 startNanos = System.nanoTime();
126 for (int i = 0; i < iterations; i++)
127 {
128 double x = 0.1 + i / 1000000.0;
129 Math.sin(x);
130 }
131 nowNanos = System.nanoTime();
132 durationNanos = nowNanos - startNanos - baseNanos;
133 System.out.println(String.format(" Math.sin: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
134 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
135
136 startNanos = System.nanoTime();
137 for (int i = 0; i < iterations; i++)
138 {
139 double x = 0.1 + i / 1000000.0;
140 Math.cos(x);
141 }
142 nowNanos = System.nanoTime();
143 durationNanos = nowNanos - startNanos - baseNanos;
144 System.out.println(String.format(" Math.cos: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
145 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
146
147 startNanos = System.nanoTime();
148 for (int i = 0; i < iterations; i++)
149 {
150 double x = 0.1 + i / 1000.0;
151 double y = -0.5 + i / 2000.0;
152 Math.sqrt(x * x + y * y);
153 }
154 nowNanos = System.nanoTime();
155 durationNanos = nowNanos - startNanos - baseNanos;
156 System.out.println(String.format(" Math.sqrt(x*x+y*y): %d invocations in %.6f s (%.1f ns/invocation)",
157 iterations, durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
158 }
159
160
161 private static final double TWO_POW_450 = Double.longBitsToDouble(0x5C10000000000000L);
162
163
164 private static final double TWO_POW_N450 = Double.longBitsToDouble(0x23D0000000000000L);
165
166
167 private static final double TWO_POW_750 = Double.longBitsToDouble(0x6ED0000000000000L);
168
169
170 private static final double TWO_POW_N750 = Double.longBitsToDouble(0x1110000000000000L);
171
172
173
174
175
176
177
178 public static double hypotA(final double px, final double py)
179 {
180 double x = Math.abs(px);
181 double y = Math.abs(py);
182 if (y < x)
183 {
184 double a = x;
185 x = y;
186 y = a;
187 }
188 else if (!(y >= x))
189 {
190 if ((x == Double.POSITIVE_INFINITY) || (y == Double.POSITIVE_INFINITY))
191 {
192 return Double.POSITIVE_INFINITY;
193 }
194 else
195 {
196 return Double.NaN;
197 }
198 }
199 if (y - x == y)
200 {
201 return y;
202 }
203 else
204 {
205 double factor;
206 if (x > TWO_POW_450)
207 {
208 x *= TWO_POW_N750;
209 y *= TWO_POW_N750;
210 factor = TWO_POW_750;
211 }
212 else if (y < TWO_POW_N450)
213 {
214 x *= TWO_POW_750;
215 y *= TWO_POW_750;
216 factor = TWO_POW_N750;
217 }
218 else
219 {
220 factor = 1.0;
221 }
222 return factor * Math.sqrt(x * x + y * y);
223 }
224 }
225
226
227
228
229
230
231
232
233
234
235
236 public static double hypotB(final double px, final double py)
237 {
238 if (Double.isInfinite(px) || Double.isInfinite(py))
239 {
240 return Double.POSITIVE_INFINITY;
241 }
242 if (Double.isNaN(px) || Double.isNaN(py))
243 {
244 return Double.NaN;
245 }
246
247 double x = Math.abs(px);
248 double y = Math.abs(py);
249
250 if (x < y)
251 {
252 double d = x;
253 x = y;
254 y = d;
255 }
256
257 int xi = Math.getExponent(x);
258 int yi = Math.getExponent(y);
259
260 if (xi > yi + 27)
261 {
262 return x;
263 }
264
265 int bias = 0;
266 if (xi > 510 || xi < -511)
267 {
268 bias = xi;
269 x = Math.scalb(x, -bias);
270 y = Math.scalb(y, -bias);
271 }
272
273
274 double z = 0;
275 if (x > 2 * y)
276 {
277 double x1 = Double.longBitsToDouble(Double.doubleToLongBits(x) & 0xffffffff00000000L);
278 double x2 = x - x1;
279 z = Math.sqrt(x1 * x1 + (y * y + x2 * (x + x1)));
280 }
281 else
282 {
283 double t = 2 * x;
284 double t1 = Double.longBitsToDouble(Double.doubleToLongBits(t) & 0xffffffff00000000L);
285 double t2 = t - t1;
286 double y1 = Double.longBitsToDouble(Double.doubleToLongBits(y) & 0xffffffff00000000L);
287 double y2 = y - y1;
288 double xMinusY = x - y;
289 z = Math.sqrt(t1 * y1 + (xMinusY * xMinusY + (t1 * y2 + t2 * y)));
290 }
291
292 if (bias == 0)
293 {
294 return z;
295 }
296 else
297 {
298 return Math.scalb(z, bias);
299 }
300 }
301
302
303 private static final double EPSILONSQRT = Math.sqrt(Math.ulp(1.0) / 2);
304
305 private static final double SQRT_OF_MIN_VALUE = Math.sqrt(Double.MIN_VALUE);
306
307 private static final double SQRT_OF_MAX_VALUE = Math.sqrt(Double.MAX_VALUE);
308
309
310
311
312
313
314
315
316 public static double hypotC(final double x, final double y)
317 {
318 if (x != x || y != y)
319 {
320 return Double.NaN;
321 }
322 double absX = Math.abs(x);
323 double absY = Math.abs(y);
324 if (absX == Double.POSITIVE_INFINITY || absY == Double.POSITIVE_INFINITY)
325 {
326 return Double.POSITIVE_INFINITY;
327 }
328 if (absX < absY)
329 {
330 double swap = absX;
331 absX = absY;
332 absY = swap;
333 }
334 if (absY <= absX * EPSILONSQRT)
335 {
336 return absX;
337 }
338 double scale = SQRT_OF_MIN_VALUE;
339 if (absX > SQRT_OF_MAX_VALUE)
340 {
341 scale = SQRT_OF_MIN_VALUE;
342 absX *= scale;
343 absY *= scale;
344 scale = 1.0 / scale;
345 }
346 else if (absY < SQRT_OF_MIN_VALUE)
347 {
348 scale = SQRT_OF_MIN_VALUE;
349 absX /= scale;
350 absY /= scale;
351 }
352 else
353 {
354 scale = 1.0;
355 }
356 double h = Math.sqrt(Math.fma(absX, absX, absY * absY));
357 double hsq = h * h;
358 double xsq = absX * absX;
359 double a = Math.fma(-absY, absY, hsq - xsq) + Math.fma(h, h, -hsq) - Math.fma(absX, absX, -xsq);
360 return scale * (h - a / (2.0 * h));
361 }
362
363 }