1 /*************************************************************************** 2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * 3 * Copyright (c) QuantStack * 4 * * 5 * Distributed under the terms of the BSD 3-Clause License. * 6 * * 7 * The full license is in the file LICENSE, distributed with this software. * 8 ****************************************************************************/ 9 10 #include "xtl/xcomplex.hpp" 11 12 #include <complex> 13 14 #include "test_common_macros.hpp" 15 #include "xtl/xclosure.hpp" 16 17 namespace xtl 18 { 19 using namespace std::complex_literals; 20 21 using complex_type = xcomplex<double>; 22 using complex_ref_type = xcomplex<double&, double&>; 23 TEST(xcomplex,constructor)24 TEST(xcomplex, constructor) 25 { 26 complex_type c0; 27 EXPECT_APPROX_EQ(c0.real(), 0.); 28 EXPECT_APPROX_EQ(c0.imag(), 0.); 29 30 complex_type c1(2.); 31 EXPECT_APPROX_EQ(c1.real(), 2.); 32 EXPECT_APPROX_EQ(c1.imag(), 0.); 33 34 complex_type c2(2., 3.); 35 EXPECT_APPROX_EQ(c2.real(), 2.); 36 EXPECT_APPROX_EQ(c2.imag(), 3.); 37 38 complex_type c3(c2); 39 EXPECT_APPROX_EQ(c3.real(), c2.real()); 40 EXPECT_APPROX_EQ(c3.imag(), c2.imag()); 41 42 complex_type c4(std::move(c3)); 43 EXPECT_APPROX_EQ(c4.real(), c2.real()); 44 EXPECT_APPROX_EQ(c4.imag(), c2.imag()); 45 46 std::complex<double> sc(1., 2.); 47 complex_type c5(sc); 48 EXPECT_APPROX_EQ(c5.real(), sc.real()); 49 EXPECT_APPROX_EQ(c5.imag(), sc.imag()); 50 51 complex_type c6(std::move(sc)); 52 EXPECT_APPROX_EQ(c6.real(), c5.real()); 53 EXPECT_APPROX_EQ(c6.imag(), c5.imag()); 54 55 double re = 1.2, im = 4.5; 56 complex_ref_type c7(re, im); 57 EXPECT_APPROX_EQ(c7.real(), re); 58 EXPECT_APPROX_EQ(c7.imag(), im); 59 60 xcomplex<float> f(1.f, 2.f); 61 complex_type c8(f); 62 EXPECT_APPROX_EQ(c8.real(), 1.); 63 EXPECT_APPROX_EQ(c8.imag(), 2.); 64 } 65 TEST(xcomplex,assign)66 TEST(xcomplex, assign) 67 { 68 complex_type c0(1., 2.); 69 complex_type c1(4., 5.); 70 71 c0 = 3.; 72 EXPECT_APPROX_EQ(c0.real(), 3.); 73 EXPECT_APPROX_EQ(c0.imag(), 0.); 74 75 c0 = std::move(4.); 76 EXPECT_APPROX_EQ(c0.real(), 4.); 77 EXPECT_APPROX_EQ(c0.imag(), 0.); 78 79 c0 = c1; 80 EXPECT_APPROX_EQ(c0.real(), c1.real()); 81 EXPECT_APPROX_EQ(c0.imag(), c1.imag()); 82 83 c0 = complex_type(2., 3.); 84 EXPECT_APPROX_EQ(c0.real(), 2.); 85 EXPECT_APPROX_EQ(c0.imag(), 3.); 86 87 std::complex<double> c2(1.4, 5.2); 88 c0 = c2; 89 EXPECT_APPROX_EQ(c0.real(), c2.real()); 90 EXPECT_APPROX_EQ(c0.imag(), c2.imag()); 91 92 c0 = std::complex<double>(1.2, 2.5); 93 EXPECT_APPROX_EQ(c0.real(), 1.2); 94 EXPECT_APPROX_EQ(c0.imag(), 2.5); 95 } 96 TEST(xcomplex,conversion)97 TEST(xcomplex, conversion) 98 { 99 complex_type c(1., 2.); 100 std::complex<double> sc = c; 101 EXPECT_APPROX_EQ(c.real(), sc.real()); 102 EXPECT_APPROX_EQ(c.imag(), sc.imag()); 103 } 104 TEST(xcomplex,comparison)105 TEST(xcomplex, comparison) 106 { 107 using int_complex_type = xcomplex<int>; 108 109 int_complex_type vc0(1, 2); 110 int_complex_type vc1(2, 4); 111 112 EXPECT_TRUE(vc0 == vc0); 113 EXPECT_FALSE(vc0 == vc1); 114 115 EXPECT_FALSE(vc0 != vc0); 116 EXPECT_TRUE(vc0 != vc1); 117 } 118 TEST(xcomplex,computed_assign)119 TEST(xcomplex, computed_assign) 120 { 121 complex_type vc0(1., 2.); 122 complex_type vc1(2., 4.); 123 124 complex_type c0(vc0); 125 c0 += vc1; 126 EXPECT_APPROX_EQ(c0.real(), 3.); 127 EXPECT_APPROX_EQ(c0.imag(), 6.); 128 129 complex_type c1(vc0); 130 c1 -= vc1; 131 EXPECT_APPROX_EQ(c1.real(), -1.); 132 EXPECT_APPROX_EQ(c1.imag(), -2.); 133 134 complex_type c2(vc0); 135 c2 *= vc1; 136 EXPECT_APPROX_EQ(c2.real(), -6.); 137 EXPECT_APPROX_EQ(c2.imag(), 8.); 138 139 complex_type c3(vc0); 140 c3 /= vc1; 141 EXPECT_APPROX_EQ(c3.real(), 0.5); 142 EXPECT_APPROX_EQ(c3.imag(), 0.); 143 144 double v = 0.5; 145 146 complex_type c4(vc0); 147 c4 += v; 148 EXPECT_APPROX_EQ(c4.real(), 1.5); 149 EXPECT_APPROX_EQ(c4.imag(), 2.); 150 151 complex_type c5(vc0); 152 c5 -= v; 153 EXPECT_APPROX_EQ(c5.real(), 0.5); 154 EXPECT_APPROX_EQ(c5.imag(), 2.); 155 156 complex_type c6(vc0); 157 c6 *= v; 158 EXPECT_APPROX_EQ(c6.real(), 0.5); 159 EXPECT_APPROX_EQ(c6.imag(), 1.); 160 161 complex_type c7(vc0); 162 c7 /= v; 163 EXPECT_APPROX_EQ(c7.real(), 2.); 164 EXPECT_APPROX_EQ(c7.imag(), 4.); 165 166 xcomplex<double, double, true> sc(vc1); 167 xcomplex<double, double, true> c8(vc0); 168 c8 *= sc; 169 EXPECT_APPROX_EQ(c8.real(), -6.); 170 EXPECT_APPROX_EQ(c8.imag(), 8.); 171 172 xcomplex<double, double, true> c9(vc0); 173 c9 /= sc; 174 EXPECT_APPROX_EQ(c9.real(), 0.5); 175 EXPECT_APPROX_EQ(c9.imag(), 0.); 176 } 177 TEST(xcomplex,arithmetic)178 TEST(xcomplex, arithmetic) 179 { 180 complex_type vc0(1., 2.); 181 complex_type vc1(2., 4.); 182 183 complex_type c0 = vc0 + vc1; 184 EXPECT_APPROX_EQ(c0.real(), 3.); 185 EXPECT_APPROX_EQ(c0.imag(), 6.); 186 187 complex_type c1 = vc0 - vc1; 188 EXPECT_APPROX_EQ(c1.real(), -1.); 189 EXPECT_APPROX_EQ(c1.imag(), -2.); 190 191 complex_type c2 = vc0 * vc1; 192 EXPECT_APPROX_EQ(c2.real(), -6.); 193 EXPECT_APPROX_EQ(c2.imag(), 8.); 194 195 complex_type c3 = vc0 / vc1; 196 EXPECT_APPROX_EQ(c3.real(), 0.5); 197 EXPECT_APPROX_EQ(c3.imag(), 0.); 198 199 double v = 0.5; 200 201 complex_type c4 = vc0 + v; 202 EXPECT_APPROX_EQ(c4.real(), 1.5); 203 EXPECT_APPROX_EQ(c4.imag(), 2.); 204 205 complex_type c5 = vc0 - v; 206 EXPECT_APPROX_EQ(c5.real(), 0.5); 207 EXPECT_APPROX_EQ(c5.imag(), 2.); 208 209 complex_type c6 = vc0 * v; 210 EXPECT_APPROX_EQ(c6.real(), 0.5); 211 EXPECT_APPROX_EQ(c6.imag(), 1.); 212 213 complex_type c7 = vc0 / v; 214 EXPECT_APPROX_EQ(c7.real(), 2.); 215 EXPECT_APPROX_EQ(c7.imag(), 4.); 216 } 217 TEST(xcomplex,real_imag)218 TEST(xcomplex, real_imag) 219 { 220 complex_type c(1., 2.); 221 222 auto d1 = real(c); 223 EXPECT_APPROX_EQ(d1, c.real()); 224 225 auto d2 = real(std::move(c)); 226 EXPECT_APPROX_EQ(d2, c.real()); 227 228 auto d3 = imag(c); 229 EXPECT_APPROX_EQ(d3, c.imag()); 230 231 auto d4 = imag(std::move(c)); 232 EXPECT_APPROX_EQ(d4, c.imag()); 233 } 234 TEST(xcomplex,free_functions)235 TEST(xcomplex, free_functions) 236 { 237 complex_type c(1., 2.); 238 std::complex<double> sc(c); 239 240 EXPECT_APPROX_EQ(abs(c), std::abs(sc)); 241 EXPECT_APPROX_EQ(arg(c), std::arg(sc)); 242 EXPECT_APPROX_EQ(norm(c), std::norm(sc)); 243 EXPECT_COMPLEX_APPROX_EQ(conj(c), complex_type(std::conj(sc))); 244 EXPECT_COMPLEX_APPROX_EQ(proj(c), complex_type(std::proj(sc))); 245 } 246 TEST(xcomplex,exponential)247 TEST(xcomplex, exponential) 248 { 249 complex_type c(1., 2.); 250 std::complex<double> sc(c); 251 EXPECT_COMPLEX_APPROX_EQ(exp(c), complex_type(std::exp(sc))); 252 EXPECT_COMPLEX_APPROX_EQ(log(c), complex_type(std::log(sc))); 253 EXPECT_COMPLEX_APPROX_EQ(log10(c), complex_type(std::log10(sc))); 254 } 255 TEST(xcomplex,power)256 TEST(xcomplex, power) 257 { 258 complex_type c(1., 2.); 259 std::complex<double> sc(c); 260 double d = 1.5; 261 // this test is failing because comparing floating points is a bad idea 262 //EXPECT_EQ(pow(c, c), complex_type(std::pow(sc, sc))); 263 EXPECT_COMPLEX_APPROX_EQ(pow(c, d), complex_type(std::pow(sc, d))); 264 EXPECT_COMPLEX_APPROX_EQ(pow(d, c), complex_type(std::pow(d, sc))); 265 EXPECT_COMPLEX_APPROX_EQ(sqrt(c), complex_type(std::sqrt(sc))); 266 } 267 TEST(xcomplex,trigonometric)268 TEST(xcomplex, trigonometric) 269 { 270 complex_type c(1., 2.); 271 std::complex<double> sc(c); 272 EXPECT_COMPLEX_APPROX_EQ(sin(c), complex_type(std::sin(sc))); 273 EXPECT_COMPLEX_APPROX_EQ(cos(c), complex_type(std::cos(sc))); 274 EXPECT_COMPLEX_APPROX_EQ(tan(c), complex_type(std::tan(sc))); 275 EXPECT_COMPLEX_APPROX_EQ(asin(c), complex_type(std::asin(sc))); 276 EXPECT_COMPLEX_APPROX_EQ(acos(c), complex_type(std::acos(sc))); 277 EXPECT_COMPLEX_APPROX_EQ(atan(c), complex_type(std::atan(sc))); 278 } 279 TEST(xcomplex,hyperbolic)280 TEST(xcomplex, hyperbolic) 281 { 282 complex_type c(1., 2.); 283 std::complex<double> sc(c); 284 EXPECT_COMPLEX_APPROX_EQ(sinh(c), complex_type(std::sinh(sc))); 285 EXPECT_COMPLEX_APPROX_EQ(cosh(c), complex_type(std::cosh(sc))); 286 EXPECT_COMPLEX_APPROX_EQ(tanh(c), complex_type(std::tanh(sc))); 287 EXPECT_COMPLEX_APPROX_EQ(asinh(c), complex_type(std::asinh(sc))); 288 EXPECT_COMPLEX_APPROX_EQ(acosh(c), complex_type(std::acosh(sc))); 289 EXPECT_COMPLEX_APPROX_EQ(atanh(c), complex_type(std::atanh(sc))); 290 } 291 TEST(xcomplex,forward_offset)292 TEST(xcomplex, forward_offset) 293 { 294 // Test that lvalues can be modified 295 std::complex<double> clv; 296 forward_real(clv) = 3.0; 297 EXPECT_EQ(std::real(clv), 3.0); 298 299 forward_imag(clv) = 1.0; 300 EXPECT_EQ(std::imag(clv), 1.0); 301 302 double rlv = 2.0; 303 forward_real(rlv) = 1.0; 304 EXPECT_EQ(forward_imag(rlv), 0.0); 305 EXPECT_EQ(forward_real(rlv), 1.0); 306 } 307 TEST(xcomplex,scalar)308 TEST(xcomplex, scalar) 309 { 310 double d = 1.0; 311 ASSERT_EQ(1.0, real(d)); 312 ASSERT_EQ(0.0, imag(d)); 313 real(d) = 2.0; 314 ASSERT_EQ(2.0, d); 315 } 316 TEST(xcomplex,closure)317 TEST(xcomplex, closure) 318 { 319 double x = 5.0; 320 auto x_closure = closure(x); 321 std::complex<double> b(0, 5), c; 322 EXPECT_COMPLEX_APPROX_EQ(b + x_closure, b + 5.0); 323 EXPECT_COMPLEX_APPROX_EQ(x_closure + b, 5.0 + b); 324 EXPECT_COMPLEX_APPROX_EQ(b - x_closure, b - 5.0); 325 EXPECT_COMPLEX_APPROX_EQ(x_closure - b, 5.0 - b); 326 EXPECT_COMPLEX_APPROX_EQ(b * x_closure, b * 5.0); 327 EXPECT_COMPLEX_APPROX_EQ(x_closure * b, 5.0 * b); 328 EXPECT_COMPLEX_APPROX_EQ(b / x_closure, b / 5.0); 329 EXPECT_COMPLEX_APPROX_EQ(x_closure / b, 5.0 / b); 330 } 331 } 332 333