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