| 1 | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
| 2 | |
| 3 | /* |
| 4 | Copyright (C) 2003 RiskMap srl |
| 5 | Copyright (C) 2015 Peter Caspers |
| 6 | |
| 7 | This file is part of QuantLib, a free-software/open-source library |
| 8 | for financial quantitative analysts and developers - http://quantlib.org/ |
| 9 | |
| 10 | QuantLib is free software: you can redistribute it and/or modify it |
| 11 | under the terms of the QuantLib license. You should have received a |
| 12 | copy of the license along with this program; if not, please email |
| 13 | <quantlib-dev@lists.sf.net>. The license is also available online at |
| 14 | <http://quantlib.org/license.shtml>. |
| 15 | |
| 16 | This program is distributed in the hope that it will be useful, but WITHOUT |
| 17 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 18 | FOR A PARTICULAR PURPOSE. See the license for more details. |
| 19 | */ |
| 20 | |
| 21 | #include "integrals.hpp" |
| 22 | #include "utilities.hpp" |
| 23 | #include <ql/math/integrals/exponentialintegrals.hpp> |
| 24 | #include <ql/math/integrals/filonintegral.hpp> |
| 25 | #include <ql/math/integrals/segmentintegral.hpp> |
| 26 | #include <ql/math/integrals/simpsonintegral.hpp> |
| 27 | #include <ql/math/integrals/trapezoidintegral.hpp> |
| 28 | #include <ql/math/integrals/kronrodintegral.hpp> |
| 29 | #include <ql/math/integrals/gausslobattointegral.hpp> |
| 30 | #include <ql/math/integrals/discreteintegrals.hpp> |
| 31 | #include <ql/math/integrals/tanhsinhintegral.hpp> |
| 32 | #include <ql/math/integrals/gaussianquadratures.hpp> |
| 33 | #include <ql/math/interpolations/bilinearinterpolation.hpp> |
| 34 | #include <ql/math/distributions/normaldistribution.hpp> |
| 35 | #include <ql/termstructures/volatility/abcd.hpp> |
| 36 | #include <ql/math/integrals/twodimensionalintegral.hpp> |
| 37 | #include <ql/experimental/math/piecewisefunction.hpp> |
| 38 | #include <ql/experimental/math/piecewiseintegral.hpp> |
| 39 | |
| 40 | using namespace QuantLib; |
| 41 | using boost::unit_test_framework::test_suite; |
| 42 | |
| 43 | namespace integrals_test { |
| 44 | |
| 45 | Real tolerance = 1.0e-6; |
| 46 | |
| 47 | template <class T> |
| 48 | void testSingle(const T& I, const std::string& tag, |
| 49 | const ext::function<Real (Real)>& f, |
| 50 | Real xMin, Real xMax, Real expected) { |
| 51 | Real calculated = I(f,xMin,xMax); |
| 52 | if (std::fabs(x: calculated-expected) > integrals_test::tolerance) { |
| 53 | BOOST_FAIL(std::setprecision(10) |
| 54 | << "integrating " << tag |
| 55 | << " calculated: " << calculated |
| 56 | << " expected: " << expected); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | template <class T> |
| 61 | void testSeveral(const T& I) { |
| 62 | testSingle(I, "f(x) = 0" , [](Real x) -> Real { return 0.0; }, 0.0, 1.0, 0.0); |
| 63 | testSingle(I, "f(x) = 1" , [](Real x) -> Real { return 1.0; }, 0.0, 1.0, 1.0); |
| 64 | testSingle(I, "f(x) = x" , [](Real x) -> Real { return x; }, 0.0, 1.0, 0.5); |
| 65 | testSingle(I, "f(x) = x^2" , |
| 66 | [](Real x) -> Real { return x * x; }, 0.0, 1.0, 1.0/3.0); |
| 67 | testSingle(I, "f(x) = sin(x)" , |
| 68 | [](Real x) -> Real { return std::sin(x: x); }, 0.0, M_PI, 2.0); |
| 69 | testSingle(I, "f(x) = cos(x)" , |
| 70 | [](Real x) -> Real { return std::cos(x: x); }, 0.0, M_PI, 0.0); |
| 71 | |
| 72 | testSingle(I, "f(x) = Gaussian(x)" , |
| 73 | NormalDistribution(), -10.0, 10.0, 1.0); |
| 74 | testSingle(I, "f(x) = Abcd2(x)" , |
| 75 | AbcdSquared(0.07, 0.07, 0.5, 0.1, 8.0, 10.0), 5.0, 6.0, |
| 76 | AbcdFunction(0.07, 0.07, 0.5, 0.1).covariance(t1: 5.0, t2: 6.0, T: 8.0, S: 10.0)); |
| 77 | } |
| 78 | |
| 79 | template <class T> |
| 80 | void testDegeneratedDomain(const T& I) { |
| 81 | testSingle(I, "f(x) = 0 over [1, 1 + macheps]" , [](Real x) -> Real { return 0.0; }, 1.0, |
| 82 | 1.0 + QL_EPSILON, 0.0); |
| 83 | } |
| 84 | |
| 85 | } |
| 86 | |
| 87 | |
| 88 | void IntegralTest::testSegment() { |
| 89 | BOOST_TEST_MESSAGE("Testing segment integration..." ); |
| 90 | |
| 91 | using namespace integrals_test; |
| 92 | |
| 93 | testSeveral(I: SegmentIntegral(10000)); |
| 94 | testDegeneratedDomain(I: SegmentIntegral(10000)); |
| 95 | } |
| 96 | |
| 97 | void IntegralTest::testTrapezoid() { |
| 98 | BOOST_TEST_MESSAGE("Testing trapezoid integration..." ); |
| 99 | |
| 100 | using namespace integrals_test; |
| 101 | |
| 102 | testSeveral(I: TrapezoidIntegral<Default>(integrals_test::tolerance, 10000)); |
| 103 | testDegeneratedDomain(I: TrapezoidIntegral<Default>(integrals_test::tolerance, 10000)); |
| 104 | } |
| 105 | |
| 106 | void IntegralTest::testMidPointTrapezoid() { |
| 107 | BOOST_TEST_MESSAGE("Testing mid-point trapezoid integration..." ); |
| 108 | |
| 109 | using namespace integrals_test; |
| 110 | |
| 111 | testSeveral(I: TrapezoidIntegral<MidPoint>(integrals_test::tolerance, 10000)); |
| 112 | testDegeneratedDomain(I: TrapezoidIntegral<MidPoint>(integrals_test::tolerance, 10000)); |
| 113 | } |
| 114 | |
| 115 | void IntegralTest::testSimpson() { |
| 116 | BOOST_TEST_MESSAGE("Testing Simpson integration..." ); |
| 117 | |
| 118 | using namespace integrals_test; |
| 119 | |
| 120 | testSeveral(I: SimpsonIntegral(integrals_test::tolerance, 10000)); |
| 121 | testDegeneratedDomain(I: SimpsonIntegral(integrals_test::tolerance, 10000)); |
| 122 | } |
| 123 | |
| 124 | void IntegralTest::testGaussKronrodAdaptive() { |
| 125 | BOOST_TEST_MESSAGE("Testing adaptive Gauss-Kronrod integration..." ); |
| 126 | |
| 127 | using namespace integrals_test; |
| 128 | |
| 129 | Size maxEvaluations = 1000; |
| 130 | testSeveral(I: GaussKronrodAdaptive(integrals_test::tolerance, maxEvaluations)); |
| 131 | testDegeneratedDomain(I: GaussKronrodAdaptive(integrals_test::tolerance, maxEvaluations)); |
| 132 | } |
| 133 | |
| 134 | void IntegralTest::testGaussLobatto() { |
| 135 | BOOST_TEST_MESSAGE("Testing adaptive Gauss-Lobatto integration..." ); |
| 136 | |
| 137 | using namespace integrals_test; |
| 138 | |
| 139 | Size maxEvaluations = 1000; |
| 140 | testSeveral(I: GaussLobattoIntegral(maxEvaluations, integrals_test::tolerance)); |
| 141 | // on degenerated domain [1,1+macheps] an exception is thrown |
| 142 | // which is also ok, but not tested here |
| 143 | } |
| 144 | |
| 145 | void IntegralTest::testTanhSinh() { |
| 146 | BOOST_TEST_MESSAGE("Testing tanh-sinh integration..." ); |
| 147 | |
| 148 | using namespace integrals_test; |
| 149 | testSeveral(I: TanhSinhIntegral()); |
| 150 | } |
| 151 | |
| 152 | void IntegralTest::testGaussLegendreIntegrator() { |
| 153 | BOOST_TEST_MESSAGE("Testing Gauss-Legendre integrator..." ); |
| 154 | |
| 155 | using namespace integrals_test; |
| 156 | |
| 157 | const GaussLegendreIntegrator integrator(64); |
| 158 | testSeveral(I: integrator); |
| 159 | testDegeneratedDomain(I: integrator); |
| 160 | } |
| 161 | |
| 162 | void IntegralTest::testGaussChebyshevIntegrator() { |
| 163 | BOOST_TEST_MESSAGE("Testing Gauss-Chebyshev integrator..." ); |
| 164 | |
| 165 | using namespace integrals_test; |
| 166 | |
| 167 | const GaussChebyshevIntegrator integrator(64); |
| 168 | testSingle(I: integrator, tag: "f(x) = Gaussian(x)" , |
| 169 | f: NormalDistribution(), xMin: -10.0, xMax: 10.0, expected: 1.0); |
| 170 | testDegeneratedDomain(I: integrator); |
| 171 | } |
| 172 | |
| 173 | void IntegralTest::testGaussChebyshev2ndIntegrator() { |
| 174 | BOOST_TEST_MESSAGE("Testing Gauss-Chebyshev 2nd integrator..." ); |
| 175 | |
| 176 | using namespace integrals_test; |
| 177 | |
| 178 | const GaussChebyshev2ndIntegrator integrator(64); |
| 179 | testSingle(I: integrator, tag: "f(x) = Gaussian(x)" , |
| 180 | f: NormalDistribution(), xMin: -10.0, xMax: 10.0, expected: 1.0); |
| 181 | testDegeneratedDomain(I: integrator); |
| 182 | } |
| 183 | |
| 184 | |
| 185 | |
| 186 | void IntegralTest::testGaussKronrodNonAdaptive() { |
| 187 | BOOST_TEST_MESSAGE("Testing non-adaptive Gauss-Kronrod integration..." ); |
| 188 | |
| 189 | using namespace integrals_test; |
| 190 | |
| 191 | Real precision = integrals_test::tolerance; |
| 192 | Size maxEvaluations = 100; |
| 193 | Real relativeAccuracy = integrals_test::tolerance; |
| 194 | GaussKronrodNonAdaptive gaussKronrodNonAdaptive(precision, maxEvaluations, |
| 195 | relativeAccuracy); |
| 196 | testSeveral(I: gaussKronrodNonAdaptive); |
| 197 | testDegeneratedDomain(I: gaussKronrodNonAdaptive); |
| 198 | } |
| 199 | |
| 200 | void IntegralTest::testTwoDimensionalIntegration() { |
| 201 | BOOST_TEST_MESSAGE("Testing two dimensional adaptive " |
| 202 | "Gauss-Lobatto integration..." ); |
| 203 | |
| 204 | using namespace integrals_test; |
| 205 | |
| 206 | const Size maxEvaluations = 1000; |
| 207 | const Real calculated = TwoDimensionalIntegral( |
| 208 | ext::shared_ptr<Integrator>( |
| 209 | new TrapezoidIntegral<Default>(integrals_test::tolerance, maxEvaluations)), |
| 210 | ext::shared_ptr<Integrator>( |
| 211 | new TrapezoidIntegral<Default>(integrals_test::tolerance, maxEvaluations)))( |
| 212 | std::multiplies<>(), |
| 213 | std::make_pair(x: 0.0, y: 0.0), std::make_pair(x: 1.0, y: 2.0)); |
| 214 | |
| 215 | const Real expected = 1.0; |
| 216 | if (std::fabs(x: calculated-expected) > integrals_test::tolerance) { |
| 217 | BOOST_FAIL(std::setprecision(10) |
| 218 | << "two dimensional integration: " |
| 219 | << "\n calculated: " << calculated |
| 220 | << "\n expected: " << expected); |
| 221 | } |
| 222 | } |
| 223 | |
| 224 | namespace integrals_test { |
| 225 | |
| 226 | class sineF { |
| 227 | public: |
| 228 | Real operator()(Real x) const { |
| 229 | return std::exp(x: -0.5*(x - M_PI_2/100)); |
| 230 | } |
| 231 | }; |
| 232 | |
| 233 | class cosineF { |
| 234 | public: |
| 235 | Real operator()(Real x) const { |
| 236 | return std::exp(x: -0.5*x); |
| 237 | } |
| 238 | }; |
| 239 | |
| 240 | } |
| 241 | |
| 242 | void IntegralTest::testFolinIntegration() { |
| 243 | BOOST_TEST_MESSAGE("Testing Folin's integral formulae..." ); |
| 244 | |
| 245 | using namespace integrals_test; |
| 246 | |
| 247 | // Examples taken from |
| 248 | // http://www.tat.physik.uni-tuebingen.de/~kokkotas/Teaching/Num_Methods_files/Comp_Phys5.pdf |
| 249 | const Size nr[] = { 4, 8, 16, 128, 256, 1024, 2048 }; |
| 250 | const Real expected[] = { 4.55229440e-5,4.72338540e-5, 4.72338540e-5, |
| 251 | 4.78308678e-5,4.78404787e-5, 4.78381120e-5, |
| 252 | 4.78381084e-5}; |
| 253 | |
| 254 | const Real t = 100; |
| 255 | const Real o = M_PI_2/t; |
| 256 | |
| 257 | const Real tol = 1e-12; |
| 258 | |
| 259 | for (Size i=0; i < LENGTH(nr); ++i) { |
| 260 | const Size n = nr[i]; |
| 261 | const Real calculatedCosine |
| 262 | = FilonIntegral(FilonIntegral::Cosine, t, n)(cosineF(),0,2*M_PI); |
| 263 | const Real calculatedSine |
| 264 | = FilonIntegral(FilonIntegral::Sine, t, n) |
| 265 | (sineF(), o,2*M_PI + o); |
| 266 | |
| 267 | if (std::fabs(x: calculatedCosine-expected[i]) > tol) { |
| 268 | BOOST_FAIL(std::setprecision(10) |
| 269 | << "Filon Cosine integration failed: " |
| 270 | << "\n calculated: " << calculatedCosine |
| 271 | << "\n expected: " << expected[i]); |
| 272 | } |
| 273 | if (std::fabs(x: calculatedSine-expected[i]) > tol) { |
| 274 | BOOST_FAIL(std::setprecision(10) |
| 275 | << "Filon Sine integration failed: " |
| 276 | << "\n calculated: " << calculatedCosine |
| 277 | << "\n expected: " << expected[i]); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | namespace integrals_test { |
| 283 | |
| 284 | Real f1(Real x) { |
| 285 | return 1.2*x*x+3.2*x+3.1; |
| 286 | } |
| 287 | |
| 288 | Real f2(Real x) { |
| 289 | return 4.3*(x-2.34)*(x-2.34)-6.2*(x-2.34) + f1(x: 2.34); |
| 290 | } |
| 291 | |
| 292 | } |
| 293 | |
| 294 | void IntegralTest::testDiscreteIntegrals() { |
| 295 | BOOST_TEST_MESSAGE("Testing discrete integral formulae..." ); |
| 296 | |
| 297 | using namespace integrals_test; |
| 298 | |
| 299 | Array x(6), f(6); |
| 300 | x[0] = 1.0; x[1] = 2.02; x[2] = 2.34; x[3] = 3.3; x[4] = 4.2; x[5] = 4.6; |
| 301 | |
| 302 | std::transform(first: x.begin(), last: x.begin()+3, result: f.begin(), unary_op: f1); |
| 303 | std::transform(first: x.begin()+3, last: x.end(), result: f.begin()+3, unary_op: f2); |
| 304 | |
| 305 | const Real expectedSimpson = |
| 306 | 16.0401216 + 30.4137528 + 0.2*f2(x: 4.2) + 0.2*f2(x: 4.6); |
| 307 | const Real expectedTrapezoid = |
| 308 | 0.5*(f1(x: 1.0) + f1(x: 2.02))*1.02 |
| 309 | + 0.5*(f1(x: 2.02) + f1(x: 2.34))*0.32 |
| 310 | + 0.5*(f2(x: 2.34) + f2(x: 3.3) )*0.96 |
| 311 | + 0.5*(f2(x: 3.3) + f2(x: 4.2) )*0.9 |
| 312 | + 0.5*(f2(x: 4.2) + f2(x: 4.6) )*0.4; |
| 313 | |
| 314 | const Real calculatedSimpson = DiscreteSimpsonIntegral()(x, f); |
| 315 | const Real calculatedTrapezoid = DiscreteTrapezoidIntegral()(x, f); |
| 316 | |
| 317 | const Real tol = 1e-12; |
| 318 | if (std::fabs(x: calculatedSimpson-expectedSimpson) > tol) { |
| 319 | BOOST_FAIL(std::setprecision(16) |
| 320 | << "discrete Simpson integration failed: " |
| 321 | << "\n calculated: " << calculatedSimpson |
| 322 | << "\n expected: " << expectedSimpson); |
| 323 | } |
| 324 | |
| 325 | if (std::fabs(x: calculatedTrapezoid-expectedTrapezoid) > tol) { |
| 326 | BOOST_FAIL(std::setprecision(16) |
| 327 | << "discrete Trapezoid integration failed: " |
| 328 | << "\n calculated: " << calculatedTrapezoid |
| 329 | << "\n expected: " << expectedTrapezoid); |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | void IntegralTest::testDiscreteIntegrator() { |
| 334 | BOOST_TEST_MESSAGE("Testing discrete integrator formulae..." ); |
| 335 | |
| 336 | using namespace integrals_test; |
| 337 | |
| 338 | testSeveral(I: DiscreteSimpsonIntegrator(300)); |
| 339 | testSeveral(I: DiscreteTrapezoidIntegrator(3000)); |
| 340 | } |
| 341 | |
| 342 | namespace integrals_test{ |
| 343 | |
| 344 | std::vector<Real> x, y; |
| 345 | |
| 346 | Real pw_fct(const Real t) { return QL_PIECEWISE_FUNCTION(x, y, t); } |
| 347 | |
| 348 | void pw_check(const Integrator &in, const Real a, const Real b, |
| 349 | const Real expected) { |
| 350 | Real calculated = in(pw_fct, a, b); |
| 351 | if (!close(x: calculated, y: expected)) |
| 352 | BOOST_FAIL(std::setprecision(16) |
| 353 | << "piecewise integration over [" << a << "," << b |
| 354 | << "] failed: " |
| 355 | << "\n calculated: " << calculated |
| 356 | << "\n expected: " << expected |
| 357 | << "\n difference: " << (calculated - expected)); |
| 358 | } |
| 359 | } // empty namespace |
| 360 | |
| 361 | void IntegralTest::testPiecewiseIntegral() { |
| 362 | BOOST_TEST_MESSAGE("Testing piecewise integral..." ); |
| 363 | |
| 364 | using namespace integrals_test; |
| 365 | |
| 366 | x = { 1.0, 2.0, 3.0, 4.0, 5.0 }; |
| 367 | y = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }; |
| 368 | ext::shared_ptr<Integrator> segment = |
| 369 | ext::make_shared<SegmentIntegral>(args: 1); |
| 370 | ext::shared_ptr<Integrator> piecewise = |
| 371 | ext::make_shared<PiecewiseIntegral>(args&: segment, args&: x); |
| 372 | pw_check(in: *piecewise, a: -1.0, b: 0.0, expected: 1.0); |
| 373 | pw_check(in: *piecewise, a: 0.0, b: 1.0, expected: 1.0); |
| 374 | pw_check(in: *piecewise, a: 0.0, b: 1.5, expected: 2.0); |
| 375 | pw_check(in: *piecewise, a: 0.0, b: 2.0, expected: 3.0); |
| 376 | pw_check(in: *piecewise, a: 0.0, b: 2.5, expected: 4.5); |
| 377 | pw_check(in: *piecewise, a: 0.0, b: 3.0, expected: 6.0); |
| 378 | pw_check(in: *piecewise, a: 0.0, b: 4.0, expected: 10.0); |
| 379 | pw_check(in: *piecewise, a: 0.0, b: 5.0, expected: 15.0); |
| 380 | pw_check(in: *piecewise, a: 0.0, b: 6.0, expected: 21.0); |
| 381 | pw_check(in: *piecewise, a: 0.0, b: 7.0, expected: 27.0); |
| 382 | pw_check(in: *piecewise, a: 3.5, b: 4.5, expected: 4.5); |
| 383 | pw_check(in: *piecewise, a: 5.0, b: 10.0, expected: 30.0); |
| 384 | pw_check(in: *piecewise, a: 9.0, b: 10.0, expected: 6.0); |
| 385 | } |
| 386 | |
| 387 | namespace integrals_test { |
| 388 | template <class T> |
| 389 | void reportSiCiFail( |
| 390 | const std::string& name, T z, T c, T e, Real diff, Real tol) { |
| 391 | BOOST_FAIL(std::setprecision(16) |
| 392 | << name << " calculation failed for " << z |
| 393 | << "\n calculated: " << c |
| 394 | << "\n expected: " << e |
| 395 | << "\n difference: " << diff |
| 396 | << "\n tolerance: " << tol); |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | void IntegralTest::testExponentialIntegral() { |
| 401 | BOOST_TEST_MESSAGE("Testing exponential integrals..." ); |
| 402 | |
| 403 | using namespace ExponentialIntegral; |
| 404 | |
| 405 | // reference values are calculated with Mathematica or Python/mpmath |
| 406 | const Real data[][10] = { |
| 407 | {0.0010000000000000000208, 0.0, 0.00099999994444444613193, 0.0, -6.330539864080593754, 0.0, -6.3295393640250381967, 0.0, 6.3315393641361493112, 0.0}, |
| 408 | {0.00070710678118654756077, 0.00070710678118654751747, 0.00070710682047025644818, 0.00070710674190283627304, -6.3305396140806145873, 0.785397913397448279, -6.329832507338711751, 0.7861055202179185354, 6.3312467208225174236, -0.78469130657697802259}, |
| 409 | {6.1232339957367660136e-20, 0.0010000000000000000208, 6.1232350162201617204e-20, 0.001000000055555557243, -6.330539364080593754, 1.570796326794896558, -6.3305398640805937539, 1.5717963267393410041, 6.330539864080593754, -1.5697963268504521119}, |
| 410 | {-0.00070710678118654747417, 0.00070710678118654760407, -0.00070710682047025636158, 0.00070710674190283635964, -6.3305396140806145873, 2.356194740192344837, -6.3312467208225174235, 2.3569013470128150935, 6.3298325073387117511, -2.3554871333718745805}, |
| 411 | {-0.0010000000000000000208, 1.2246467991473532027e-19, -0.00099999994444444613193, 1.2246465950321797194e-19, -6.330539864080593754, 3.141592653589793116, -6.3315393641361493112, 3.1415926535897931161, 6.3295393640250381967, -3.1415926535897931159}, |
| 412 | {-0.00070710678118654764736, -0.00070710678118654743088, -0.00070710682047025653477, -0.00070710674190283618645, -6.3305396140806145873, -2.3561947401923450819, -6.3312467208225174237, -2.3569013470128153382, 6.3298325073387117509, 2.3554871333718748256}, |
| 413 | {-1.8369701987210298041e-19, -0.0010000000000000000208, -1.8369705049015472569e-19, -0.001000000055555557243, -6.330539364080593754, -1.5707963267948968029, -6.3305398640805937541, -1.5717963267393412491, 6.3305398640805937538, 1.5697963268504523568}, |
| 414 | {0.00070710678118654738758, -0.00070710678118654769066, 0.00070710682047025627499, -0.00070710674190283644623, -6.3305396140806145873, -0.78539791339744852393, -6.3298325073387117512, -0.78610552021791878051, 6.3312467208225174234, 0.78469130657697826735}, |
| 415 | {0.10000000000000000555, 0.0, 0.099944461108276955702, 0.0, -1.7278683866572965838, 0.0, -1.6228128139692766136, 0.0, 1.8229239584193906159, 0.0}, |
| 416 | {0.07071067811865475853, 0.0707106781186547542, 0.070749950041603603669, 0.070671382625480302524, -1.7253704697591484327, 0.78289816362892975745, -1.6546990871336681256, 0.8586481132075703999, 1.7960418523846287393, -0.7171482131243632012}, |
| 417 | {6.123233995736766226e-18, 0.10000000000000000555, 6.1334444895968712791e-18, 0.10005557222505700112, -1.7228683861943336147, 1.5707963267948965577, -1.7278683866572965777, 1.670740787903173514, 1.7278683866572965899, -1.4708518656866196026}, |
| 418 | {-0.070710678118654749871, 0.07071067811865476286, -0.070749950041603595024, 0.070671382625480311198, -1.7253704697591484321, 2.3586944899608633586, -1.7960418523846287312, 2.4244444404654299234, 1.6546990871336681349, -2.2829445403822227075}, |
| 419 | {-0.10000000000000000555, 1.2246467991473532452e-17, -0.099944461108276955702, 1.2226067414369268591e-17, -1.7278683866572965838, 3.1415926535897931166, -1.8229239584193906159, 3.1415926535897931277, 1.6228128139692766136, -3.1415926535897931031}, |
| 420 | {-0.07071067811865476719, -0.070710678118654745541, -0.070749950041603612314, -0.07067138262548029385, -1.7253704697591484333, -2.3586944899608636035, -1.7960418523846287474, -2.4244444404654301511, 1.6546990871336681163, 2.2829445403822229697}, |
| 421 | {-1.8369701987210298678e-17, -0.10000000000000000555, -1.8400333469093536425e-17, -0.10005557222505700112, -1.7228683861943336147, -1.5707963267948968038, -1.7278683866572966021, -1.6707407879031737577, 1.7278683866572965654, 1.4708518656866198463}, |
| 422 | {0.070710678118654741211, -0.07071067811865477152, 0.070749950041603586379, -0.070671382625480319872, -1.7253704697591484315, -0.78289816362893000238, -1.6546990871336681441, -0.85864811320757066212, 1.7960418523846287232, 0.71714821312436342884}, |
| 423 | {0.25, 0.0, 0.2491335703197571641, 0.0, -0.82466306258094565309, 0.0, -0.54254326466191372953, 0.0, 1.0442826344437381945, 0.0}, |
| 424 | {0.17677669529663688651, 0.17677669529663687569, 0.17738935115398995617, 0.17616173766104897661, -0.80911938627521916259, 0.76977321991145556311, -0.63295764861417017313, 0.97841245803743094036, 0.98528112393626814822, -0.62363375572945104943}, |
| 425 | {1.5308084989341914715e-17, 0.25, 1.5468043259937507815e-17, 0.2508696848909122325, -0.79341294955282596203, 1.5707963267948965561, -0.82466306258094563794, 1.819929897114653724, 0.82466306258094566823, -1.3216627564751393958}, |
| 426 | {-0.17677669529663686486, 0.17677669529663689734, -0.17738935115398993475, 0.17616173766104899848, -0.80911938627521915876, 2.3718194336783375529, -0.98528112393626813018, 2.517958897860342088, 0.63295764861417019883, -2.1631801955523621542}, |
| 427 | {-0.25, 3.0616169978683829431e-17, -0.2491335703197571641, 3.0298246679137807606e-17, -0.82466306258094565309, 3.1415926535897931198, -1.0442826344437381945, 3.1415926535897931431, 0.54254326466191372953, -3.1415926535897930812}, |
| 428 | {-0.17677669529663690816, -0.17677669529663685404, -0.1773893511539899776, -0.17616173766104895473, -0.80911938627521916642, -2.3718194336783377978, -0.98528112393626816627, -2.5179588978603422901, 0.63295764861417014743, 2.163180195552362442}, |
| 429 | {-4.5924254968025744146e-17, -0.25, -4.6404129781529084775e-17, -0.2508696848909122325, -0.79341294955282596203, -1.5707963267948968087, -0.82466306258094569853, -1.8199298971146539613, 0.82466306258094560764, 1.3216627564751396331}, |
| 430 | {0.17677669529663684321, -0.17677669529663691899, 0.17738935115398991333, -0.17616173766104902036, -0.80911938627521915494, -0.769773219911455808, -0.63295764861417022453, -0.97841245803743122809, 0.98528112393626811213, 0.62363375572945125148}, |
| 431 | {0.5, 0.0, 0.49310741804306668916, 0.0, -0.17778407880661290134, 0.0, 0.45421990486317357992, 0.0, 0.55977359477616081175, 0.0}, |
| 432 | {0.35355339059327377302, 0.35355339059327375138, 0.3584268697133189464, 0.34860625536259795411, -0.11658254521497154353, 0.72290178026868503268, 0.23202371014762644078, 1.2063214162395304511, 0.46518880057756951253, -0.48946767681289259981}, |
| 433 | {3.0616169978683829431e-17, 0.5, 3.190788489546069124e-17, 0.50699674981966719583, -0.052776844956493615913, 1.5707963267948965502, -0.17778407880661287198, 2.0639037448379632547, 0.17778407880661293069, -1.0776889087518298763}, |
| 434 | {-0.35355339059327372973, 0.35355339059327379467, -0.35842686971331890493, 0.34860625536259799919, -0.11658254521497152822, 2.4186908733211080836, -0.46518880057756948275, 2.652124976776900558, -0.2320237101476263804, -1.9352712373502626237}, |
| 435 | {-0.5, 6.1232339957367658861e-17, -0.49310741804306668916, 5.8712695126944314728e-17, -0.17778407880661290134, 3.141592653589793131, -0.55977359477616081175, 3.1415926535897931642, -0.45421990486317357992, -3.1415926535897930366}, |
| 436 | {-0.35355339059327381632, -0.35355339059327370808, -0.35842686971331898787, -0.34860625536259790903, -0.11658254521497155883, -2.4186908733211083279, -0.4651888005775695423, -2.6521249767769007193, -0.23202371014762650116, 1.9352712373502629509}, |
| 437 | {-9.1848509936051488292e-17, -0.5, -9.5723654690421041556e-17, -0.50699674981966719583, -0.052776844956493615913, -1.5707963267948968264, -0.1777840788066129894, -2.0639037448379634696, 0.17778407880661281327, 1.0776889087518300913}, |
| 438 | {0.35355339059327368643, -0.35355339059327383797, 0.35842686971331886346, -0.34860625536259804427, -0.11658254521497151291, -0.72290178026868527697, 0.23202371014762632001, -1.2063214162395307784, 0.46518880057756945298, 0.48946767681289276116}, |
| 439 | {1.0, 0.0, 0.94608307036718301494, 0.0, 0.33740392290096813466, 0.0, 1.8951178163559367555, 0.0, 0.21938393439552027368, 0.0}, |
| 440 | {0.70710678118654754605, 0.70710678118654750275, 0.74519215535365930209, 0.66666481741950631398, 0.56680209825930888934, 0.53562961732242986806, 1.233466915678815284, 1.7803588648261259588, 0.099862719160197444251, -0.28997455411880742612}, |
| 441 | {6.1232339957367658861e-17, 1.0, 7.1960319005373041642e-17, 1.0572508753757285146, 0.83786694098020824089, 1.5707963267948965247, 0.33740392290096818619, 2.5168793971620796011, -0.33740392290096808314, -0.62471325642771357121}, |
| 442 | {-0.70710678118654745945, 0.70710678118654758935, -0.74519215535365923063, 0.66666481741950641427, 0.5668020982593089504, 2.605963036267363253, -0.099862719160197405024, 2.8516180994709857664, -1.2334669156788151226, -1.3612337887636670908}, |
| 443 | {-1.0, 1.2246467991473531772e-16, -0.94608307036718301494, 1.0305047480945999774e-16, 0.33740392290096813466, 3.1415926535897931723, -0.21938393439552027368, 3.1415926535897931934, -1.8951178163559367555, -3.1415926535897929056}, |
| 444 | {-0.70710678118654763265, -0.70710678118654741616, -0.74519215535365937355, -0.66666481741950621369, 0.56680209825930882828, -2.6059630362673634878, -0.099862719160197483478, -2.8516180994709858582, -1.2334669156788154453, 1.3612337887636674684}, |
| 445 | {-1.8369701987210297658e-16, -1.0, -2.158809570266204413e-16, -1.0572508753757285146, 0.83786694098020824089, -1.5707963267948969027, 0.33740392290096798009, -2.5168793971620797334, -0.33740392290096828924, 0.62471325642771370354}, |
| 446 | {0.70710678118654737286, -0.70710678118654767594, 0.74519215535365915917, -0.66666481741950651456, 0.56680209825930901147, -0.53562961732243010279, 1.2334669156788149613, -1.7803588648261263365, 0.099862719160197365796, 0.28997455411880751794}, |
| 447 | {1.5, 0.0, 1.3246835311721196804, 0.0, 0.47035631719539988668, 0.0, 3.301285449129797838, 0.0, 0.1000195824066326519, 0.0}, |
| 448 | {1.0606601717798213191, 1.0606601717798212541, 1.1839593855572855609, 0.9194789610047786165, 0.93002583013377829907, 0.22553329329273497242, 1.8495047911385570699, 2.5292224190594471214, -0.010546869128999664075, -0.16130364794487607552}, |
| 449 | {9.1848509936051488292e-17, 1.5, 1.3038076345658281264e-16, 1.7006525157682152449, 1.600632933361582593, 1.5707963267948964752, 0.47035631719539994775, 2.8954798579670162953, -0.4703563171953998256, -0.24611279562277693453}, |
| 450 | {-1.0606601717798211892, 1.060660171779821384, -1.1839593855572854849, 0.91947896100477878934, 0.93002583013377843491, 2.9160593602970581693, 0.010546869128999701077, 2.9802890056449171422, -1.8495047911385567612, -0.61237023453034594437}, |
| 451 | {-1.5, 1.8369701987210297658e-16, -1.3246835311721196804, 1.2215790424776667532e-16, 0.47035631719539988668, 3.1415926535897932298, -0.1000195824066326519, 3.1415926535897932111, -3.301285449129797838, -3.1415926535897926896}, |
| 452 | {-1.060660171779821449, -1.0606601717798211242, -1.1839593855572856369, -0.91947896100477844366, 0.93002583013377816324, -2.9160593602970583627, 0.010546869128999627072, -2.9802890056449171836, -1.8495047911385573786, 0.6123702345303462898}, |
| 453 | {-2.7554552980815446488e-16, -1.5, -3.9114229038065365107e-16, -1.7006525157682152449, 1.600632933361582593, -1.5707963267948970514, 0.47035631719539970344, -2.8954798579670163126, -0.47035631719540006991, 0.24611279562277695186}, |
| 454 | {1.0606601717798210593, -1.0606601717798215139, 1.1839593855572854089, -0.91947896100477896218, 0.93002583013377857075, -0.22553329329273516584, 1.8495047911385564526, -2.5292224190594474668, -0.010546869128999738079, 0.16130364794487611693}, |
| 455 | {2.0, 0.0, 1.6054129768026948486, 0.0, 0.4229808287748649957, 0.0, 4.9542343560018901634, 0.0, 0.048900510708061119567, 0.0}, |
| 456 | {1.4142135623730950921, 1.4142135623730950055, 1.6883194933582990243, 1.0649044719839209475, 1.1044891171909028954, -0.19981522706084708457, 2.1693935891748240916, 3.4589310472140426889, -0.039584645206981933184, -0.08229206049744467714}, |
| 457 | {1.2246467991473531772e-16, 2.0, 2.2208114946641807464e-16, 2.5015674333549756415, 2.4526669226469145219, 1.5707963267948963889, 0.42298082877486505138, 3.1762093035975914933, -0.42298082877486494002, 0.034616650007798203864}, |
| 458 | {-1.4142135623730949189, 1.4142135623730951787, -1.6883194933582989874, 1.0649044719839212109, 1.1044891171909031294, 3.3414078806506402814, 0.039584645206981962593, 3.0593005930923485567, -2.169393589174823594, 0.31733839362424952895}, |
| 459 | {-2.0, 2.4492935982947063545e-16, -1.6054129768026948486, 1.1135681831696612616e-16, 0.4229808287748649957, 3.1415926535897932894, -0.048900510708061119567, 3.1415926535897932219, -4.9542343560018901634, -3.1415926535897923336}, |
| 460 | {-1.4142135623730952653, -1.4142135623730948323, -1.6883194933582990613, -1.064904471983920684, 1.1044891171909026613, -3.3414078806506403646, 0.039584645206981903775, -3.059300593092348566, -2.1693935891748245892, -0.31733839362424937184}, |
| 461 | {-3.6739403974420595317e-16, -2.0, -6.6624344842268023737e-16, -2.5015674333549756415, 2.4526669226469145219, -1.5707963267948973103, 0.42298082877486482866, -3.1762093035975913914, -0.42298082877486516273, -0.03461665000779830579}, |
| 462 | {1.4142135623730947457, -1.4142135623730953519, 1.6883194933582989504, -1.0649044719839214744, 1.1044891171909033635, 0.19981522706084700137, 2.1693935891748230965, -3.458931047214042846, -0.039584645206981992002, 0.082292060497444686426}, |
| 463 | {5.0, 0.0, 1.5499312449446741373, 0.0, -0.19002974965664387862, 0.0, 40.185275355803177455, 0.0, 0.0011482955912753257973, 0.0}, |
| 464 | {3.5355339059327377302, 3.5355339059327375138, 3.6871508611543429709, -3.157181373909001357, -3.1547681046716106125, -2.1118502909279661892, -6.311949478580612776, 7.3697974788772077195, -0.0024132692373907452624, 0.0045042434314801607547}, |
| 465 | {3.0616169978683829431e-16, 5.0, 4.5436362172750887551e-15, 20.09321182569722639, 20.092063530105951065, 1.5707963267948920752, -0.19002974965664393734, 3.1207275717395707391, 0.1900297496566438199, -0.020865081850222464588}, |
| 466 | {-3.5355339059327372973, 3.5355339059327379467, -3.6871508611543449094, -3.1571813739090021642, -3.1547681046716114182, 5.2534429445177613695, 0.0024132692373907438925, 3.1460968970212734025, 6.3119494785806111631, 4.2282048252874106008}, |
| 467 | {-5.0, 6.1232339957367658861e-16, -1.5499312449446741373, -1.174343542809398959e-16, -0.19002974965664387862, 3.1415926535897932037, -0.0011482955912753257973, 3.1415926535897932376, -40.185275355803177455, -3.1415926535897750631}, |
| 468 | {-3.5355339059327381632, -3.5355339059327370808, -3.6871508611543410324, 3.1571813739090005499, -3.1547681046716098067, -5.2534429445177574859, 0.0024132692373907466323, -3.1460968970212733959, 6.3119494785806143889, -4.2282048252874183613}, |
| 469 | {-9.1848509936051488292e-16, -5.0, -1.3630908648516543815e-14, -20.09321182569722639, 20.092063530105951065, -1.5707963267949102514, -0.19002974965664370247, -3.1207275717395708086, 0.19002974965664405477, 0.020865081850222534065}, |
| 470 | {3.5355339059327368643, -3.5355339059327383797, 3.6871508611543468479, 3.1571813739090029713, -3.154768104671612224, 2.1118502909279700728, -6.3119494785806095501, -7.3697974788771999589, -0.0024132692373907425226, -0.004504243431480167346}, |
| 471 | {10.0, 0.0, 1.6583475942188740493, 0.0, -0.045456433004455372635, 0.0, 2492.2289762418777591, 0.0, 4.1569689296853242774e-6, 0.0}, |
| 472 | {7.0710678118654754605, 7.0710678118654750275, -3.7745175303432929615, 62.642575559232345941, 62.642571122904060317, 5.3452347019798827768, 125.28514668213645736, -7.5489559055283299711, 4.4363282856236060522e-6, -0.000079155158306803868409}, |
| 473 | {6.1232339957367658861e-16, 10.0, 6.7436601941373126554e-13, 1246.1144901994233444, 1246.1144860424544147, 1.5707963267942222532, -0.045456433004455405946, 3.2291439210137707199, 0.045456433004455339323, 0.087551267423977378721}, |
| 474 | {-7.0710678118654745945, 7.0710678118654758935, 3.7745175303433438135, 62.642575559232397046, 62.642571122904111422, -2.2036420483901403904, -4.4363282856235323221e-6, 3.1415134984314864345, -125.28514668213635515, -10.690548559118021506}, |
| 475 | {-10.0, 1.2246467991473531772e-15, -1.6583475942188740493, -6.6623371218859982286e-17, -0.045456433004455372635, 3.1415926535897933412, -4.1569689296853242774e-6, 3.1415926535897932385, -2492.2289762418777591, -3.1415926535870957744}, |
| 476 | {-7.0710678118654763265, -7.0710678118654741616, 3.7745175303432421091, -62.642575559232294835, 62.642571122904009212, 2.2036420483900386859, -4.4363282856236797822e-6, -3.1415134984314864347, -125.28514668213655957, 10.690548559118224914}, |
| 477 | {-1.8369701987210297658e-15, -10.0, -2.0230980582411937966e-12, -1246.1144901994233444, 1246.1144860424544147, -1.5707963267969197173, -0.045456433004455272699, -3.2291439210137705144, 0.04545643300445547257, -0.087551267423977584235}, |
| 478 | {7.0710678118654737286, -7.0710678118654767594, -3.7745175303433946658, -62.642575559232448152, 62.642571122904162528, -5.3452347019799844813, 125.28514668213625294, 7.5489559055281265623, 4.4363282856234585915e-6, 0.000079155158306804015139}, |
| 479 | {15.0, 0.0, 1.6181944437083687391, 0.0, 0.046278677674360439604, 0.0, 234955.85249076830358, 0.0, 1.9186278921478669771e-8, 0.0}, |
| 480 | {10.606601717798213191, 10.606601717798212541, -471.05515346873571713, -1328.2594907541181068, -1328.2594913017652105, 472.62595127241629118, -2656.5189820558856064, -942.11030841435617353, 5.4764710367805069957e-7, 1.4768856774331466472e-6}, |
| 481 | {9.1848509936051488292e-16, 15.0, 1.0008479153886857898e-10, 117477.92624539374493, 117477.92624537455865, 1.5707963266948118277, 0.046278677674360479423, 3.1889907705032654049, -0.046278677674360399786, 0.047398116913472073375}, |
| 482 | {-10.606601717798211892, 10.60660171779821384, 471.05515346873477896, -1328.2594907541203959, -1328.2594913017674995, -469.48435861882555978, -5.4764710367805350438e-7, 3.1415941304754706716, 2656.5189820558810283, -945.2519010679478431}, |
| 483 | {-15.0, 1.8369701987210297658e-15, -1.6181944437083687391, 7.9637292204322254463e-17, 0.046278677674360439604, 3.1415926535897933315, -1.9186278921478669771e-8, 3.1415926535897932385, -234955.85249076830358, -3.1415926531894540723}, |
| 484 | {-10.60660171779821449, -10.606601717798211242, 471.05515346873665531, 1328.2594907541158178, -1328.2594913017629215, 469.48435861882743613, -5.4764710367804789476e-7, -3.1415941304754706716, 2656.5189820558901845, 945.25190106794409045}, |
| 485 | {-2.7554552980815446488e-15, -15.0, -3.0025437461660077385e-10, -117477.92624539374493, 117477.92624537455865, -1.5707963270951509938, 0.046278677674360320148, -3.1889907705032652188, -0.04627867767436055906, -0.047398116913472259445}, |
| 486 | {10.606601717798210593, -10.606601717798215139, -471.05515346873384079, 1328.2594907541226849, -1328.2594913017697886, -472.62595127241441484, -2656.5189820558764503, 942.11030841435992621, 5.4764710367805630921e-7, -1.4768856774331489463e-6}, |
| 487 | {20.0, 0.0, 1.5482417010434398402, 0.0, 0.04441982084535331654, 0.0, 25615652.66405658882, 0.0, 9.8355252906498816904e-11, 0.0}, |
| 488 | {14.142135623730950921, 14.142135623730950055, 24486.68965358318626, 26235.092183360235647, 26235.092183384186671, -24485.118857281672279, 52470.184366744507202, 48973.379307191653857, -2.3951024244493564362e-8, -2.5280915398646225218e-8}, |
| 489 | {1.2246467991473531772e-15, 20.0, 1.4853900090407493933e-8, 12807826.332028294459, 12807826.332028294361, 1.5707963119409965288, 0.044419820845353372442, 3.1190380278383364344, -0.044419820845353260638, -0.02255462575145675408}, |
| 490 | {-14.142135623730949189, 14.142135623730951787, -24486.689653583186682, 26235.092183360320531, 26235.092183384271555, 24488.260449935262494, 2.3951024244493652701e-8, 3.1415926283088778398, -52470.184366744337435, 48970.23771453806322}, |
| 491 | {-20.0, 2.4492935982947063545e-15, -1.5482417010434398402, 1.1180354790034662799e-16, 0.04441982084535331654, 3.1415926535897931885, -9.8355252906498816904e-11, 3.1415926535897932385, -25615652.66405658882, -3.1415925941741928768}, |
| 492 | {-14.142135623730952653, -14.142135623730948323, -24486.689653583185838, -26235.092183360150763, 26235.092183384101787, -24488.26044993526165, 2.3951024244493476023e-8, -3.1415926283088778398, -52470.184366744676971, -48970.237714538064908}, |
| 493 | {-3.6739403974420595317e-15, -20.0, -4.4561700271222483452e-8, -12807826.332028294459, 12807826.332028294361, -1.5707963713565968905, 0.044419820845353148834, -3.1190380278383365344, -0.044419820845353484245, 0.022554625751456854031}, |
| 494 | {14.142135623730947457, -14.142135623730953519, 24486.689653583187103, -26235.092183360405415, 26235.09218338435644, 24485.118857281673122, 52470.184366744167666, -48973.37930719165217, -2.3951024244493741041e-8, 2.528091539864622434e-8}, |
| 495 | {24.989999999999998437, 0.0, 1.5315374843262580141, 0.0, -0.0072448862399538447391, 0.0, 2977286754.0962403117, 0.0, 5.4047414055481939457e-13, 0.0}, |
| 496 | {17.67059846185182207, 17.670598461851820988, -885673.16331345207799, -400248.00540652140574, -400248.00540652215797, 885674.7341097792085, -800496.01081304623667, -1771346.3266269055961, 7.5223231588352466724e-10, 3.3560562518531656391e-10}, |
| 497 | {1.5301961755346176992e-15, 24.989999999999998437, 2.1825789542468514196e-6, 1488643377.0481201559, 1488643377.0481201559, 1.5707941442159423724, -0.0072448862399538534498, 3.1023338111211545727, 0.0072448862399538360284, -0.039258842468638544566}, |
| 498 | {-17.670598461851819906, 17.670598461851823152, 885673.16331345318248, -400248.0054065240787, -400248.00540652483093, -885671.59251712672318, -7.5223231588352706351e-10, 3.1415926539253988636, 800496.01081304089075, -1771349.4682195569769}, |
| 499 | {-24.989999999999998437, 3.0603923510692353985e-15, -1.5315374843262580141, -1.7421457417638512695e-17, -0.0072448862399538447391, 3.1415926535897931172, -5.4047414055481939457e-13, 3.1415926535897932385, -2977286754.0962403117, -3.1415839232739762511}, |
| 500 | {-17.670598461851824234, -17.670598461851818824, 885673.16331345097349, 400248.00540651873277, -400248.005406519485, 885671.5925171245142, -7.5223231588352227096e-10, -3.1415926539253988636, 800496.01081305158263, 1771349.4682195613948}, |
| 501 | {-4.5905885266038530977e-15, -24.989999999999998437, -6.5477368627405542588e-6, -1488643377.0481201559, 1488643377.0481201559, -1.5708028745317593598, -0.0072448862399538186069, -3.1023338111211548151, 0.0072448862399538708713, 0.039258842468638787005}, |
| 502 | {17.670598461851817742, -17.670598461851825316, -885673.16331345428695, 400248.00540652675168, -400248.00540652750391, -885674.73410978141745, -800496.01081303554482, 1771346.3266269011781, 7.5223231588352945979e-10, -3.3560562518531458362e-10} |
| 503 | }; |
| 504 | |
| 505 | const Real tol = 1e-10; |
| 506 | |
| 507 | for (const auto& i : data) { |
| 508 | const Real x = i[0]; |
| 509 | const Real y = (std::abs(x: i[1]) < 1e-12) ? 0.0 : i[1]; |
| 510 | const std::complex<Real> z(x, y); |
| 511 | |
| 512 | |
| 513 | const std::complex<Real> si = Si(z); |
| 514 | std::complex<Real> ref(i[2], i[3]); |
| 515 | Real diff = std::abs(z: si-ref)/std::abs(z: ref); |
| 516 | if (diff > tol |
| 517 | || (std::abs(x: ref.real()) < tol && std::abs(x: si.real()) > tol) |
| 518 | || (std::abs(x: ref.imag()) < tol && std::abs(x: si.imag()) > tol)) { |
| 519 | integrals_test::reportSiCiFail(name: "Si" , z, c: si, e: ref, diff, tol); |
| 520 | } |
| 521 | |
| 522 | const std::complex<Real> ci = Ci(z); |
| 523 | ref = std::complex<Real>(i[4], i[5]); |
| 524 | diff = std::min(a: std::abs(z: ci-ref), b: std::abs(z: ci-ref)/std::abs(z: ref)); |
| 525 | if (diff > tol |
| 526 | || (std::abs(x: ref.real()) < tol && std::abs(x: ci.real()) > tol) |
| 527 | || (std::abs(x: ref.imag()) < tol && std::abs(x: ci.imag()) > tol)) { |
| 528 | integrals_test::reportSiCiFail(name: "Ci" , z, c: ci, e: ref, diff, tol); |
| 529 | } |
| 530 | |
| 531 | const std::complex<Real> ei = Ei(z); |
| 532 | ref = std::complex<Real>(i[6], i[7]); |
| 533 | diff = std::abs(z: ei-ref)/std::abs(z: ref); |
| 534 | if (diff > tol |
| 535 | || (std::abs(x: ref.real()) < tol && std::abs(x: ei.real()) > tol) |
| 536 | || (std::abs(x: ref.imag()) < tol && std::abs(x: ei.imag()) > tol)) { |
| 537 | integrals_test::reportSiCiFail(name: "Ei" , z, c: ei, e: ref, diff, tol); |
| 538 | } |
| 539 | |
| 540 | const std::complex<Real> e1 = E1(z); |
| 541 | ref = std::complex<Real>(i[8], i[9]); |
| 542 | diff = std::min(a: std::abs(z: e1-ref), b: std::abs(z: e1-ref)/std::abs(z: ref)); |
| 543 | if (std::abs(z: z) < 10.0) |
| 544 | if (diff > tol |
| 545 | || (std::abs(x: ref.real()) < tol && std::abs(x: e1.real()) > tol) |
| 546 | || (std::abs(x: ref.imag()) < tol && std::abs(x: e1.imag()) > tol)) { |
| 547 | integrals_test::reportSiCiFail(name: "E1" , z, c: e1, e: ref, diff, tol); |
| 548 | } |
| 549 | } |
| 550 | } |
| 551 | |
| 552 | |
| 553 | |
| 554 | void IntegralTest::testRealSiCiIntegrals() { |
| 555 | BOOST_TEST_MESSAGE("Testing real Ci and Si..." ); |
| 556 | |
| 557 | using namespace ExponentialIntegral; |
| 558 | |
| 559 | // reference values are calculated with Mathematica or Python/mpmath |
| 560 | const Real data[][3] = { |
| 561 | {1e-12, 1e-12, -27.0538054510270153677}, |
| 562 | {0.1, 0.09994446110827695570, -1.7278683866572965838}, |
| 563 | {1.0, 0.9460830703671830149, 0.3374039229009681347}, |
| 564 | {1.9999, 1.6053675097543679041, 0.4230016343635392}, |
| 565 | {3.9999, 1.758222058430840841, -0.140965355646150101}, |
| 566 | {4.0001, 1.758184218306157867, -0.140998037827177150}, |
| 567 | {5.0, 1.5499312449446741373, -0.19002974965664387862}, |
| 568 | {7.0, 1.4545966142480935906, 0.076695278482184518383,}, |
| 569 | {10.0, 1.6583475942188740493, -0.045456433004455372635}, |
| 570 | {15.0, 1.6181944437083687391, 0.046278677674360439604}, |
| 571 | {20.0, 1.5482417010434398402, 0.04441982084535331654}, |
| 572 | {24.9, 1.532210740207620024, -0.010788215638781789846}, |
| 573 | {25.1, 1.5311526281483412938, -0.0028719014454227088097}, |
| 574 | {30.0, 1.566756540030351111, -0.033032417282071143779}, |
| 575 | {40.0, 1.5869851193547845068, 0.019020007896208766962}, |
| 576 | {400.0, 1.5721148692738117518, -0.00212398883084634893}, |
| 577 | {4000.0, 1.5709788562309441985, -0.00017083030544201591130} |
| 578 | }; |
| 579 | |
| 580 | |
| 581 | const Real tol = 1e-12; |
| 582 | |
| 583 | for (const auto& i : data) { |
| 584 | Real x = i[0]; |
| 585 | Real si = Si(x); |
| 586 | |
| 587 | Real diff = std::fabs(x: si - i[1]); |
| 588 | if (diff > tol) { |
| 589 | integrals_test::reportSiCiFail(name: "SineIntegral" , z: x, c: si, e: i[1], diff, tol); |
| 590 | } |
| 591 | |
| 592 | const Real ci = Ci(x); |
| 593 | diff = std::fabs(x: ci - i[2]); |
| 594 | if (diff > tol) { |
| 595 | integrals_test::reportSiCiFail(name: "CosineIntegral" , z: x, c: ci, e: i[2], diff, tol); |
| 596 | } |
| 597 | |
| 598 | x = -i[0]; |
| 599 | si = Si(x); |
| 600 | diff = std::fabs(x: si + i[1]); |
| 601 | if (diff > tol) { |
| 602 | integrals_test::reportSiCiFail(name: "SineIntegral" , z: x, c: si, e: Real(-i[1]), diff, tol); |
| 603 | } |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | test_suite* IntegralTest::suite() { |
| 608 | auto* suite = BOOST_TEST_SUITE("Integration tests" ); |
| 609 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testSegment)); |
| 610 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testTrapezoid)); |
| 611 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testMidPointTrapezoid)); |
| 612 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testSimpson)); |
| 613 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testGaussKronrodAdaptive)); |
| 614 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testGaussKronrodNonAdaptive)); |
| 615 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testGaussLobatto)); |
| 616 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testGaussLegendreIntegrator)); |
| 617 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testGaussChebyshevIntegrator)); |
| 618 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testGaussChebyshev2ndIntegrator)); |
| 619 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testTwoDimensionalIntegration)); |
| 620 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testFolinIntegration)); |
| 621 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testDiscreteIntegrals)); |
| 622 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testDiscreteIntegrator)); |
| 623 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testPiecewiseIntegral)); |
| 624 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testExponentialIntegral)); |
| 625 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testRealSiCiIntegrals)); |
| 626 | |
| 627 | #ifdef QL_BOOST_HAS_TANH_SINH |
| 628 | suite->add(QUANTLIB_TEST_CASE(&IntegralTest::testTanhSinh)); |
| 629 | #endif |
| 630 | |
| 631 | return suite; |
| 632 | } |
| 633 | |
| 634 | |