16 template<
class count_t>
17 inline std::optional<count_t> integration_sample_count(
double fExtent,
size_t nSamplesPerUnit) noexcept
19 if (!std::isfinite(fExtent) || nSamplesPerUnit == 0)
23 const double fCount = std::ceil(std::abs(fExtent) *
static_cast<double>(nSamplesPerUnit));
26 const double fCountLimit = std::ldexp(1.0, std::numeric_limits<count_t>::digits);
27 if (!std::isfinite(fCount) || fCount >= fCountLimit)
30 return static_cast<count_t
>(fCount);
35 template<
class function_2d_t>
37 noexcept(
static_cast<double>(func(0.0))))
39 const auto optIntervals = details::integration_sample_count<size_t>(x1 - x0, nIntervalsPer1);
41 return std::numeric_limits<double>::quiet_NaN();
43 const size_t nIntervals = *optIntervals;
47 const double dx = (x1 - x0) /
static_cast<double>(nIntervals);
48 double fTotalArea = 0.0;
51 for (
size_t i = 0; i < nIntervals; ++i)
53 fTotalArea += dx * func(x);
60 template<
class function_2d_t>
62 noexcept(
static_cast<double>(func(0.0))))
64 const auto optIntervals = details::integration_sample_count<size_t>(x1 - x0, nIntervalsPer1);
66 return std::numeric_limits<double>::quiet_NaN();
68 const size_t nIntervals = *optIntervals;
72 const double dx = (x1 - x0) /
static_cast<double>(nIntervals);
73 double fTotalArea = 0.0;
76 for (
size_t i = 0; i < nIntervals; ++i)
78 fTotalArea += dx * (func(x) + func(x + dx)) / 2;
85 template<
class function_2d_t>
87 const function_2d_t& func,
90 double fMaxSliceError,
91 size_t nIntervalsPer1,
92 size_t nMaxRecursion) noexcept(noexcept(
static_cast<double>(func(0.0))))
94 const auto optIntervals = details::integration_sample_count<size_t>(x1 - x0, nIntervalsPer1);
96 return std::numeric_limits<double>::quiet_NaN();
98 const size_t nIntervals = *optIntervals;
102 const double dx = (x1 - x0) /
static_cast<double>(nIntervals);
103 double fTotalArea = 0.0;
108 const auto& slice_area,
109 const function_2d_t& func,
112 double max_slice_error,
113 size_t recursionLevel)
115 const double y0 = func(x0);
116 const double y1 = func(x1);
117 const double xm = (x0 + x1) / 2;
118 const double ym = func(xm);
120 const double fArea12 = (x1 - x0) * (y0 + y1) / 2.0;
121 const double fArea1m = (xm - x0) * (y0 + ym) / 2.0;
122 const double fAream2 = (x1 - xm) * (ym + y1) / 2.0;
123 const double fArea1m2 = fArea1m + fAream2;
125 const double fError = (fArea1m2 - fArea12) / fArea12;
128 if (recursionLevel > nMaxRecursion || std::abs(fError) < max_slice_error)
134 return slice_area(func, x0, xm, max_slice_error, recursionLevel)
135 + slice_area(func, xm, x1, max_slice_error, recursionLevel);
139 for (
size_t i = 0; i < nIntervals; ++i)
141 fTotalArea += slice_area(func, x, x + dx, fMaxSliceError, 0);
148 template<
class function_2d_t>
150 const function_2d_t& funcIsInside,
153 size_t nPointsPerOneSquare) noexcept(noexcept(
static_cast<int>(funcIsInside(0.0, 0.0))))
155 const double fArea = std::abs(pos1.x - pos0.x) * std::abs(pos1.y - pos0.y);
157 const auto optTotalPoints = details::integration_sample_count<int>(fArea, nPointsPerOneSquare);
159 return std::numeric_limits<double>::quiet_NaN();
161 const int nTotalPoints = *optTotalPoints;
162 if (nTotalPoints == 0)
165 int points_inside = 0;
167 std::default_random_engine generator(
static_cast<unsigned>(std::time(
nullptr)));
169 std::uniform_real_distribution<double> x_dist(std::min(pos0.x, pos1.x), std::max(pos0.x, pos1.x));
170 std::uniform_real_distribution<double> y_dist(std::min(pos0.y, pos1.y), std::max(pos0.y, pos1.y));
172 for (
int i = 0; i < nTotalPoints; ++i)
174 int f = funcIsInside(x_dist(generator), y_dist(generator));
181 return (
static_cast<double>(points_inside) / nTotalPoints) * fArea;
double integrate_monte_carlo(const function_2d_t &funcIsInside, glm::dvec2 pos0, glm::dvec2 pos1, size_t nPointsPerOneSquare=1000) noexcept(noexcept(static_cast< int >(funcIsInside(0.0, 0.0))))
Integrate using probabilistic algorithm Monte Carlo.
double integrate_rectangle_rule(const function_2d_t &func, double x0, double x1, size_t nIntervalsPer1=10) noexcept(noexcept(static_cast< double >(func(0.0))))
Integrate using rectangle rule.
double integrate_adaptive_midpoint(const function_2d_t &func, double x0, double x1, double fMaxSliceError, size_t nIntervalsPer1=10, size_t nMaxRecursion=300) noexcept(noexcept(static_cast< double >(func(0.0))))
Integrate using adaptive midpoint.
double integrate_trapezoid_rule(const function_2d_t &func, double x0, double x1, size_t nIntervalsPer1=10) noexcept(noexcept(static_cast< double >(func(0.0))))
Integrate using trapezoid rule.
recursive_lambda< std::decay_t< lambda_t > > make_recursive_lambda(lambda_t &&lambda)
Create lambda that can be called recursively.