303 */ |
303 */ |
304 friend std::ostream& operator << (std::ostream &os, const FixedT &value) { os << (double)value.m_data / (1ULL << Raw::dec_bits); return os; } |
304 friend std::ostream& operator << (std::ostream &os, const FixedT &value) { os << (double)value.m_data / (1ULL << Raw::dec_bits); return os; } |
305 |
305 |
306 }; |
306 }; |
307 |
307 |
308 |
308 /** The value of \f$\pi\f$ with ample precision for our computations */ |
|
309 static const FixedT<int64, 16> PI(3141592, 1000000); |
|
310 /** The number of elements used in Taylor approximations */ |
|
311 static const int PRECISION = 5; |
|
312 |
|
313 /** |
|
314 * Computes a single element of the Taylor series for the approximation of the cosine. |
|
315 * A single element of the Taylor series computes as: |
|
316 * \f[ |
|
317 * \frac{(-1)^nx^{2n}}{(2n)!} |
|
318 * \f] |
|
319 * In order to prevent overflows, underflows and other nasty stuff, we do not compute |
|
320 * the numerator and denominator separately in the formula but build a product of |
|
321 * fractions: |
|
322 * \f[ |
|
323 * \frac{x}{2n} * \frac{x}{2n-1} * \frac{x}{2n-2} ... |
|
324 * \f] |
|
325 * @param arg The value of "x" in above formula |
|
326 * @param pow The value of "2n" in above formula |
|
327 * @return The value of the element of the Taylor series |
|
328 */ |
|
329 template <typename Tstorage, int Tdec_bits> |
|
330 FixedT<Tstorage, Tdec_bits> trigbase(const FixedT<Tstorage, Tdec_bits> &arg, int pow) |
|
331 { |
|
332 /* Shortcut for the very first element */ |
|
333 if (pow == 0) return (FixedT<Tstorage, Tdec_bits>)1; |
|
334 |
|
335 /* find out the (-1)^n part, element should be negative if n is non-even |
|
336 * but "pow" already holds 2n, account for that |
|
337 */ |
|
338 bool neg = ( (pow / 2) % 2 > 0); |
|
339 |
|
340 FixedT<Tstorage, Tdec_bits> element = arg / pow; |
|
341 for (--pow; pow > 0; pow --) element *= arg / pow; |
|
342 |
|
343 return (neg) ? -element : element; |
|
344 } |
|
345 |
|
346 /** |
|
347 * Computes the cosine of an argument using a Taylor series. |
|
348 * @param arg The number to compute the cosine from, assumes arg to be in radians. |
|
349 * @returns The cosine |
|
350 * @todo Optimize the two while loops. |
|
351 * @note It is possible to factor out the series to optimize even further, but is it |
|
352 * worth the effort? It could reduce the opcount a little. |
|
353 * @see trigbase, PRECISION |
|
354 */ |
|
355 template <typename Tstorage, int Tdec_bits> |
|
356 FixedT<Tstorage, Tdec_bits> cos(const FixedT<Tstorage, Tdec_bits> &arg) |
|
357 { |
|
358 FixedT<Tstorage, Tdec_bits> l_arg = arg; |
|
359 FixedT<Tstorage, Tdec_bits> cosine = 0; |
|
360 |
|
361 /* We've got to adjust the argument around zero, otherwise we will need |
|
362 * (literally) hundreds of elements |
|
363 */ |
|
364 while (l_arg < -PI) l_arg += PI * 2; |
|
365 while (l_arg > PI) l_arg -= PI * 2; |
|
366 |
|
367 /* sum up the Taylor elements */ |
|
368 for(int i = 0; i < PRECISION; i++) cosine += trigbase(l_arg, 2 * i); |
|
369 |
|
370 return cosine; |
|
371 } |
|
372 |
|
373 /** |
|
374 * Computes the sine of an argument using a Taylor series, uses the cosine |
|
375 * computation in fact, as \f$sin(x) = cos(x - \frac{\pi}{2}))\f$ |
|
376 * @param arg The number to compute the cosine from, assumes arg to be in radians. |
|
377 * @returns The sine |
|
378 */ |
|
379 template <typename Tstorage, int Tdec_bits> |
|
380 FixedT<Tstorage, Tdec_bits> sin(const FixedT<Tstorage, Tdec_bits> &arg) |
|
381 { |
|
382 return cos(arg - PI / 2); |
|
383 } |
|
384 |