File indexing completed on 2026-09-28 09:20:49
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathInteg_DoubleExp_HeaderFile
0015 #define _MathInteg_DoubleExp_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathUtils_Core.hxx>
0020
0021 #include <cmath>
0022
0023 namespace MathInteg
0024 {
0025 using namespace MathUtils;
0026
0027
0028 struct DoubleExpConfig : IntegConfig
0029 {
0030 int NbLevels = 6;
0031 double StepFactor = 0.5;
0032
0033
0034 DoubleExpConfig() = default;
0035
0036
0037 explicit DoubleExpConfig(double theTolerance, int theMaxIter = 100)
0038 : IntegConfig(theTolerance, theMaxIter)
0039 {
0040 }
0041 };
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 template <typename Function>
0064 IntegResult TanhSinh(Function& theFunc,
0065 double theLower,
0066 double theUpper,
0067 const DoubleExpConfig& theConfig = DoubleExpConfig())
0068 {
0069 IntegResult aResult;
0070
0071 if (theLower >= theUpper)
0072 {
0073 aResult.Status = Status::InvalidInput;
0074 return aResult;
0075 }
0076
0077 const double aHalfPi = M_PI / 2.0;
0078 const double aMid = 0.5 * (theUpper + theLower);
0079 const double aHalf = 0.5 * (theUpper - theLower);
0080
0081
0082 double aH = 1.0;
0083
0084
0085 double aPrevSum = 0.0;
0086 size_t aTotalPoints = 0;
0087
0088
0089 for (int aLevel = 0; aLevel < theConfig.NbLevels; ++aLevel)
0090 {
0091 double aSum = 0.0;
0092 int aNbPoints = 0;
0093
0094
0095
0096 int aStart = (aLevel == 0) ? 0 : 1;
0097 int aStep = (aLevel == 0) ? 1 : 2;
0098
0099
0100 for (int k = aStart;; k += aStep)
0101 {
0102 double aT = k * aH;
0103
0104
0105 double aSinhT = std::sinh(aT);
0106 double aCoshT = std::cosh(aT);
0107
0108
0109 double aU = aHalfPi * aSinhT;
0110
0111
0112 if (std::abs(aU) > 700.0)
0113 {
0114 break;
0115 }
0116
0117
0118 double aTanhU = std::tanh(aU);
0119 double aCoshU = std::cosh(aU);
0120 double aSech2U = 1.0 / (aCoshU * aCoshU);
0121
0122
0123 double aX = aMid + aHalf * aTanhU;
0124
0125
0126 if (aX <= theLower + MathUtils::THE_ZERO_TOL || aX >= theUpper - MathUtils::THE_ZERO_TOL)
0127 {
0128 break;
0129 }
0130
0131
0132 double aWeight = aHalf * aHalfPi * aCoshT * aSech2U;
0133
0134
0135 if (aWeight < MathUtils::THE_ZERO_TOL)
0136 {
0137 break;
0138 }
0139
0140
0141 double aF = 0.0;
0142 if (!theFunc.Value(aX, aF))
0143 {
0144
0145 continue;
0146 }
0147
0148
0149 if (!std::isfinite(aF))
0150 {
0151 continue;
0152 }
0153
0154 aSum += aWeight * aF;
0155 ++aNbPoints;
0156
0157
0158 if (aNbPoints > 10000)
0159 {
0160 break;
0161 }
0162 }
0163
0164
0165 int aNegStart = (aLevel == 0) ? 1 : aStart;
0166 for (int k = aNegStart;; k += aStep)
0167 {
0168 double aT = -k * aH;
0169
0170 double aSinhT = std::sinh(aT);
0171 double aCoshT = std::cosh(aT);
0172 double aU = aHalfPi * aSinhT;
0173
0174 if (std::abs(aU) > 700.0)
0175 {
0176 break;
0177 }
0178
0179 double aTanhU = std::tanh(aU);
0180 double aCoshU = std::cosh(aU);
0181 double aSech2U = 1.0 / (aCoshU * aCoshU);
0182
0183 double aX = aMid + aHalf * aTanhU;
0184
0185 if (aX <= theLower + MathUtils::THE_ZERO_TOL || aX >= theUpper - MathUtils::THE_ZERO_TOL)
0186 {
0187 break;
0188 }
0189
0190 double aWeight = aHalf * aHalfPi * aCoshT * aSech2U;
0191
0192 if (aWeight < MathUtils::THE_ZERO_TOL)
0193 {
0194 break;
0195 }
0196
0197 double aF = 0.0;
0198 if (!theFunc.Value(aX, aF))
0199 {
0200 continue;
0201 }
0202
0203 if (!std::isfinite(aF))
0204 {
0205 continue;
0206 }
0207
0208 aSum += aWeight * aF;
0209 ++aNbPoints;
0210
0211 if (aNbPoints > 10000)
0212 {
0213 break;
0214 }
0215 }
0216
0217
0218 double aLevelSum = aH * aSum;
0219 aTotalPoints += static_cast<size_t>(aNbPoints);
0220
0221
0222
0223 double aNewSum = (aLevel == 0) ? aLevelSum : 0.5 * aPrevSum + aLevelSum;
0224
0225
0226 if (aLevel > 0)
0227 {
0228 double aAbsError = std::abs(aNewSum - aPrevSum);
0229 double aRelError = aAbsError / std::max(std::abs(aNewSum), 1.0e-15);
0230
0231 if (aRelError < theConfig.Tolerance)
0232 {
0233 aResult.Status = Status::OK;
0234 aResult.Value = aNewSum;
0235 aResult.AbsoluteError = aAbsError;
0236 aResult.RelativeError = aRelError;
0237 aResult.NbPoints = aTotalPoints;
0238 aResult.NbIterations = static_cast<size_t>(aLevel + 1);
0239 return aResult;
0240 }
0241 }
0242
0243 aPrevSum = aNewSum;
0244 aH *= 0.5;
0245 }
0246
0247
0248 aResult.Status = Status::OK;
0249 aResult.Value = aPrevSum;
0250 aResult.NbPoints = aTotalPoints;
0251 aResult.NbIterations = static_cast<size_t>(theConfig.NbLevels);
0252 return aResult;
0253 }
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 template <typename Function>
0266 IntegResult ExpSinh(Function& theFunc,
0267 double theLower,
0268 const DoubleExpConfig& theConfig = DoubleExpConfig())
0269 {
0270 IntegResult aResult;
0271
0272 const double aHalfPi = M_PI / 2.0;
0273 double aH = 1.0;
0274 double aPrevSum = 0.0;
0275 size_t aTotalPoints = 0;
0276
0277 for (int aLevel = 0; aLevel < theConfig.NbLevels; ++aLevel)
0278 {
0279 double aSum = 0.0;
0280 int aNbPoints = 0;
0281
0282 int aStart = (aLevel == 0) ? 0 : 1;
0283 int aStep = (aLevel == 0) ? 1 : 2;
0284
0285
0286 for (int aSign = -1; aSign <= 1; aSign += 2)
0287 {
0288 for (int k = (aSign < 0 && aLevel == 0) ? 1 : aStart;; k += aStep)
0289 {
0290 if (aSign < 0 && k == 0)
0291 {
0292 continue;
0293 }
0294
0295 double aT = aSign * k * aH;
0296
0297 double aSinhT = std::sinh(aT);
0298 double aCoshT = std::cosh(aT);
0299 double aU = aHalfPi * aSinhT;
0300
0301
0302 if (aU > 700.0)
0303 {
0304 break;
0305 }
0306
0307 double aExpU = std::exp(aU);
0308
0309
0310 double aX = theLower + aExpU;
0311
0312
0313 double aWeight = aHalfPi * aCoshT * aExpU;
0314
0315 if (aWeight < MathUtils::THE_ZERO_TOL || !std::isfinite(aWeight))
0316 {
0317 break;
0318 }
0319
0320
0321 if (aU < -30.0)
0322 {
0323 break;
0324 }
0325
0326 double aF = 0.0;
0327 if (!theFunc.Value(aX, aF))
0328 {
0329 continue;
0330 }
0331
0332 if (!std::isfinite(aF))
0333 {
0334 continue;
0335 }
0336
0337 aSum += aWeight * aF;
0338 ++aNbPoints;
0339
0340 if (aNbPoints > 10000)
0341 {
0342 break;
0343 }
0344 }
0345 }
0346
0347 double aLevelSum = aH * aSum;
0348 aTotalPoints += static_cast<size_t>(aNbPoints);
0349
0350
0351 double aNewSum = (aLevel == 0) ? aLevelSum : 0.5 * aPrevSum + aLevelSum;
0352
0353 if (aLevel > 0)
0354 {
0355 double aAbsError = std::abs(aNewSum - aPrevSum);
0356 double aRelError = aAbsError / std::max(std::abs(aNewSum), 1.0e-15);
0357
0358 if (aRelError < theConfig.Tolerance)
0359 {
0360 aResult.Status = Status::OK;
0361 aResult.Value = aNewSum;
0362 aResult.AbsoluteError = aAbsError;
0363 aResult.RelativeError = aRelError;
0364 aResult.NbPoints = aTotalPoints;
0365 aResult.NbIterations = static_cast<size_t>(aLevel + 1);
0366 return aResult;
0367 }
0368 }
0369
0370 aPrevSum = aNewSum;
0371 aH *= 0.5;
0372 }
0373
0374 aResult.Status = Status::OK;
0375 aResult.Value = aPrevSum;
0376 aResult.NbPoints = aTotalPoints;
0377 aResult.NbIterations = static_cast<size_t>(theConfig.NbLevels);
0378 return aResult;
0379 }
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390 template <typename Function>
0391 IntegResult SinhSinh(Function& theFunc, const DoubleExpConfig& theConfig = DoubleExpConfig())
0392 {
0393 IntegResult aResult;
0394
0395 const double aHalfPi = M_PI / 2.0;
0396 double aH = 1.0;
0397 double aPrevSum = 0.0;
0398 size_t aTotalPoints = 0;
0399
0400 for (int aLevel = 0; aLevel < theConfig.NbLevels; ++aLevel)
0401 {
0402 double aSum = 0.0;
0403 int aNbPoints = 0;
0404
0405 int aStart = (aLevel == 0) ? 0 : 1;
0406 int aStep = (aLevel == 0) ? 1 : 2;
0407
0408
0409 for (int aSign = -1; aSign <= 1; aSign += 2)
0410 {
0411 for (int k = (aSign < 0 && aLevel == 0) ? 1 : aStart;; k += aStep)
0412 {
0413 if (aSign < 0 && k == 0)
0414 {
0415 continue;
0416 }
0417
0418 double aT = aSign * k * aH;
0419
0420 double aSinhT = std::sinh(aT);
0421 double aCoshT = std::cosh(aT);
0422 double aU = aHalfPi * aSinhT;
0423
0424
0425 if (std::abs(aU) > 700.0)
0426 {
0427 break;
0428 }
0429
0430 double aSinhU = std::sinh(aU);
0431 double aCoshU = std::cosh(aU);
0432
0433
0434 double aX = aSinhU;
0435
0436
0437 double aWeight = aHalfPi * aCoshT * aCoshU;
0438
0439 if (aWeight < MathUtils::THE_ZERO_TOL || !std::isfinite(aWeight))
0440 {
0441 break;
0442 }
0443
0444 double aF = 0.0;
0445 if (!theFunc.Value(aX, aF))
0446 {
0447 continue;
0448 }
0449
0450 if (!std::isfinite(aF))
0451 {
0452 continue;
0453 }
0454
0455 aSum += aWeight * aF;
0456 ++aNbPoints;
0457
0458 if (aNbPoints > 10000)
0459 {
0460 break;
0461 }
0462 }
0463 }
0464
0465 double aLevelSum = aH * aSum;
0466 aTotalPoints += static_cast<size_t>(aNbPoints);
0467
0468
0469 double aNewSum = (aLevel == 0) ? aLevelSum : 0.5 * aPrevSum + aLevelSum;
0470
0471 if (aLevel > 0)
0472 {
0473 double aAbsError = std::abs(aNewSum - aPrevSum);
0474 double aRelError = aAbsError / std::max(std::abs(aNewSum), 1.0e-15);
0475
0476 if (aRelError < theConfig.Tolerance)
0477 {
0478 aResult.Status = Status::OK;
0479 aResult.Value = aNewSum;
0480 aResult.AbsoluteError = aAbsError;
0481 aResult.RelativeError = aRelError;
0482 aResult.NbPoints = aTotalPoints;
0483 aResult.NbIterations = static_cast<size_t>(aLevel + 1);
0484 return aResult;
0485 }
0486 }
0487
0488 aPrevSum = aNewSum;
0489 aH *= 0.5;
0490 }
0491
0492 aResult.Status = Status::OK;
0493 aResult.Value = aPrevSum;
0494 aResult.NbPoints = aTotalPoints;
0495 aResult.NbIterations = static_cast<size_t>(theConfig.NbLevels);
0496 return aResult;
0497 }
0498
0499
0500
0501
0502
0503
0504
0505
0506
0507
0508
0509
0510
0511
0512 template <typename Function>
0513 IntegResult DoubleExponential(Function& theFunc,
0514 double theLower,
0515 double theUpper,
0516 const DoubleExpConfig& theConfig = DoubleExpConfig())
0517 {
0518 const double aHuge = 1.0e300;
0519
0520 bool aIsLowerInf = (theLower < -aHuge);
0521 bool aIsUpperInf = (theUpper > aHuge);
0522
0523 if (aIsLowerInf && aIsUpperInf)
0524 {
0525
0526 return SinhSinh(theFunc, theConfig);
0527 }
0528 else if (aIsUpperInf)
0529 {
0530
0531 return ExpSinh(theFunc, theLower, theConfig);
0532 }
0533 else if (aIsLowerInf)
0534 {
0535
0536 class NegatedFunc
0537 {
0538 public:
0539 NegatedFunc(Function& theF)
0540 : myFunc(theF)
0541 {
0542 }
0543
0544 bool Value(double theX, double& theF) { return myFunc.Value(-theX, theF); }
0545
0546 private:
0547 Function& myFunc;
0548 };
0549
0550 NegatedFunc aNegated(theFunc);
0551 return ExpSinh(aNegated, -theUpper, theConfig);
0552 }
0553 else
0554 {
0555
0556 return TanhSinh(theFunc, theLower, theUpper, theConfig);
0557 }
0558 }
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571 template <typename Function>
0572 IntegResult TanhSinhSingular(Function& theFunc,
0573 double theLower,
0574 double theUpper,
0575 double theTolerance = 1.0e-10)
0576 {
0577 DoubleExpConfig aConfig;
0578 aConfig.Tolerance = theTolerance;
0579 aConfig.NbLevels = 8;
0580
0581 return TanhSinh(theFunc, theLower, theUpper, aConfig);
0582 }
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595 template <typename Function>
0596 IntegResult TanhSinhWithSingularity(Function& theFunc,
0597 double theLower,
0598 double theUpper,
0599 double theSingularity,
0600 const DoubleExpConfig& theConfig = DoubleExpConfig())
0601 {
0602 IntegResult aResult;
0603
0604 if (theSingularity <= theLower || theSingularity >= theUpper)
0605 {
0606
0607 return TanhSinh(theFunc, theLower, theUpper, theConfig);
0608 }
0609
0610
0611 IntegResult aLeft = TanhSinh(theFunc, theLower, theSingularity, theConfig);
0612 if (!aLeft.IsDone())
0613 {
0614 return aLeft;
0615 }
0616
0617
0618 IntegResult aRight = TanhSinh(theFunc, theSingularity, theUpper, theConfig);
0619 if (!aRight.IsDone())
0620 {
0621 return aRight;
0622 }
0623
0624
0625 aResult.Status = Status::OK;
0626 aResult.Value = *aLeft.Value + *aRight.Value;
0627 aResult.NbPoints = aLeft.NbPoints + aRight.NbPoints;
0628 aResult.NbIterations = std::max(aLeft.NbIterations, aRight.NbIterations);
0629
0630 if (aLeft.AbsoluteError && aRight.AbsoluteError)
0631 {
0632 aResult.AbsoluteError = *aLeft.AbsoluteError + *aRight.AbsoluteError;
0633 aResult.RelativeError = *aResult.AbsoluteError / std::max(std::abs(*aResult.Value), 1.0e-15);
0634 }
0635
0636 return aResult;
0637 }
0638
0639 }
0640
0641 #endif