| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // This file is part of INSTINCT, the INS Toolkit for Integrated | ||
| 2 | // Navigation Concepts and Training by the Institute of Navigation of | ||
| 3 | // the University of Stuttgart, Germany. | ||
| 4 | // | ||
| 5 | // This Source Code Form is subject to the terms of the Mozilla Public | ||
| 6 | // License, v. 2.0. If a copy of the MPL was not distributed with this | ||
| 7 | // file, You can obtain one at https://mozilla.org/MPL/2.0/. | ||
| 8 | |||
| 9 | #include "Math.hpp" | ||
| 10 | |||
| 11 | namespace NAV::math | ||
| 12 | { | ||
| 13 | |||
| 14 | 25776 | uint64_t factorial(uint64_t n) | |
| 15 | { | ||
| 16 | // uint64_t is required to calculate factorials of n > 12 (Limit of uint32_t). The limit of uint64_t is at n = 20 | ||
| 17 | 25776 | constexpr std::array factorials = { | |
| 18 | uint64_t(1), // 0 | ||
| 19 | uint64_t(1), // 1 | ||
| 20 | uint64_t(2), // 2 | ||
| 21 | uint64_t(6), // 3 | ||
| 22 | uint64_t(24), // 4 | ||
| 23 | uint64_t(120), // 5 | ||
| 24 | uint64_t(720), // 6 | ||
| 25 | uint64_t(5040), // 7 | ||
| 26 | uint64_t(40320), // 8 | ||
| 27 | uint64_t(362880), // 9 | ||
| 28 | uint64_t(3628800), // 10 | ||
| 29 | uint64_t(39916800), // 11 | ||
| 30 | uint64_t(479001600), // 12 | ||
| 31 | uint64_t(6227020800), // 13 | ||
| 32 | uint64_t(87178291200), // 14 | ||
| 33 | uint64_t(1307674368000), // 15 | ||
| 34 | uint64_t(20922789888000), // 16 | ||
| 35 | uint64_t(355687428096000), // 17 | ||
| 36 | uint64_t(6402373705728000), // 18 | ||
| 37 | uint64_t(121645100408832000), // 19 | ||
| 38 | uint64_t(2432902008176640000), // 20 | ||
| 39 | }; | ||
| 40 | |||
| 41 |
1/2✓ Branch 0 taken 25776 times.
✗ Branch 1 not taken.
|
25776 | if (n < factorials.size()) |
| 42 | { | ||
| 43 |
1/2✓ Branch 1 taken 25776 times.
✗ Branch 2 not taken.
|
25776 | return factorials.at(n); |
| 44 | } | ||
| 45 | ✗ | return n * factorial(n - 1); | |
| 46 | } | ||
| 47 | |||
| 48 | ✗ | double normalCDF(double value) | |
| 49 | { | ||
| 50 | ✗ | return 0.5 * std::erfc(-value * M_SQRT1_2); | |
| 51 | } | ||
| 52 | |||
| 53 | 1343753 | double calcEllipticalIntegral(double phi, double m) | |
| 54 | { | ||
| 55 | 1343753 | double origM = m; | |
| 56 | 1343753 | double scale = 0.0; | |
| 57 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1343753 times.
|
1343753 | if (m > 1.0) |
| 58 | { | ||
| 59 | ✗ | scale = std::sqrt(m); | |
| 60 | ✗ | phi = std::asin(scale * std::sin(phi)); | |
| 61 | ✗ | m = 1.0 / m; | |
| 62 | } | ||
| 63 |
1/2✓ Branch 0 taken 1343753 times.
✗ Branch 1 not taken.
|
1343753 | else if (m < 0.0) |
| 64 | { | ||
| 65 | 1343753 | scale = std::sqrt(1.0 - m); | |
| 66 | 1343753 | phi = 0.5 * M_PI - phi; | |
| 67 | 1343753 | m /= m - 1.0; | |
| 68 | } | ||
| 69 | 1343753 | double a = 0.0; | |
| 70 | 1343753 | double eok = 0.0; | |
| 71 | 1343753 | double f = 0.0; | |
| 72 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1343753 times.
|
1343753 | if (m == 1.0) |
| 73 | { | ||
| 74 | ✗ | double per = std::floor((phi + 0.5 * M_PI) / M_PI); | |
| 75 | ✗ | phi = std::sin(phi) * math::sgn(0.5 - std::abs(std::fmod(per, 2.0))) + 2 * per; | |
| 76 | ✗ | a = 0.0; | |
| 77 | } | ||
| 78 | else | ||
| 79 | { // compute using arithmetic-geometric mean | ||
| 80 | 1343753 | double sgn = math::sgn(phi); | |
| 81 | 1343753 | phi = std::abs(phi), | |
| 82 | 1343753 | a = 1.0; | |
| 83 | 1343753 | double b = std::sqrt(1.0 - m); | |
| 84 | 1343753 | eok = 1.0 - 0.5 * m; | |
| 85 | 1343753 | double cs = 0.0; | |
| 86 | 1343753 | double twon = 1.0; | |
| 87 | 1343753 | double pi2 = 0.5 * M_PI; | |
| 88 | while (true) | ||
| 89 | { // maximum of 8 passes for 64-bit double | ||
| 90 | 6718765 | double c = 0.5 * (a - b); | |
| 91 |
2/2✓ Branch 2 taken 1343753 times.
✓ Branch 3 taken 5375012 times.
|
6718765 | if (std::abs(c) <= std::numeric_limits<double>::epsilon() * c) { break; } |
| 92 | 5375012 | phi += std::atan((b / a) * std::tan(phi)) + M_PI * std::floor((phi + pi2) / M_PI); | |
| 93 | 5375012 | cs += c * std::sin(phi); | |
| 94 | 5375012 | eok -= twon * c * c; | |
| 95 | 5375012 | twon *= 2.0; | |
| 96 | 5375012 | double am = a - c; | |
| 97 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5375012 times.
|
5375012 | if (am == a) { break; } |
| 98 | 5375012 | b = std::sqrt(a * b); | |
| 99 | 5375012 | a = am; | |
| 100 | 5375012 | } | |
| 101 | 1343753 | double f = sgn * phi / (twon * a); | |
| 102 | 1343753 | phi = eok * f + sgn * cs; | |
| 103 | } | ||
| 104 | |||
| 105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1343753 times.
|
1343753 | if (origM > 1.0) |
| 106 | { | ||
| 107 | ✗ | phi = (phi - (1.0 - m) * f) / scale; | |
| 108 | } | ||
| 109 |
1/2✓ Branch 0 taken 1343753 times.
✗ Branch 1 not taken.
|
1343753 | else if (origM < 0.0) |
| 110 | { | ||
| 111 | 1343753 | phi = (eok * 0.5 * M_PI / a - phi) * scale; | |
| 112 | } | ||
| 113 | |||
| 114 | 1343753 | return phi; | |
| 115 | } | ||
| 116 | } // namespace NAV::math | ||
| 117 |