1- // Copyright 2024 Matt Borland
1+ // Copyright 2024 - 2025 Matt Borland
2+ // Copyright 2024 - 2025 Christopher Kormanyos
23// Distributed under the Boost Software License, Version 1.0.
34// https://www.boost.org/LICENSE_1_0.txt
45
1415# pragma clang diagnostic ignored "-Wconversion"
1516# pragma clang diagnostic ignored "-Wsign-conversion"
1617# pragma clang diagnostic ignored "-Wfloat-equal"
17- # if __clang_major__ >= 20
18+ # if ( __clang_major__ >= 20)
1819# pragma clang diagnostic ignored "-Wfortify-source"
1920# endif
2021#elif defined(__GNUC__)
2829
2930#include < boost/math/special_functions/next.hpp>
3031#include < boost/core/lightweight_test.hpp>
31- #include < iostream>
32- #include < random>
32+
3333#include < cmath>
34+ #include < random>
3435
3536#if !defined(BOOST_DECIMAL_REDUCE_TEST_DEPTH)
3637static constexpr auto N = static_cast <std::size_t >(128U ); // Number of trials
@@ -42,6 +43,9 @@ static std::mt19937_64 rng(42);
4243
4344using namespace boost ::decimal;
4445
46+ template <typename T> auto my_zero () -> T;
47+ template <typename T> auto my_one () -> T;
48+
4549template <typename Dec>
4650void test_asin ()
4751{
@@ -137,6 +141,100 @@ void print_value(T value, const char* str)
137141 << " \n Exp: " << ptr << " \n " << std::endl;
138142}
139143
144+ template <typename T>
145+ auto test_asin_edge () -> void
146+ {
147+ using nl = std::numeric_limits<T>;
148+
149+ const T tiny0 { nl::epsilon () * 999 / 1000 };
150+ const T tiny1 { nl::epsilon () };
151+ const T tiny2 { nl::epsilon () * 1000 / 999 };
152+
153+ const T asin_tiny0 { asin (tiny0) };
154+ const T asin_tiny1 { asin (tiny1) };
155+ const T asin_tiny2 { asin (tiny2) };
156+
157+ // tiny1: 1
158+ // tiny2: 1.001001
159+ // tiny0: 0.999
160+ // tiny1: 1
161+ // tiny2: 1.001001001001001
162+ // tiny0: 0.999
163+ // tiny1: 1
164+ // tiny2: 1.001001001001001001001001001001001
165+
166+ constexpr T ctrl_tiny2
167+ {
168+ std::numeric_limits<T>::digits10 < 10 ? T (" 1.001001" )
169+ : std::numeric_limits<T>::digits10 < 20 ? T (" 1.001001001001001" )
170+ : T (" 1.001001001001001001001001001001001" )
171+ };
172+
173+ BOOST_TEST_EQ (asin_tiny0 / nl::epsilon (), T (999 , -3 ));
174+ BOOST_TEST_EQ (asin_tiny1 / nl::epsilon (), T (1 ));
175+ BOOST_TEST_EQ (asin_tiny2 / nl::epsilon (), ctrl_tiny2);
176+
177+ constexpr T half_pi { numbers::pi_v<T> / 2 };
178+
179+ BOOST_TEST_EQ (asin (my_zero<T>() + my_one<T>()), half_pi);
180+ BOOST_TEST_EQ (asin (my_zero<T>() - my_one<T>()), -half_pi);
181+ }
182+
183+ template <typename T>
184+ void test_asin_1137 ()
185+ {
186+ using nl = std::numeric_limits<T>;
187+
188+ const T tiny0 { nl::epsilon () * 999 /1000 };
189+ const T tiny1 { nl::epsilon () };
190+ const T tiny2 { nl::epsilon () * 1000 /999 };
191+
192+ BOOST_TEST (tiny0 != tiny1);
193+ BOOST_TEST (tiny1 != tiny2);
194+
195+ std::stringstream strm { };
196+
197+ BOOST_TEST_EQ (tiny0, asin (tiny0));
198+ BOOST_TEST_EQ (tiny1, asin (tiny1));
199+ BOOST_TEST_EQ (tiny2, asin (tiny2));
200+
201+ const T sqrt_tiny0 { sqrt (nl::epsilon () * 999 /1000 ) };
202+ const T sqrt_tiny1 { sqrt (nl::epsilon ()) };
203+ const T sqrt_tiny2 { sqrt (nl::epsilon () * 1000 /999 ) };
204+
205+ BOOST_TEST_EQ (sqrt_tiny0, asin (sqrt_tiny0));
206+ BOOST_TEST_EQ (sqrt_tiny1, asin (sqrt_tiny1));
207+ BOOST_TEST_EQ (sqrt_tiny2, asin (sqrt_tiny2));
208+
209+ const T cbrt_tiny0 { cbrt (nl::epsilon () * 999 /1000 ) };
210+ const T cbrt_tiny1 { cbrt (nl::epsilon ()) };
211+ const T cbrt_tiny2 { cbrt (nl::epsilon () * 1000 /999 ) };
212+ const T cbrt_tiny3 { cbrt (nl::epsilon () * 1004 /999 ) };
213+
214+ auto mini_series
215+ {
216+ [](const T eps)
217+ {
218+ return eps * (1 + (eps / 6 ) * eps);
219+ }
220+ };
221+
222+ auto is_close
223+ {
224+ [](const T a, const T b)
225+ {
226+ const T delta { fabs (a - b) };
227+
228+ return (delta < (std::numeric_limits<T>::epsilon () * 4 ));
229+ }
230+ };
231+
232+ BOOST_TEST (is_close (asin (cbrt_tiny0), mini_series (cbrt_tiny0)));
233+ BOOST_TEST (is_close (asin (cbrt_tiny1), mini_series (cbrt_tiny1)));
234+ BOOST_TEST (is_close (asin (cbrt_tiny2), mini_series (cbrt_tiny2)));
235+ BOOST_TEST (is_close (asin (cbrt_tiny3), mini_series (cbrt_tiny3)));
236+ }
237+
140238int main ()
141239{
142240 #ifdef BOOST_DECIMAL_GENERATE_CONSTANT_SIGS
@@ -187,12 +285,22 @@ int main()
187285
188286 test_asin<decimal32_t >();
189287 test_asin<decimal64_t >();
190-
191288 #if !defined(BOOST_DECIMAL_REDUCE_TEST_DEPTH)
192289 test_asin<decimal128_t >();
193290 #endif
194291
195292 test_asin<decimal_fast32_t >();
196293
294+ test_asin_edge<decimal32_t >();
295+ test_asin_edge<decimal64_t >();
296+ test_asin_edge<decimal128_t >();
297+
298+ test_asin_1137<decimal32_t >();
299+ test_asin_1137<decimal64_t >();
300+ test_asin_1137<decimal128_t >();
301+
197302 return boost::report_errors ();
198303}
304+
305+ template <typename T> auto my_zero () -> T { T zero { 0 }; return zero; }
306+ template <typename T> auto my_one () -> T { T one { 1 }; return one; }
0 commit comments