Skip to content

Commit

Permalink
Closes gh-1279
Browse files Browse the repository at this point in the history
Provide cabs private method implementating abs for complex types, paying
attention to array-API mandated special values.

To work-around gh-1279, use std::hypot to compute value for finite inputs.
Compile with -DUSE_STD_ABS_FOR_COMPLEX_TYPES to use std::abs(z) instead of
std::hypot(std::real(z), std::imag(z)).
  • Loading branch information
oleksandr-pavlyk committed Aug 15, 2023
1 parent 2381a87 commit f814be1
Showing 1 changed file with 41 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <complex>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <type_traits>

#include "kernels/elementwise_functions/common.hpp"
Expand All @@ -37,8 +38,6 @@
#include "utils/type_utils.hpp"
#include <pybind11/pybind11.h>

#include <iostream>

namespace dpctl
{
namespace tensor
Expand Down Expand Up @@ -76,21 +75,56 @@ template <typename argT, typename resT> struct AbsFunctor
if constexpr (is_complex<argT>::value) {
return cabs(x);
}
else if constexpr (std::is_same_v<argT, sycl::half> ||
std::is_floating_point_v<argT>)
{
return (std::signbit(x) ? -x : x);
}
else {
return std::abs(x);
}
}
}

private:
template <typename realT> realT cabs(std::complex<realT> const &z)
template <typename realT> realT cabs(std::complex<realT> const &z) const
{
#ifdef _WINDOWS
// work-around for gh-1279
return std::hypot(std::real(z), std::imag(z));
// Special values for cabs( x + y * 1j):
// * If x is either +infinity or -infinity and y is any value
// (including NaN), the result is +infinity.
// * If x is any value (including NaN) and y is either +infinity or
// -infinity, the result is +infinity.
// * If x is either +0 or -0, the result is equal to abs(y).
// * If y is either +0 or -0, the result is equal to abs(x).
// * If x is NaN and y is a finite number, the result is NaN.
// * If x is a finite number and y is NaN, the result is NaN.
// * If x is NaN and y is NaN, the result is NaN.

const realT x = std::real(z);
const realT y = std::imag(z);

constexpr realT q_nan = std::numeric_limits<realT>::quiet_NaN();
constexpr realT p_inf = std::numeric_limits<realT>::infinity();

if (std::isinf(x)) {
return p_inf;
}
else if (std::isinf(y)) {
return p_inf;
}
else if (std::isnan(x)) {
return q_nan;
}
else if (std::isnan(y)) {
return q_nan;
}
else {
#ifdef USE_STD_ABS_FOR_COMPLEX_TYPES
return std::abs(z);
#else
return std::abs(z);
return std::hypot(std::real(z), std::imag(z));
#endif
}
}
};

Expand Down

0 comments on commit f814be1

Please sign in to comment.