/* * Copyright 2008-2021 NVIDIA Corporation * Copyright 2013 Filipe RNC Maia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include THRUST_NAMESPACE_BEGIN /* --- Binary Arithmetic Operators --- */ template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator+(const complex& x, const complex& y) { using T = ::cuda::std::__common_type_t; return complex(x.real() + y.real(), x.imag() + y.imag()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator+(const complex& x, const T1& y) { using T = ::cuda::std::__common_type_t; return complex(x.real() + y, x.imag()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator+(const T0& x, const complex& y) { using T = ::cuda::std::__common_type_t; return complex(x + y.real(), y.imag()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator-(const complex& x, const complex& y) { using T = ::cuda::std::__common_type_t; return complex(x.real() - y.real(), x.imag() - y.imag()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator-(const complex& x, const T1& y) { using T = ::cuda::std::__common_type_t; return complex(x.real() - y, x.imag()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator-(const T0& x, const complex& y) { using T = ::cuda::std::__common_type_t; return complex(x - y.real(), -y.imag()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator*(const complex& x, const complex& y) { using T = ::cuda::std::__common_type_t; return complex(x.real() * y.real() - x.imag() * y.imag(), x.real() * y.imag() + x.imag() * y.real()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator*(const complex& x, const T1& y) { using T = ::cuda::std::__common_type_t; return complex(x.real() * y, x.imag() * y); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator*(const T0& x, const complex& y) { using T = ::cuda::std::__common_type_t; return complex(x * y.real(), x * y.imag()); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator/(const complex& x, const complex& y) { using T = ::cuda::std::__common_type_t; // Find `abs` by ADL. using std::abs; T s = abs(y.real()) + abs(y.imag()); T oos = T(1.0) / s; T ars = x.real() * oos; T ais = x.imag() * oos; T brs = y.real() * oos; T bis = y.imag() * oos; s = (brs * brs) + (bis * bis); oos = T(1.0) / s; complex quot(((ars * brs) + (ais * bis)) * oos, ((ais * brs) - (ars * bis)) * oos); return quot; } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator/(const complex& x, const T1& y) { using T = ::cuda::std::__common_type_t; return complex(x.real() / y, x.imag() / y); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> operator/(const T0& x, const complex& y) { using T = ::cuda::std::__common_type_t; return complex(x) / y; } /* --- Unary Arithmetic Operators --- */ template _CCCL_HOST_DEVICE complex operator+(const complex& y) { return y; } template _CCCL_HOST_DEVICE complex operator-(const complex& y) { return y * -T(1); } /* --- Other Basic Arithmetic Functions --- */ // As std::hypot is only C++11 we have to use the C interface template _CCCL_HOST_DEVICE T abs(const complex& z) { return hypot(z.real(), z.imag()); } // XXX Why are we specializing here? namespace detail { namespace complex { _CCCL_HOST_DEVICE inline float abs(const thrust::complex& z) { return hypotf(z.real(), z.imag()); } _CCCL_HOST_DEVICE inline double abs(const thrust::complex& z) { return hypot(z.real(), z.imag()); } } // end namespace complex } // end namespace detail template <> _CCCL_HOST_DEVICE inline float abs(const complex& z) { return detail::complex::abs(z); } template <> _CCCL_HOST_DEVICE inline double abs(const complex& z) { return detail::complex::abs(z); } template _CCCL_HOST_DEVICE T arg(const complex& z) { // Find `atan2` by ADL. using std::atan2; return atan2(z.imag(), z.real()); } template _CCCL_HOST_DEVICE complex conj(const complex& z) { return complex(z.real(), -z.imag()); } template _CCCL_HOST_DEVICE T norm(const complex& z) { return z.real() * z.real() + z.imag() * z.imag(); } // XXX Why specialize these, we could just rely on ADL. template <> _CCCL_HOST_DEVICE inline float norm(const complex& z) { // Find `abs` and `sqrt` by ADL. using std::abs; using std::sqrt; if (abs(z.real()) < sqrt(FLT_MIN) && abs(z.imag()) < sqrt(FLT_MIN)) { float a = z.real() * 4.0f; float b = z.imag() * 4.0f; return (a * a + b * b) / 16.0f; } return z.real() * z.real() + z.imag() * z.imag(); } template <> _CCCL_HOST_DEVICE inline double norm(const complex& z) { // Find `abs` and `sqrt` by ADL. using std::abs; using std::sqrt; if (abs(z.real()) < sqrt(DBL_MIN) && abs(z.imag()) < sqrt(DBL_MIN)) { double a = z.real() * 4.0; double b = z.imag() * 4.0; return (a * a + b * b) / 16.0; } return z.real() * z.real() + z.imag() * z.imag(); } template _CCCL_HOST_DEVICE complex<::cuda::std::__common_type_t> polar(const T0& m, const T1& theta) { using T = ::cuda::std::__common_type_t; // Find `cos` and `sin` by ADL. using std::cos; using std::sin; return complex(m * cos(theta), m * sin(theta)); } THRUST_NAMESPACE_END