Estimates an integral over a semi-infinite or infinite interval. Calculates an approximation to an integral
< Left end point.
< Right end point.
< Approximation to the integral over this interval.
< Error estimate.
< Left end point.
< Right end point.
< Approximation to the integral over this interval.
< Error estimate.
146 {
147
148 status = 0;
149 result = 0.;
150 abserr = 0.;
151
152
153 constexpr double eps = std::numeric_limits<double>::epsilon();
154 if (epsabs <= 0. && epsrel < std::max(50. * eps, 0.5e-28)) {
155 status = 6;
156 return;
157 }
158
159 if (inf == 2) bound = 0.;
160 double resabs0 = 0., resasc0 = 0.;
161 qk15i(f, bound, inf, 0., 1., result, abserr, resabs0, resasc0);
162
163
164 double tol = std::max(epsabs, epsrel * std::abs(result));
165
166 if (abserr <= 100. * eps * resabs0 && abserr > tol) {
167
168 status = 2;
169 return;
170 }
171
172 if ((abserr <= tol && abserr != resasc0) || abserr == 0.) return;
173
174 struct Interval {
175 double a;
176 double b;
177 double r;
178 double e;
179 };
180 std::vector<Interval> intervals(1);
181 intervals[0].a = 0.;
182 intervals[0].b = 1.;
183 intervals[0].r = result;
184 intervals[0].e = abserr;
185 constexpr unsigned int nMaxIntervals = 500;
186 unsigned int nIntervals = 1;
187
188 auto it = intervals.begin();
189 size_t nrmax = 0;
190
191
192 std::array<double, 52> epstab;
193 epstab[0] = result;
194
195 unsigned int nEps = 2;
196
197 std::array<double, 3> lastRes = {0., 0., 0.};
198
199 unsigned int nRes = 0;
200
201 bool extrap = false;
202
203 bool noext = false;
204 unsigned int ktmin = 0;
205
206
207 double area = result;
208
209 double errSum = abserr;
210
211 double small = 0.375;
212
213
214 double errLarge = 0.;
215 double errTest = 0.;
216
217 double errMax = abserr;
218 abserr = std::numeric_limits<double>::max();
219
220
221 std::array<unsigned int, 3> nRoundOff = {0, 0, 0};
222 bool roundOffErrors = false;
223 double correc = 0.;
224
225
226 const bool pos = (std::abs(result) >= (1. - 50. * eps) * resabs0);
227
228
229 bool dosum = false;
230 for (nIntervals = 2; nIntervals <= nMaxIntervals; ++nIntervals) {
231
232 const double a1 = (*it).a;
233 const double b2 = (*it).b;
234 const double b1 = 0.5 * (a1 + b2);
235 const double a2 = b1;
236
237 const double errLast = (*it).e;
238 double area1 = 0., err1 = 0., resabs1 = 0., resasc1 = 0.;
239 qk15i(f, bound, inf, a1, b1, area1, err1, resabs1, resasc1);
240 double area2 = 0., err2 = 0., resabs2 = 0., resasc2 = 0.;
241 qk15i(f, bound, inf, a2, b2, area2, err2, resabs2, resasc2);
242
243
244 const double area12 = area1 + area2;
245 const double err12 = err1 + err2;
246 errSum += err12 - errMax;
247 area += area12 - (*it).r;
248 if (resasc1 != err1 && resasc2 != err2) {
249 if (std::abs((*it).r - area12) <= 1.e-5 * std::abs(area12) &&
250 err12 >= 0.99 * errMax) {
251 if (extrap) {
252 ++nRoundOff[1];
253 } else {
254 ++nRoundOff[0];
255 }
256 }
257 if (nIntervals > 10 && err12 > errMax) ++nRoundOff[2];
258 }
259 tol = std::max(epsabs, epsrel * std::abs(area));
260
261 if (nRoundOff[0] + nRoundOff[1] >= 10 || nRoundOff[2] >= 20) status = 2;
262 if (nRoundOff[1] >= 5) roundOffErrors = true;
263
264 if (nIntervals == nMaxIntervals) status = 1;
265
266
267 constexpr double tol1 = 1. + 100. * eps;
268 constexpr double tol2 = 1000. * std::numeric_limits<double>::min();
269 if (std::max(std::abs(a1), std::abs(b2)) <= tol1 * (std::abs(a2) + tol2)) {
270 status = 4;
271 }
272
273 if (err2 > err1) {
274 (*it).a = a2;
275 (*it).r = area2;
276 (*it).e = err2;
277 Interval interval;
278 interval.a = a1;
279 interval.b = b1;
280 interval.r = area1;
281 interval.e = err1;
282 intervals.push_back(std::move(interval));
283 } else {
284 (*it).b = b1;
285 (*it).r = area1;
286 (*it).e = err1;
287 Interval interval;
288 interval.a = a2;
289 interval.b = b2;
290 interval.r = area2;
291 interval.e = err2;
292 intervals.push_back(std::move(interval));
293 }
294
295 std::sort(intervals.begin(), intervals.end(),
296 [](const Interval& lhs, const Interval& rhs) {
297 return (lhs.e > rhs.e);
298 });
299
300 it = intervals.begin() + nrmax;
301 errMax = (*it).e;
302 if (errSum <= tol) {
303 dosum = true;
304 break;
305 }
306 if (status != 0) break;
307 if (nIntervals == 2) {
308 errLarge = errSum;
309 errTest = tol;
310 epstab[1] = area;
311 continue;
312 }
313 if (noext) continue;
314 errLarge -= errLast;
315 if (std::abs(b1 - a1) > small) errLarge += err12;
316 if (!extrap) {
317
318 if (std::abs((*it).b - (*it).a) > small) continue;
319 extrap = true;
320 nrmax = 1;
321 }
322
323
324
325 if (!roundOffErrors && errLarge > errTest) {
326 const size_t k0 = nrmax;
327 size_t k1 = nIntervals;
328 if (nIntervals > (2 + nMaxIntervals / 2)) {
329 k1 = nMaxIntervals + 3 - nIntervals;
330 }
331 bool found = false;
332 for (unsigned int k = k0; k < k1; ++k) {
333 it = intervals.begin() + nrmax;
334 errMax = (*it).e;
335 if (std::abs((*it).b - (*it).a) > small) {
336 found = true;
337 break;
338 }
339 ++nrmax;
340 }
341 if (found) continue;
342 }
343
344 epstab[nEps] = area;
345 ++nEps;
346 double resExtr = 0., errExtr = 0.;
347 qelg(nEps, epstab, resExtr, errExtr, lastRes, nRes);
348 ++ktmin;
349 if (ktmin > 5 && abserr < 1.e-3 * errSum) status = 5;
350 if (errExtr < abserr) {
351 ktmin = 0;
352 abserr = errExtr;
353 result = resExtr;
354 correc = errLarge;
355 errTest = std::max(epsabs, epsrel * std::abs(resExtr));
356 if (abserr <= errTest) break;
357 }
358
359 if (nEps == 1) noext = true;
360 if (status == 5) break;
361 it = intervals.begin();
362 errMax = (*it).e;
363 nrmax = 0;
364 extrap = false;
366 errLarge = errSum;
367 }
368
369 if (abserr == std::numeric_limits<double>::max()) dosum = true;
370 if (!dosum) {
371 if ((status != 0 || roundOffErrors)) {
372 if (roundOffErrors) {
373 abserr += correc;
374 if (status == 0) status = 3;
375 }
376 if (result != 0. && area != 0.) {
377 if (abserr / std::abs(result) > errSum / std::abs(area)) dosum = true;
378 } else {
379 if (abserr > errSum) {
380 dosum = true;
381 } else if (area == 0.) {
382 if (status > 2) --status;
383 return;
384 }
385 }
386 }
387
388 if (!dosum) {
389 if (!pos && std::max(std::abs(result), std::abs(area)) <= resabs0 * 0.01) {
390 if (status > 2) --status;
391 return;
392 }
393 const double r = result / area;
394 if (r < 0.01 || r > 100. || errSum > std::abs(area)) {
395 status = 5;
396 return;
397 }
398 }
399 } else {
400
401 result = 0.;
402 for (const auto& interval : intervals) result += interval.r;
403 abserr = errSum;
404 if (status > 2) --status;
405 }
406}
void qk15i(std::function< double(double)> f, double bound, const int inf, const double a, const double b, double &result, double &abserr, double &resabs, double &resasc)