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