Skip to content

Commit

Permalink
Add acos() and its tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ckormanyos committed Feb 5, 2024
1 parent 403af94 commit 4a8554c
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 6 deletions.
62 changes: 56 additions & 6 deletions math/softfloat/soft_double.h
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using representation_type = std::uint64_t;

constexpr soft_double() noexcept : my_value(static_cast<std::uint64_t>(UINT8_C(0))) { }
constexpr soft_double() noexcept = default;

template<typename UnsignedIntegralType,
typename std::enable_if<( std::is_integral<UnsignedIntegralType>::value
Expand Down Expand Up @@ -2682,11 +2682,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
}
else if(x < static_cast<int>(INT8_C(1)))
{
if(x < soft_double::my_value_epsilon())
{
result = x;
}
else if(x < soft_double::my_value_half())
if(x < soft_double::my_value_half())
{
result = detail::asin_pade(x);
}
Expand All @@ -2708,6 +2704,60 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
return result;
}

constexpr auto acos(soft_double x) -> soft_double // NOLINT(performance-unnecessary-value-param)
{
soft_double result { };

if(x < -soft_double::my_value_one())
{
result = soft_double::my_value_quiet_NaN();
}
else if(x > -soft_double::my_value_one())
{
const auto absx = fabs(x);

if(x > soft_double::my_value_one())
{
result = soft_double::my_value_quiet_NaN();
}
else if(x < soft_double::my_value_one())
{
if(x < -soft_double::my_value_half())
{
result = soft_double::my_value_pi() - 2 * detail::asin_pade(sqrt((1 - absx) / 2));
}
else if(x < soft_double::my_value_zero())
{
result = soft_double::my_value_pi_half() + detail::asin_pade(absx);
}
else if((x > soft_double::my_value_zero()) && (x < soft_double::my_value_half()))
{
result = soft_double::my_value_pi_half() - detail::asin_pade(x);
}
else if(x >= soft_double::my_value_half())
{
result = 2 * detail::asin_pade(sqrt((1 - x) / 2));
}
else
{
result = soft_double::my_value_pi_half();
}
}
else
{
// x == 1 and result = zero.
result = soft_double::my_value_zero();
}
}
else
{
// x == -1 and result = pi.
result = soft_double::my_value_pi();
}

return result;
}

constexpr auto floor(soft_double x) -> soft_double // NOLINT(performance-unnecessary-value-param)
{
auto result = soft_double { };
Expand Down
100 changes: 100 additions & 0 deletions test/test_soft_double.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,104 @@ auto test_asin() -> bool
return result_is_ok;
}

auto test_acos() -> bool
{
bool result_is_ok = true;

for(int i = 0; i < 100; ++i) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
{
const math::softfloat::float64_t x = math::softfloat::float64_t(i) / 100; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
const auto d = static_cast<double>(x);

using std::acos;

const math::softfloat::float64_t ac_x = acos(x);
const double ac_d = acos(d);

if(i == 0)
{
const auto result_acos_zero_is_ok = (ac_x == math::softfloat::float64_t::my_value_pi_half());

result_is_ok = (result_acos_zero_is_ok && result_is_ok);
}
else
{
const double closeness = std::fabs(1.0 - (static_cast<double>(ac_x) / ac_d));

const auto result_acos_is_ok = (closeness < std::numeric_limits<double>::epsilon() * 64.0); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)

result_is_ok = (result_acos_is_ok && result_is_ok);
}
}

{
const math::softfloat::float64_t x = math::softfloat::float64_t(-33) / 100;
const auto d = static_cast<double>(x);

using std::acos;

const math::softfloat::float64_t ac_x = acos(x);
const double ac_d = acos(d);

const double closeness = std::fabs(1.0 - (static_cast<double>(ac_x) / ac_d));

const auto result_acos_is_ok = (closeness < std::numeric_limits<double>::epsilon() * 64.0); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)

result_is_ok = (result_acos_is_ok && result_is_ok);
}

{
const math::softfloat::float64_t x = math::softfloat::float64_t(-67) / 100;
const auto d = static_cast<double>(x);

using std::acos;

const math::softfloat::float64_t ac_x = acos(x);
const double ac_d = acos(d);

const double closeness = std::fabs(1.0 - (static_cast<double>(ac_x) / ac_d));

const auto result_acos_is_ok = (closeness < std::numeric_limits<double>::epsilon() * 64.0); // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)

result_is_ok = (result_acos_is_ok && result_is_ok);
}

for(int i = 121; i < 124; ++i) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
{
const math::softfloat::float64_t x = math::softfloat::float64_t(i) / 100; // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)

const math::softfloat::float64_t ac_x = acos(x);

const auto result_acos_is_ok = isnan(ac_x);

result_is_ok = (result_acos_is_ok && result_is_ok);
}

{
std::mt19937 eng(static_cast<typename std::mt19937::result_type>(UINT8_C(42))); // NOLINT(cert-msc32-c,cert-msc51-cpp)

std::uniform_int_distribution<int> dist_one(1, 1);

for(int i = 0; i < 3; ++i) // NOLINT(cppcoreguidelines-avoid-magic-numbers,readability-magic-numbers)
{
const math::softfloat::float64_t x_one_pos = math::softfloat::float64_t(+1) * dist_one(eng);
const math::softfloat::float64_t x_one_neg = math::softfloat::float64_t(-1) * dist_one(eng);

using std::acos;

const math::softfloat::float64_t acos_one_pos = acos(x_one_pos);
const math::softfloat::float64_t acos_one_neg = acos(x_one_neg);

const auto result_acos_one_pos_neg_is_ok = ( (acos_one_pos == math::softfloat::float64_t::my_value_zero())
&& (acos_one_neg == math::softfloat::float64_t::my_value_pi()));

result_is_ok = (result_acos_one_pos_neg_is_ok && result_is_ok);
}
}

return result_is_ok;
}

auto test_floor(const std::uint32_t n) -> bool
{
bool result_is_ok = true;
Expand Down Expand Up @@ -876,6 +974,7 @@ auto test_soft_double() -> bool
std::cout << "testing cos____... "; const auto result_cos____is_ok = test_cos ( ); std::cout << std::boolalpha << result_cos____is_ok << std::endl; // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
std::cout << "testing tan____... "; const auto result_tan____is_ok = test_tan ( ); std::cout << std::boolalpha << result_tan____is_ok << std::endl; // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
std::cout << "testing asin___... "; const auto result_asin___is_ok = test_asin ( ); std::cout << std::boolalpha << result_asin___is_ok << std::endl; // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
std::cout << "testing acos___... "; const auto result_acos___is_ok = test_acos ( ); std::cout << std::boolalpha << result_acos___is_ok << std::endl; // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)

local::eng32.seed(::util::util_pseudorandom_time_point_seed::value<typename local::eng32_type::result_type>());
local::eng64.seed(::util::util_pseudorandom_time_point_seed::value<typename local::eng64_type::result_type>());
Expand Down Expand Up @@ -925,6 +1024,7 @@ auto test_soft_double() -> bool
&& result_cos____is_ok
&& result_tan____is_ok
&& result_asin___is_ok
&& result_acos___is_ok
&& result_floor__is_ok
&& result_ceil___is_ok
&& result_add____is_ok
Expand Down

0 comments on commit 4a8554c

Please sign in to comment.