CMS 3D CMS Logo

approx_atan2.h
Go to the documentation of this file.
1 #ifndef DataFormatsMathAPPROX_ATAN2_H
2 #define DataFormatsMathAPPROX_ATAN2_H
3 
4 /*
5  * approximate atan2 evaluations
6  *
7  * Polynomials were obtained using Sollya scripts (in comments below)
8  *
9  *
10 */
11 
12 /*
13 f= atan((1-x)/(1+x))-atan(1);
14 I=[-1+10^(-4);1.0];
15 filename="atan.txt";
16 print("") > filename;
17 for deg from 3 to 11 do begin
18  p = fpminimax(f, deg,[|1,23...|],I, floating, absolute);
19  display=decimal;
20  acc=floor(-log2(sup(supnorm(p, f, I, absolute, 2^(-20)))));
21  print( " // degree = ", deg,
22  " => absolute accuracy is ", acc, "bits" ) >> filename;
23  print("template<> constexpr float approx_atan2f_P<", deg, ">(float x){") >> filename;
24  display=hexadecimal;
25  print(" return ", horner(p) , ";") >> filename;
26  print("}") >> filename;
27 end;
28 */
29 
30 #include <cstdint>
31 #include <cmath>
32 #include <limits>
33 #include <algorithm>
34 
35 // float
36 
37 template <int DEGREE>
38 constexpr float approx_atan2f_P(float x);
39 
40 // degree = 3 => absolute accuracy is 7 bits
41 template <>
42 constexpr float approx_atan2f_P<3>(float x) {
43  return x * (float(-0xf.8eed2p-4) + x * x * float(0x3.1238p-4));
44 }
45 
46 // degree = 5 => absolute accuracy is 10 bits
47 template <>
48 constexpr float approx_atan2f_P<5>(float x) {
49  auto z = x * x;
50  return x * (float(-0xf.ecfc8p-4) + z * (float(0x4.9e79dp-4) + z * float(-0x1.44f924p-4)));
51 }
52 
53 // degree = 7 => absolute accuracy is 13 bits
54 template <>
55 constexpr float approx_atan2f_P<7>(float x) {
56  auto z = x * x;
57  return x * (float(-0xf.fcc7ap-4) + z * (float(0x5.23886p-4) + z * (float(-0x2.571968p-4) + z * float(0x9.fb05p-8))));
58 }
59 
60 // degree = 9 => absolute accuracy is 16 bits
61 template <>
62 constexpr float approx_atan2f_P<9>(float x) {
63  auto z = x * x;
64  return x * (float(-0xf.ff73ep-4) +
65  z * (float(0x5.48ee1p-4) +
66  z * (float(-0x2.e1efe8p-4) + z * (float(0x1.5cce54p-4) + z * float(-0x5.56245p-8)))));
67 }
68 
69 // degree = 11 => absolute accuracy is 19 bits
70 template <>
71 constexpr float approx_atan2f_P<11>(float x) {
72  auto z = x * x;
73  return x * (float(-0xf.ffe82p-4) +
74  z * (float(0x5.526c8p-4) +
75  z * (float(-0x3.18bea8p-4) +
76  z * (float(0x1.dce3bcp-4) + z * (float(-0xd.7a64ap-8) + z * float(0x3.000eap-8))))));
77 }
78 
79 // degree = 13 => absolute accuracy is 21 bits
80 template <>
81 constexpr float approx_atan2f_P<13>(float x) {
82  auto z = x * x;
83  return x * (float(-0xf.fffbep-4) +
84  z * (float(0x5.54adp-4) +
85  z * (float(-0x3.2b4df8p-4) +
86  z * (float(0x2.1df79p-4) +
87  z * (float(-0x1.46081p-4) + z * (float(0x8.99028p-8) + z * float(-0x1.be0bc4p-8)))))));
88 }
89 
90 // degree = 15 => absolute accuracy is 24 bits
91 template <>
92 constexpr float approx_atan2f_P<15>(float x) {
93  auto z = x * x;
94  return x * (float(-0xf.ffff4p-4) +
95  z * (float(0x5.552f9p-4 + z * (float(-0x3.30f728p-4) +
96  z * (float(0x2.39826p-4) +
97  z * (float(-0x1.8a880cp-4) +
98  z * (float(0xe.484d6p-8) +
99  z * (float(-0x5.93d5p-8) + z * float(0x1.0875dcp-8)))))))));
100 }
101 
102 template <int DEGREE>
103 constexpr float unsafe_atan2f_impl(float y, float x) {
104  constexpr float pi4f = 3.1415926535897932384626434 / 4;
105  constexpr float pi34f = 3.1415926535897932384626434 * 3 / 4;
106 
107  auto r = (std::abs(x) - std::abs(y)) / (std::abs(x) + std::abs(y));
108  if (x < 0)
109  r = -r;
110 
111  auto angle = (x >= 0) ? pi4f : pi34f;
112  angle += approx_atan2f_P<DEGREE>(r);
113 
114  return ((y < 0)) ? -angle : angle;
115 }
116 
117 template <int DEGREE>
118 constexpr float unsafe_atan2f(float y, float x) {
119  return unsafe_atan2f_impl<DEGREE>(y, x);
120 }
121 
122 template <int DEGREE>
123 constexpr float safe_atan2f(float y, float x) {
124  return unsafe_atan2f_impl<DEGREE>(y, ((y == 0.f) & (x == 0.f)) ? 0.2f : x);
125  // return (y==0.f)&(x==0.f) ? 0.f : unsafe_atan2f_impl<DEGREE>( y, x);
126 }
127 
128 // integer...
129 /*
130  f= (2^31/pi)*(atan((1-x)/(1+x))-atan(1));
131  I=[-1+10^(-4);1.0];
132  p = fpminimax(f, [|1,3,5,7,9,11|],[|23...|],I, floating, absolute);
133  */
134 
135 template <int DEGREE>
136 constexpr float approx_atan2i_P(float x);
137 
138 // degree = 3 => absolute accuracy is 6*10^6
139 template <>
140 constexpr float approx_atan2i_P<3>(float x) {
141  auto z = x * x;
142  return x * (-664694912.f + z * 131209024.f);
143 }
144 
145 // degree = 5 => absolute accuracy is 4*10^5
146 template <>
147 constexpr float approx_atan2i_P<5>(float x) {
148  auto z = x * x;
149  return x * (-680392064.f + z * (197338400.f + z * (-54233256.f)));
150 }
151 
152 // degree = 7 => absolute accuracy is 6*10^4
153 template <>
154 constexpr float approx_atan2i_P<7>(float x) {
155  auto z = x * x;
156  return x * (-683027840.f + z * (219543904.f + z * (-99981040.f + z * 26649684.f)));
157 }
158 
159 // degree = 9 => absolute accuracy is 8000
160 template <>
161 constexpr float approx_atan2i_P<9>(float x) {
162  auto z = x * x;
163  return x * (-683473920.f + z * (225785056.f + z * (-123151184.f + z * (58210592.f + z * (-14249276.f)))));
164 }
165 
166 // degree = 11 => absolute accuracy is 1000
167 template <>
168 constexpr float approx_atan2i_P<11>(float x) {
169  auto z = x * x;
170  return x *
171  (-683549696.f + z * (227369312.f + z * (-132297008.f + z * (79584144.f + z * (-35987016.f + z * 8010488.f)))));
172 }
173 
174 // degree = 13 => absolute accuracy is 163
175 template <>
176 constexpr float approx_atan2i_P<13>(float x) {
177  auto z = x * x;
178  return x * (-683562624.f +
179  z * (227746080.f +
180  z * (-135400128.f + z * (90460848.f + z * (-54431464.f + z * (22973256.f + z * (-4657049.f)))))));
181 }
182 
183 template <>
184 constexpr float approx_atan2i_P<15>(float x) {
185  auto z = x * x;
186  return x * (-683562624.f +
187  z * (227746080.f +
188  z * (-135400128.f + z * (90460848.f + z * (-54431464.f + z * (22973256.f + z * (-4657049.f)))))));
189 }
190 
191 template <int DEGREE>
192 constexpr int unsafe_atan2i_impl(float y, float x) {
193  constexpr long long maxint = (long long)(std::numeric_limits<int>::max()) + 1LL;
194  constexpr int pi4 = int(maxint / 4LL);
195  constexpr int pi34 = int(3LL * maxint / 4LL);
196 
197  auto r = (std::abs(x) - std::abs(y)) / (std::abs(x) + std::abs(y));
198  if (x < 0)
199  r = -r;
200 
201  auto angle = (x >= 0) ? pi4 : pi34;
202  angle += int(approx_atan2i_P<DEGREE>(r));
203  // angle += int(std::round(approx_atan2i_P<DEGREE>(r)));
204 
205  return (y < 0) ? -angle : angle;
206 }
207 
208 template <int DEGREE>
209 constexpr int unsafe_atan2i(float y, float x) {
210  return unsafe_atan2i_impl<DEGREE>(y, x);
211 }
212 
213 // short (16bits)
214 
215 template <int DEGREE>
216 constexpr float approx_atan2s_P(float x);
217 
218 // degree = 3 => absolute accuracy is 53
219 template <>
220 constexpr float approx_atan2s_P<3>(float x) {
221  auto z = x * x;
222  return x * ((-10142.439453125f) + z * 2002.0908203125f);
223 }
224 // degree = 5 => absolute accuracy is 7
225 template <>
226 constexpr float approx_atan2s_P<5>(float x) {
227  auto z = x * x;
228  return x * ((-10381.9609375f) + z * ((3011.1513671875f) + z * (-827.538330078125f)));
229 }
230 // degree = 7 => absolute accuracy is 2
231 template <>
232 constexpr float approx_atan2s_P<7>(float x) {
233  auto z = x * x;
234  return x * ((-10422.177734375f) + z * (3349.97412109375f + z * ((-1525.589599609375f) + z * 406.64190673828125f)));
235 }
236 // degree = 9 => absolute accuracy is 1
237 template <>
238 constexpr float approx_atan2s_P<9>(float x) {
239  auto z = x * x;
240  return x * ((-10428.984375f) + z * (3445.20654296875f + z * ((-1879.137939453125f) +
241  z * (888.22314453125f + z * (-217.42669677734375f)))));
242 }
243 
244 template <int DEGREE>
245 constexpr short unsafe_atan2s_impl(float y, float x) {
246  constexpr int maxshort = (int)(std::numeric_limits<short>::max()) + 1;
247  constexpr short pi4 = short(maxshort / 4);
248  constexpr short pi34 = short(3 * maxshort / 4);
249 
250  auto r = (std::abs(x) - std::abs(y)) / (std::abs(x) + std::abs(y));
251  if (x < 0)
252  r = -r;
253 
254  auto angle = (x >= 0) ? pi4 : pi34;
255  angle += short(approx_atan2s_P<DEGREE>(r));
256 
257  return (y < 0) ? -angle : angle;
258 }
259 
260 template <int DEGREE>
261 constexpr short unsafe_atan2s(float y, float x) {
262  return unsafe_atan2s_impl<DEGREE>(y, x);
263 }
264 
265 constexpr int phi2int(float x) {
266  constexpr float p2i = ((long long)(std::numeric_limits<int>::max()) + 1LL) / M_PI;
267  return std::round(x * p2i);
268 }
269 
270 constexpr float int2phi(int x) {
271  constexpr float i2p = M_PI / ((long long)(std::numeric_limits<int>::max()) + 1LL);
272  return float(x) * i2p;
273 }
274 
275 constexpr double int2dphi(int x) {
276  constexpr double i2p = M_PI / ((long long)(std::numeric_limits<int>::max()) + 1LL);
277  return x * i2p;
278 }
279 
280 constexpr short phi2short(float x) {
281  constexpr float p2i = ((int)(std::numeric_limits<short>::max()) + 1) / M_PI;
282  return std::round(x * p2i);
283 }
284 
285 constexpr float short2phi(short x) {
286  constexpr float i2p = M_PI / ((int)(std::numeric_limits<short>::max()) + 1);
287  return float(x) * i2p;
288 }
289 
290 #endif
constexpr float approx_atan2f_P< 13 >(float x)
Definition: approx_atan2.h:81
constexpr short phi2short(float x)
Definition: approx_atan2.h:280
constexpr int unsafe_atan2i(float y, float x)
Definition: approx_atan2.h:209
constexpr float approx_atan2s_P< 3 >(float x)
Definition: approx_atan2.h:220
constexpr float approx_atan2i_P< 9 >(float x)
Definition: approx_atan2.h:161
constexpr float approx_atan2f_P< 15 >(float x)
Definition: approx_atan2.h:92
constexpr float approx_atan2i_P< 3 >(float x)
Definition: approx_atan2.h:140
constexpr float approx_atan2s_P< 7 >(float x)
Definition: approx_atan2.h:232
float float float z
constexpr float safe_atan2f(float y, float x)
Definition: approx_atan2.h:123
constexpr float approx_atan2f_P< 7 >(float x)
Definition: approx_atan2.h:55
constexpr float unsafe_atan2f(float y, float x)
Definition: approx_atan2.h:118
constexpr double int2dphi(int x)
Definition: approx_atan2.h:275
constexpr short unsafe_atan2s_impl(float y, float x)
Definition: approx_atan2.h:245
constexpr float approx_atan2s_P(float x)
constexpr float approx_atan2f_P< 5 >(float x)
Definition: approx_atan2.h:48
constexpr float approx_atan2f_P(float x)
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
constexpr float approx_atan2i_P< 15 >(float x)
Definition: approx_atan2.h:184
double f[11][100]
constexpr float approx_atan2s_P< 9 >(float x)
Definition: approx_atan2.h:238
constexpr float int2phi(int x)
Definition: approx_atan2.h:270
#define M_PI
constexpr float approx_atan2i_P(float x)
constexpr float approx_atan2i_P< 7 >(float x)
Definition: approx_atan2.h:154
constexpr short unsafe_atan2s(float y, float x)
Definition: approx_atan2.h:261
constexpr float approx_atan2i_P< 5 >(float x)
Definition: approx_atan2.h:147
constexpr float short2phi(short x)
Definition: approx_atan2.h:285
constexpr float approx_atan2f_P< 11 >(float x)
Definition: approx_atan2.h:71
constexpr float approx_atan2s_P< 5 >(float x)
Definition: approx_atan2.h:226
constexpr float approx_atan2i_P< 11 >(float x)
Definition: approx_atan2.h:168
float x
constexpr float unsafe_atan2f_impl(float y, float x)
Definition: approx_atan2.h:103
constexpr float approx_atan2f_P< 9 >(float x)
Definition: approx_atan2.h:62
constexpr int phi2int(float x)
Definition: approx_atan2.h:265
constexpr float approx_atan2i_P< 13 >(float x)
Definition: approx_atan2.h:176
constexpr int unsafe_atan2i_impl(float y, float x)
Definition: approx_atan2.h:192
constexpr float approx_atan2f_P< 3 >(float x)
Definition: approx_atan2.h:42
T angle(T x1, T y1, T z1, T x2, T y2, T z2)
Definition: angle.h:11