blob: 4757239d378e8402089e4bfade0a4e1424aaee2f [file] [log] [blame]
Maxwell Henderson80bec322024-01-09 15:48:44 -08001From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2From: Tyler Veness <calcmogul@gmail.com>
3Date: Sun, 3 Dec 2023 14:03:58 -0800
4Subject: [PATCH 2/2] Add hypot(x, y, z)
5
6---
7 include/gcem_incl/hypot.hpp | 85 +++++++++++++++++++++++++++++++++++--
8 1 file changed, 82 insertions(+), 3 deletions(-)
9
10diff --git a/include/gcem_incl/hypot.hpp b/include/gcem_incl/hypot.hpp
11index 00e10f899ace8f0da925fa9e46fa3f79f7e83aa0..13ea80c49d374c23434c1f9859bb6474184dc420 100644
12--- a/include/gcem_incl/hypot.hpp
13+++ b/include/gcem_incl/hypot.hpp
14@@ -27,6 +27,7 @@
15 #ifndef _gcem_hypot_HPP
16 #define _gcem_hypot_HPP
17
18+#include <algorithm>
19 #include <cmath>
20 #include <type_traits>
21
22@@ -39,10 +40,29 @@ namespace internal
23 template<typename T>
24 constexpr
25 T
26-hypot_compute(const T x, const T ydx)
27+hypot_compute(const T x, const T y)
28 noexcept
29 {
30- return abs(x) * sqrt( T(1) + (ydx * ydx) );
31+ T a = std::max(abs(x), abs(y));
32+ if (a) {
33+ return a * sqrt((x / a) * (x / a) + (y / a) * (y / a));
34+ } else {
35+ return {};
36+ }
37+}
38+
39+template<typename T>
40+constexpr
41+T
42+hypot_compute(const T x, const T y, const T z)
43+noexcept
44+{
45+ T a = std::max({abs(x), abs(y), abs(z)});
46+ if (a) {
47+ return a * sqrt((x / a) * (x / a) + (y / a) * (y / a) + (z / a) * (z / a));
48+ } else {
49+ return {};
50+ }
51 }
52
53 template<typename T>
54@@ -62,7 +82,35 @@ noexcept
55 GCLIM<T>::min() > abs(y) ? \
56 abs(x) :
57 // else
58- hypot_compute(x, y/x) );
59+ hypot_compute(x, y) );
60+}
61+
62+template<typename T>
63+constexpr
64+T
65+hypot_vals_check(const T x, const T y, const T z)
66+noexcept
67+{
68+ return( any_nan(x, y, z) ? \
69+ GCLIM<T>::quiet_NaN() :
70+ //
71+ any_inf(x,y,z) ? \
72+ GCLIM<T>::infinity() :
73+ // indistinguishable from zero or one
74+ GCLIM<T>::min() > abs(x) && GCLIM<T>::min() > abs(y) ? \
75+ abs(z) :
76+ GCLIM<T>::min() > abs(x) && GCLIM<T>::min() > abs(z) ? \
77+ abs(y) :
78+ GCLIM<T>::min() > abs(y) && GCLIM<T>::min() > abs(z) ? \
79+ abs(x) :
80+ GCLIM<T>::min() > abs(x) ? \
81+ hypot_vals_check(y, z) :
82+ GCLIM<T>::min() > abs(y) ? \
83+ hypot_vals_check(x, z) :
84+ GCLIM<T>::min() > abs(z) ? \
85+ hypot_vals_check(x, y) :
86+ // else
87+ hypot_compute(x, y, z) );
88 }
89
90 template<typename T1, typename T2, typename TC = common_return_t<T1,T2>>
91@@ -74,6 +122,15 @@ noexcept
92 return hypot_vals_check(static_cast<TC>(x),static_cast<TC>(y));
93 }
94
95+template<typename T1, typename T2, typename T3, typename TC = common_return_t<T1,T2,T3>>
96+constexpr
97+TC
98+hypot_type_check(const T1 x, const T2 y, const T3 z)
99+noexcept
100+{
101+ return hypot_vals_check(static_cast<TC>(x),static_cast<TC>(y),static_cast<TC>(z));
102+}
103+
104 }
105
106 /**
107@@ -97,6 +154,28 @@ noexcept
108 }
109 }
110
111+/**
112+ * Compile-time Pythagorean addition function
113+ *
114+ * @param x a real-valued input.
115+ * @param y a real-valued input.
116+ * @param z a real-valued input.
117+ * @return Computes \f$ x \oplus y \oplus z = \sqrt{x^2 + y^2 + z^2} \f$.
118+ */
119+
120+template<typename T1, typename T2, typename T3>
121+constexpr
122+common_return_t<T1,T2,T3>
123+hypot(const T1 x, const T2 y, const T3 z)
124+noexcept
125+{
126+ if (std::is_constant_evaluated()) {
127+ return internal::hypot_type_check(x,y,z);
128+ } else {
129+ return std::hypot(x, y, z);
130+ }
131+}
132+
133 }
134
135 #endif