1 #ifndef STAN_MATH_PRIM_SCAL_FUN_COPYSIGN_HPP
2 #define STAN_MATH_PRIM_SCAL_FUN_COPYSIGN_HPP
3 
4 #include <stan/math/prim/meta.hpp>
5 #include <stan/math/prim/fun/value_of_rec.hpp>
6 #include <cmath>
7 #include <complex>
8 
9 namespace stan {
10 namespace math {
11 
12 /**
13  * Return the negation of the first argument if the first and second
14  * argument have different signs, otherwise return a copy of the first
15  * argument.  For the sake of this function, zero is considered
16  * positive.  This function uses negation rather than literally copying
17  * signs to preserve derivatives.
18  *
19  * Overload of `std::copysign` from `cmath` for argument-dependent
20  * lookup.
21  *
22  * @tparam T type of first argument
23  * @tparam U type of second argument
24  * @param[in] x first complex argument
25  * @param[in] y second complex argument
26  * @return copy of the first argument, negated if necessary to match
27  * the sign of the second argument
28  */
29 template <typename T, typename U>
copysign(const T & x,const U & y)30 inline T copysign(const T& x, const U& y) {
31   return (std::signbit(value_of_rec(x)) != std::signbit(value_of_rec(y))) ? -x
32                                                                           : x;
33 }
34 
35 /**
36  * Return the negation of the first argument if the first and second
37  * arguments have different signs and the first argument is not zero,
38  * otherwise return a copy of the first argument.
39  *
40  * @tparam T type of first argument
41  * @tparam U type of second argument
42  * @param[in] x first complex argument
43  * @param[in] y second complex argument
44  * @return copy of the first argument, negated if necessary to match
45  * the sign of the second argument
46  * @see copysign
47  */
48 template <typename T, typename U>
copysign_non_zero(const T & x,const U & y)49 inline T copysign_non_zero(const T& x, const U& y) {
50   return x != 0 ? stan::math::copysign(x, y) : x;
51 }
52 
53 /**
54  * Return the complex number composed of the real and complex parts
55  * with signs copied from the real and complex parts of the first
56  * arguments to the real and complex parts of the second.
57  *
58  * This is an overload of the standard libary `copysign` for complex
59  * numbers that will be used with argument-dependent lookup.  Rather
60  * than using the standard library `copysign`, it uses
61  * `copysign_non_zero`, which does not change sign if the reference
62  * value is zero (`-0.0` or `0.0`).
63  *
64  * @tparam T value type of first argument
65  * @tparam U value type of second argument
66  * @param[in] x first complex argument
67  * @param[in] y second complex argument
68  * @return copy of second argument, with components negated if
69  * necessary to match sign of first argument
70  */
71 template <typename T, typename U>
copysign(const std::complex<T> & x,const std::complex<U> & y)72 inline std::complex<T> copysign(const std::complex<T>& x,
73                                 const std::complex<U>& y) {
74   return {copysign_non_zero(x.real(), y.real()),
75           copysign_non_zero(x.imag(), y.imag())};
76 }
77 
78 }  // namespace math
79 }  // namespace stan
80 
81 #endif
82