Skip to content

Commit b6c72c7

Browse files
Vincent SAMYgergondet
Vincent SAMY
authored andcommitted
Topic/sinc (#30)
* Add sinc. Add constexpr sqrt. * Delete some blank lines. * Pass sqrt as templated function
1 parent de34c58 commit b6c72c7

File tree

2 files changed

+94
-5
lines changed

2 files changed

+94
-5
lines changed

src/SpaceVecAlg/MathFunc.h

+71-4
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,86 @@
1717

1818
#pragma once
1919

20+
#include <limits>
21+
2022
namespace sva
2123
{
2224

25+
namespace details
26+
{
27+
28+
template <typename T>
29+
T constexpr sqrtNewtonRaphson(T x, T curr, T prev)
30+
{
31+
return curr == prev
32+
? curr
33+
: sqrtNewtonRaphson(x, static_cast<T>(0.5) * (curr + x / curr), curr);
34+
}
35+
36+
/**
37+
* Constexpr version of the square root
38+
* Return value:
39+
* - For a finite and non-negative value of "x", returns an approximation for the square root of "x"
40+
* - Otherwise, returns NaN
41+
* Copied from https://stackoverflow.com/a/34134071
42+
*/
43+
template <typename T>
44+
T constexpr sqrt(T x)
45+
{
46+
return x >= static_cast<T>(0) && x < std::numeric_limits<T>::infinity()
47+
? sqrtNewtonRaphson(x, x, static_cast<T>(0))
48+
: std::numeric_limits<T>::quiet_NaN();
49+
}
50+
51+
} // namespace details
52+
53+
/** sinus cardinal: sin(x)/x
54+
* Code adapted from boost::math::detail::sinc
55+
*/
56+
template<typename T>
57+
T sinc(const T x)
58+
{
59+
constexpr T taylor_0_bound = std::numeric_limits<double>::epsilon();
60+
constexpr T taylor_2_bound = details::sqrt(taylor_0_bound);
61+
constexpr T taylor_n_bound = details::sqrt(taylor_2_bound);
62+
63+
if (std::abs(x) >= taylor_n_bound)
64+
{
65+
return(std::sin(x) / x);
66+
}
67+
else
68+
{
69+
// approximation by taylor series in x at 0 up to order 0
70+
T result = static_cast<T>(1);
71+
72+
if (std::abs(x) >= taylor_0_bound)
73+
{
74+
T x2 = x*x;
75+
76+
// approximation by taylor series in x at 0 up to order 2
77+
result -= x2 / static_cast<T>(6);
78+
79+
if (std::abs(x) >= taylor_2_bound)
80+
{
81+
// approximation by taylor series in x at 0 up to order 4
82+
result += (x2*x2) / static_cast<T>(120);
83+
}
84+
}
85+
86+
return(result);
87+
}
88+
}
89+
2390
/**
2491
* Compute 1/sinc(x).
2592
* This code is inspired by boost/math/special_functions/sinc.hpp.
2693
*/
2794
template<typename T>
2895
T sinc_inv(const T x)
2996
{
30-
const T taylor_0_bound = std::numeric_limits<T>::epsilon();
31-
const T taylor_2_bound = std::sqrt(taylor_0_bound);
32-
const T taylor_n_bound = std::sqrt(taylor_2_bound);
97+
constexpr T taylor_0_bound = std::numeric_limits<T>::epsilon();
98+
constexpr T taylor_2_bound = details::sqrt(taylor_0_bound);
99+
constexpr T taylor_n_bound = details::sqrt(taylor_2_bound);
33100

34101
// We use the 4th order taylor series around 0 of x/sin(x) to compute
35102
// this function:
@@ -71,4 +138,4 @@ T sinc_inv(const T x)
71138
}
72139
}
73140

74-
}
141+
} // namespace sva

tests/PTransformTest.cpp

+23-1
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,29 @@ BOOST_AUTO_TEST_CASE(TransformError)
352352
BOOST_CHECK_SMALL((V_b_c_a.linear() - v_b_c_a).norm(), TOL);
353353
}
354354

355+
BOOST_AUTO_TEST_CASE(sincTest)
356+
{
357+
auto dummy_sinc = [](double x){return std::sin(x)/x;};
358+
double eps = std::numeric_limits<double>::epsilon();
359+
360+
// test equality between -1 and 1 (avoid 0)
361+
double t = -1.;
362+
const int nrIter = 333;
363+
for(int i = 0; i < nrIter; ++i)
364+
{
365+
BOOST_CHECK_EQUAL(dummy_sinc(t), sva::sinc(t));
366+
t += 2./nrIter;
367+
}
368+
BOOST_CHECK(std::isnan(dummy_sinc(0.)));
369+
BOOST_CHECK_EQUAL(sva::sinc(0.), 1.);
370+
371+
// not sure thoses test will work on all architectures
372+
BOOST_CHECK_EQUAL(dummy_sinc(eps), sva::sinc(eps));
373+
BOOST_CHECK_EQUAL(dummy_sinc(std::sqrt(eps)),
374+
sva::sinc(std::sqrt(eps)));
375+
BOOST_CHECK_EQUAL(dummy_sinc(std::sqrt(std::sqrt(eps))),
376+
sva::sinc(std::sqrt(std::sqrt(eps))));
377+
}
355378

356379
BOOST_AUTO_TEST_CASE(sinc_invTest)
357380
{
@@ -377,7 +400,6 @@ BOOST_AUTO_TEST_CASE(sinc_invTest)
377400
sva::sinc_inv(std::sqrt(std::sqrt(eps))));
378401
}
379402

380-
381403
template<typename T>
382404
inline Eigen::Vector3<T> oldRotationVelocity(const Eigen::Matrix3<T>& E_a_b, double prec)
383405
{

0 commit comments

Comments
 (0)