1 package org.djutils.float128;
2
3
4
5
6
7
8
9
10
11
12
13 public final class TestHypotAtan
14 {
15
16
17
18 private TestHypotAtan()
19 {
20
21 }
22
23
24
25
26
27 public static void main(final String[] args)
28 {
29
30 Math.atan2(0.5, 1.5);
31 Math.hypot(1.2, 3.4);
32 Math.sin(0.8);
33 Math.cos(0.6);
34 Math.sqrt(2.3);
35
36 int iterations = 100000000;
37
38 long startNanos = System.nanoTime();
39 for (int i = 0; i < iterations; i++)
40 {
41 @SuppressWarnings("unused")
42 double x = 0.1 + i / 1000.0;
43 @SuppressWarnings("unused")
44 double y = -0.5 + i / 2000.0;
45 }
46 long nowNanos = System.nanoTime();
47 long baseNanos = nowNanos - startNanos;
48 System.out.println(String.format("base loop: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
49 baseNanos / 1000000000.0, 1.0 * baseNanos / iterations));
50
51 startNanos = System.nanoTime();
52 for (int i = 0; i < iterations; i++)
53 {
54 double x = 0.1 + i / 1000.0;
55 double y = -0.5 + i / 2000.0;
56 Math.atan2(y, x);
57 }
58 nowNanos = System.nanoTime();
59 long durationNanos = nowNanos - startNanos - baseNanos;
60 System.out.println(String.format("atan2: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
61 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
62
63 startNanos = System.nanoTime();
64 for (int i = 0; i < iterations; i++)
65 {
66 double x = 0.1 + i / 1000.0;
67 double y = -0.5 + i / 2000.0;
68 TestHypotAtan.atan2(y, x);
69 }
70 nowNanos = System.nanoTime();
71 durationNanos = nowNanos - startNanos - baseNanos;
72 System.out.println(String.format("PerformanceTests.atan2: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
73 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
74
75 startNanos = System.nanoTime();
76 for (int i = 0; i < iterations; i++)
77 {
78 double x = 0.1 + i / 1000.0;
79 TestHypotAtan.fastAtan(x);
80 }
81 nowNanos = System.nanoTime();
82 durationNanos = nowNanos - startNanos - baseNanos;
83 System.out.println(String.format("PerformanceTests.fastAtan: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
84 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
85
86 startNanos = System.nanoTime();
87 for (int i = 0; i < iterations; i++)
88 {
89 double x = 0.1 + i / 1000.0;
90 double y = -0.5 + i / 2000.0;
91 Math.hypot(y, x);
92 }
93 nowNanos = System.nanoTime();
94 durationNanos = nowNanos - startNanos - baseNanos;
95 System.out.println(String.format("hypot: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
96 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
97
98 startNanos = System.nanoTime();
99 for (int i = 0; i < iterations; i++)
100 {
101 double x = 0.1 + i / 1000.0;
102 double y = -0.5 + i / 2000.0;
103 TestHypotAtan.hypotA(y, x);
104 }
105 nowNanos = System.nanoTime();
106 durationNanos = nowNanos - startNanos - baseNanos;
107 System.out.println(String.format("PerformanceTests.hypotA: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
108 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
109
110 startNanos = System.nanoTime();
111 for (int i = 0; i < iterations; i++)
112 {
113 double x = 0.1 + i / 1000.0;
114 double y = -0.5 + i / 2000.0;
115 TestHypotAtan.hypotB(y, x);
116 }
117 nowNanos = System.nanoTime();
118 durationNanos = nowNanos - startNanos - baseNanos;
119 System.out.println(String.format("PerformanceTests.hypotB: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
120 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
121
122 startNanos = System.nanoTime();
123 for (int i = 0; i < iterations; i++)
124 {
125 double x = 0.1 + i / 1000.0;
126 double y = -0.5 + i / 2000.0;
127 TestHypotAtan.hypotC(y, x);
128 }
129 nowNanos = System.nanoTime();
130 durationNanos = nowNanos - startNanos - baseNanos;
131 System.out.println(String.format("PerformanceTests.hypotC: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
132 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
133
134 startNanos = System.nanoTime();
135 for (int i = 0; i < iterations; i++)
136 {
137 double x = 0.1 + i / 1000000.0;
138 Math.sin(x);
139 }
140 nowNanos = System.nanoTime();
141 durationNanos = nowNanos - startNanos - baseNanos;
142 System.out.println(String.format(" sin: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
143 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
144
145 startNanos = System.nanoTime();
146 for (int i = 0; i < iterations; i++)
147 {
148 double x = 0.1 + i / 1000000.0;
149 Math.cos(x);
150 }
151 nowNanos = System.nanoTime();
152 durationNanos = nowNanos - startNanos - baseNanos;
153 System.out.println(String.format(" cos: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
154 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
155
156 startNanos = System.nanoTime();
157 for (int i = 0; i < iterations; i++)
158 {
159 double x = 0.1 + i / 1000.0;
160 double y = -0.5 + i / 2000.0;
161 Math.atan2(y, x);
162 }
163 nowNanos = System.nanoTime();
164 durationNanos = nowNanos - startNanos - baseNanos;
165 System.out.println(String.format("atan2: %d invocations in %.6f s (%.1f ns/invocation)", iterations,
166 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
167
168 startNanos = System.nanoTime();
169 for (int i = 0; i < iterations; i++)
170 {
171 double x = 0.1 + i / 1000.0;
172 double y = -0.5 + i / 2000.0;
173 Math.sqrt(x * x + y * y);
174 }
175 nowNanos = System.nanoTime();
176 durationNanos = nowNanos - startNanos - baseNanos;
177 System.out.println(String.format("sqrt(x*x+y*y): %d invocations in %.6f s (%.1f ns/invocation)", iterations,
178 durationNanos / 1000000000.0, 1.0 * durationNanos / iterations));
179 }
180
181
182 private static final double TWO_POW_450 = Double.longBitsToDouble(0x5C10000000000000L);
183
184
185 private static final double TWO_POW_N450 = Double.longBitsToDouble(0x23D0000000000000L);
186
187
188 private static final double TWO_POW_750 = Double.longBitsToDouble(0x6ED0000000000000L);
189
190
191 private static final double TWO_POW_N750 = Double.longBitsToDouble(0x1110000000000000L);
192
193
194
195
196
197
198
199 public static double hypotA(double x, double y)
200 {
201 x = Math.abs(x);
202 y = Math.abs(y);
203 if (y < x)
204 {
205 double a = x;
206 x = y;
207 y = a;
208 }
209 else if (!(y >= x))
210 {
211 if ((x == Double.POSITIVE_INFINITY) || (y == Double.POSITIVE_INFINITY))
212 {
213 return Double.POSITIVE_INFINITY;
214 }
215 else
216 {
217 return Double.NaN;
218 }
219 }
220 if (y - x == y)
221 {
222 return y;
223 }
224 else
225 {
226 double factor;
227 if (x > TWO_POW_450)
228 {
229 x *= TWO_POW_N750;
230 y *= TWO_POW_N750;
231 factor = TWO_POW_750;
232 }
233 else if (y < TWO_POW_N450)
234 {
235 x *= TWO_POW_750;
236 y *= TWO_POW_750;
237 factor = TWO_POW_N750;
238 }
239 else
240 {
241 factor = 1.0;
242 }
243 return factor * Math.sqrt(x * x + y * y);
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256
257 public static double hypotB(double x, double y)
258 {
259 if (Double.isInfinite(x) || Double.isInfinite(y))
260 {
261 return Double.POSITIVE_INFINITY;
262 }
263 if (Double.isNaN(x) || Double.isNaN(y))
264 {
265 return Double.NaN;
266 }
267
268 x = Math.abs(x);
269 y = Math.abs(y);
270
271 if (x < y)
272 {
273 double d = x;
274 x = y;
275 y = d;
276 }
277
278 int xi = Math.getExponent(x);
279 int yi = Math.getExponent(y);
280
281 if (xi > yi + 27)
282 {
283 return x;
284 }
285
286 int bias = 0;
287 if (xi > 510 || xi < -511)
288 {
289 bias = xi;
290 x = Math.scalb(x, -bias);
291 y = Math.scalb(y, -bias);
292 }
293
294
295 double z = 0;
296 if (x > 2 * y)
297 {
298 double x1 = Double.longBitsToDouble(Double.doubleToLongBits(x) & 0xffffffff00000000L);
299 double x2 = x - x1;
300 z = Math.sqrt(x1 * x1 + (y * y + x2 * (x + x1)));
301 }
302 else
303 {
304 double t = 2 * x;
305 double t1 = Double.longBitsToDouble(Double.doubleToLongBits(t) & 0xffffffff00000000L);
306 double t2 = t - t1;
307 double y1 = Double.longBitsToDouble(Double.doubleToLongBits(y) & 0xffffffff00000000L);
308 double y2 = y - y1;
309 double xMinusY = x - y;
310 z = Math.sqrt(t1 * y1 + (xMinusY * xMinusY + (t1 * y2 + t2 * y)));
311 }
312
313 if (bias == 0)
314 {
315 return z;
316 }
317 else
318 {
319 return Math.scalb(z, bias);
320 }
321 }
322
323
324
325
326
327
328
329 public static double hypotC(final double x, final double y)
330 {
331 if (Double.isInfinite(x) || Double.isInfinite(y))
332 {
333 return Double.POSITIVE_INFINITY;
334 }
335 if (Double.isNaN(x) || Double.isNaN(y))
336 {
337 return Double.NaN;
338 }
339
340
341
342 double h = Math.sqrt(Math.fma(x, x, y * y));
343 double hsq = h * h;
344 double xsq = x * x;
345 double a = Math.fma(-y, y, hsq - xsq) + Math.fma(h, h, -hsq) - Math.fma(x, x, -xsq);
346 return h - a / (2.0 * h);
347 }
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390 private static double tiny = 1.0e-300;
391
392
393 private static double zero = 0.0;
394
395
396 private static double pi_o_4 = 7.8539816339744827900E-01;
397
398
399 private static double pi_o_2 = 1.5707963267948965580E+00;
400
401
402 private static double pi = 3.1415926535897931160E+00;
403
404
405 private static double pi_lo = 1.2246467991473531772E-16;
406
407
408
409
410
411
412
413 @SuppressWarnings("checkstyle:needbraces")
414 private static double atan2(double y, double x)
415 {
416 double z;
417 int k, m, hx, hy, ix, iy;
418 long lx, ly;
419
420 hx = __HI(x);
421 ix = hx & 0x7fffffff;
422 lx = __LO(x);
423 hy = __HI(y);
424 iy = hy & 0x7fffffff;
425 ly = __LO(y);
426 if (((ix | ((lx | -lx) >> 31)) > 0x7ff00000) || ((iy | ((ly | -ly) >> 31)) > 0x7ff00000))
427 return x + y;
428 if ((hx - 0x3ff00000 | lx) == 0)
429 return atan(y);
430 m = ((hy >> 31) & 1) | ((hx >> 30) & 2);
431
432
433 if ((iy | ly) == 0)
434 {
435 switch (m)
436 {
437 case 0:
438 case 1:
439 return y;
440 case 2:
441 return pi + tiny;
442 case 3:
443 return -pi - tiny;
444 }
445 }
446
447 if ((ix | lx) == 0)
448 return (hy < 0) ? -pi_o_2 - tiny : pi_o_2 + tiny;
449
450
451 if (ix == 0x7ff00000)
452 {
453 if (iy == 0x7ff00000)
454 {
455 switch (m)
456 {
457 case 0:
458 return pi_o_4 + tiny;
459 case 1:
460 return -pi_o_4 - tiny;
461 case 2:
462 return 3.0 * pi_o_4 + tiny;
463 case 3:
464 return -3.0 * pi_o_4 - tiny;
465 }
466 }
467 else
468 {
469 switch (m)
470 {
471 case 0:
472 return zero;
473 case 1:
474 return -zero;
475 case 2:
476 return pi + tiny;
477 case 3:
478 return -pi - tiny;
479 }
480 }
481 }
482
483 if (iy == 0x7ff00000)
484 return (hy < 0) ? -pi_o_2 - tiny : pi_o_2 + tiny;
485
486
487 k = (iy - ix) >> 20;
488 if (k > 60)
489 z = pi_o_2 + 0.5 * pi_lo;
490 else if (hx < 0 && k < -60)
491 z = 0.0;
492 else
493 z = atan(Math.abs(y / x));
494 switch (m)
495 {
496 case 0:
497 return z;
498 case 1:
499
500 z = __HI(z, __HI(z) ^ 0x80000000);
501 return z;
502 case 2:
503 return pi - (z - pi_lo);
504 default:
505 return (z - pi_lo) - pi;
506 }
507 }
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537 private static double[] atanhi = {4.63647609000806093515e-01,
538 7.85398163397448278999e-01,
539 9.82793723247329054082e-01,
540 1.57079632679489655800e+00,
541 };
542
543
544 private static double[] atanlo = {2.26987774529616870924e-17,
545 3.06161699786838301793e-17,
546 1.39033110312309984516e-17,
547 6.12323399573676603587e-17,
548 };
549
550
551 private static double[] aT = {3.33333333333329318027e-01,
552 -1.99999999998764832476e-01,
553 1.42857142725034663711e-01,
554 -1.11111104054623557880e-01,
555 9.09088713343650656196e-02,
556 -7.69187620504482999495e-02,
557 6.66107313738753120669e-02,
558 -5.83357013379057348645e-02,
559 4.97687799461593236017e-02,
560 -3.65315727442169155270e-02,
561 1.62858201153657823623e-02,
562 };
563
564
565 private static double one = 1.0;
566
567
568 private static double huge = 1.0e300;
569
570
571
572
573
574
575 @SuppressWarnings("checkstyle:needbraces")
576 static double atan(double x)
577 {
578 double w, s1, s2, z;
579 int ix, hx, id;
580
581 hx = __HI(x);
582 ix = hx & 0x7fffffff;
583 if (ix >= 0x44100000)
584 {
585 if (ix > 0x7ff00000 || (ix == 0x7ff00000 && (__LO(x) != 0)))
586 return x + x;
587 if (hx > 0)
588 return atanhi[3] + atanlo[3];
589 else
590 return -atanhi[3] - atanlo[3];
591 }
592 if (ix < 0x3fdc0000)
593 {
594 if (ix < 0x3e200000)
595 {
596 if (huge + x > one)
597 return x;
598 }
599 id = -1;
600 }
601 else
602 {
603 x = Math.abs(x);
604 if (ix < 0x3ff30000)
605 {
606 if (ix < 0x3fe60000)
607 {
608 id = 0;
609 x = (2.0 * x - one) / (2.0 + x);
610 }
611 else
612 {
613 id = 1;
614 x = (x - one) / (x + one);
615 }
616 }
617 else
618 {
619 if (ix < 0x40038000)
620 {
621 id = 2;
622 x = (x - 1.5) / (one + 1.5 * x);
623 }
624 else
625 {
626 id = 3;
627 x = -1.0 / x;
628 }
629 }
630 }
631
632 z = x * x;
633 w = z * z;
634
635 s1 = z * (aT[0] + w * (aT[2] + w * (aT[4] + w * (aT[6] + w * (aT[8] + w * aT[10])))));
636 s2 = w * (aT[1] + w * (aT[3] + w * (aT[5] + w * (aT[7] + w * aT[9]))));
637 if (id < 0)
638 return x - x * (s1 + s2);
639 else
640 {
641 z = atanhi[id] - ((x * (s1 + s2) - atanlo[id]) - x);
642 return (hx < 0) ? -z : z;
643 }
644 }
645
646
647
648
649
650
651 private static int __LO(double x)
652 {
653 long transducer = Double.doubleToRawLongBits(x);
654 return (int) transducer;
655 }
656
657
658
659
660
661
662
663 private static double __LO(double x, int low)
664 {
665 long transX = Double.doubleToRawLongBits(x);
666 return Double.longBitsToDouble((transX & 0xFFFF_FFFF_0000_0000L) | (low & 0x0000_0000_FFFF_FFFFL));
667 }
668
669
670
671
672
673
674 private static int __HI(double x)
675 {
676 long transducer = Double.doubleToRawLongBits(x);
677 return (int) (transducer >> 32);
678 }
679
680
681
682
683
684
685
686 private static double __HI(double x, int high)
687 {
688 long transX = Double.doubleToRawLongBits(x);
689 return Double.longBitsToDouble((transX & 0x0000_0000_FFFF_FFFFL) | (((long) high)) << 32);
690 }
691
692
693
694
695
696 static double fastAtan(double x)
697 {
698 double u = 1.3654703620217001424e-2;
699 u = u * x + -1.0046251337641932974e-1;
700 u = u * x + 2.7313356251360220792e-1;
701 u = u * x + -3.2614626783181052668e-1;
702 u = u * x + 7.5150001258356942267e-2;
703 u = u * x + 1.8054329923285069577e-1;
704 u = u * x + 3.1227633392937778104e-3;
705 u = u * x + -3.3362526818403318876e-1;
706 u = u * x + 1.3994641595913163446e-5;
707 u = u * x + 9.9999973830765721236e-1;
708 return u * x + 8.0891638103222688273e-10;
709 }
710
711 }