Skip to content

Commit 1444f55

Browse files
Merge pull request #77 from niclaurenti/fix-overflow
Guards against numerical overflows that result in `NaN`
2 parents bd2a9d9 + a07dab1 commit 1444f55

File tree

3 files changed

+69
-10
lines changed

3 files changed

+69
-10
lines changed

src/Convolution.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ double Convolution::regular_integrand(double z, void *p) {
126126
double x = (params->x);
127127
int nf = (params->nf);
128128

129+
// When the integration interval [x, x_max] is very small, a quadrature node can round to
130+
// z = x in double precision, giving x/z = 1 exactly. Some splitting functions (e.g. Pgg1reg)
131+
// produce NaN at x/z = 1 due to 0*inf in harmonic polylogarithms. And given that the true
132+
// integrand is finite there, we can simply return 0.
133+
if (x / z >= 1.) return 0.;
134+
129135
return (params->conv)->GetCoeffFunc()->MuIndependentTerms(z, m2Q2, nf)
130136
* (params->conv)->GetSplitFunc()->Regular(x / z, nf) / z;
131137
}
@@ -198,6 +204,12 @@ double Convolution::singular_integrand(double z, void *p) {
198204
double x = (params->x);
199205
int nf = (params->nf);
200206

207+
// When the integration interval [x/x_max, 1] is very small, a quadrature node can round to
208+
// z = 1 in double precision. At z = 1 the plus-distribution subtraction (f(x/z)/z - f(x))
209+
// vanishes while Singular(z) = 1/(1-z) diverges, producing inf * 0 = NaN. Given that the
210+
// true limit is finite, we can simply return 0.
211+
if (z >= 1.) return 0.;
212+
201213
return (params->conv)->GetSplitFunc()->Singular(z, nf)
202214
* ((params->conv)
203215
->GetCoeffFunc()
@@ -468,6 +480,9 @@ double
468480

469481
double z1 = z[0], z2 = z[1];
470482

483+
// Guard against x/z1 or z1/z2 rounding to 1 (see `regular_integrand`).
484+
if (x / z1 >= 1. || z1 / z2 >= 1.) return 0.;
485+
471486
if (z2 > z1) {
472487
return 1. / (z1 * z2)
473488
* (params->conv)->GetSplitFunc()->Regular(x / z1, nf)
@@ -494,6 +509,9 @@ double
494509

495510
double z1 = z[0], z2 = z[1];
496511

512+
// Guard against x/z1 rounding to 1 or z1/z2 rounding to 1.
513+
if (x / z1 >= 1. || z1 / z2 >= 1.) return 0.;
514+
497515
if (z2 > z1) {
498516
return 1. / (z1 * z2)
499517
* (params->conv)->GetSplitFunc()->Regular(x / z1, nf)
@@ -522,6 +540,9 @@ double DoubleConvolution::regular3_integrand(double z, void *p) {
522540
double x = (params->x);
523541
int nf = (params->nf);
524542

543+
// Guard against x/z rounding to 1.
544+
if (x / z >= 1.) return 0.;
545+
525546
double x_max = CoefficientFunction::xMax(m2Q2);
526547

527548
return -1. / z * (params->conv)->GetSplitFunc()->Regular(x / z, nf)
@@ -599,6 +620,11 @@ double DoubleConvolution::singular1_integrand(
599620

600621
double z1 = z[0], z2 = z[1];
601622

623+
// At z1 = 1 the plus-distribution subtraction vanishes while Singular diverges,
624+
// producing inf * 0 = NaN. Given that the true integrand is finite, we can simply
625+
// return 0.
626+
if (z1 >= 1.) return 0.;
627+
602628
double tmp;
603629
if (z2 > x / z1) {
604630
tmp = (params->conv)->GetSplitFunc()->Regular(x / (z1 * z2), nf) / z1;
@@ -630,6 +656,10 @@ double DoubleConvolution::singular2_integrand(
630656

631657
double z1 = z[0], z2 = z[1];
632658

659+
// At z1 = 1 or z2 = 1 the plus-distribution subtraction vanishes while Singular diverges,
660+
// producing inf * 0 = NaN.
661+
if (z1 >= 1. || z2 >= 1.) return 0.;
662+
633663
double tmp;
634664
if (z2 > x / (x_max * z1)) {
635665
tmp = ((params->conv)
@@ -668,6 +698,10 @@ double DoubleConvolution::singular3_integrand(double z, void *p) {
668698
double x = (params->x);
669699
int nf = (params->nf);
670700

701+
// Guard: at z = 1 the plus-distribution subtraction vanishes while Singular diverges,
702+
// producing inf * 0 = NaN.
703+
if (z >= 1.) return 0.;
704+
671705
double x_max = CoefficientFunction::xMax(m2Q2);
672706

673707
return -(

src/ExactCoefficientFunction.cc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,12 @@ double ExactCoefficientFunction::fx(
436436
double ExactCoefficientFunction::MuIndependentTerms(
437437
double x, double m2Q2, int nf
438438
) const {
439+
// The coefficient function vanishes at x = xmax due to a constrained phase-space. We need
440+
// to avoid x >= xmax to prevent sqrt of a negative number due to floating-point rounding
441+
// in the beta computation: the expression 1 - 4*m2Q2*x/(1-x), which should be 0 at x = xmax,
442+
// can become slightly negative (~-1e-9) in floating point.
443+
if (x >= xMax(m2Q2)) return 0.;
444+
439445
try {
440446
return (this->*mu_indep_)(x, m2Q2, nf);
441447
} catch (NotValidException &e) {
@@ -454,8 +460,7 @@ double ExactCoefficientFunction::MuDependentTerms(
454460
double x, double m2Q2, double m2mu2, int nf
455461
) const {
456462

457-
if (x <= 0 || x > xMax(m2Q2))
458-
return 0.;
463+
if (x <= 0 || x >= xMax(m2Q2)) return 0.;
459464

460465
return (this->*mu_dep_)(x, m2Q2, m2mu2, nf);
461466
}
@@ -480,7 +485,9 @@ Value ExactCoefficientFunction::fxBand(
480485
double ExactCoefficientFunction::C2_g1(double x, double m2Q2, int /*nf*/)
481486
const { // m2Q2=m^2/Q^2
482487

483-
double beta = sqrt(1. - 4. * m2Q2 * x / (1 - x));
488+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
489+
if (beta2 < 0.) beta2 = 0.;
490+
double beta = sqrt(beta2);
484491
double x2 = x * x;
485492
double m4Q4 = m2Q2 * m2Q2;
486493
double L = log((1. + beta) / (1. - beta));
@@ -501,7 +508,9 @@ double ExactCoefficientFunction::C2_g1(double x, double m2Q2, int /*nf*/)
501508
double
502509
ExactCoefficientFunction::CL_g1(double x, double m2Q2, int /*nf*/) const {
503510

504-
double beta = sqrt(1. - 4. * m2Q2 * x / (1. - x));
511+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
512+
if (beta2 < 0.) beta2 = 0.;
513+
double beta = sqrt(beta2);
505514
double x2 = x * x;
506515
double L = log((1. + beta) / (1. - beta));
507516

src/ThresholdCoefficientFunction.cc

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,9 @@ double ThresholdCoefficientFunction::BetaIndependentTerms(
331331
double
332332
ThresholdCoefficientFunction::C2_g1_threshold(double x, double m2Q2) const {
333333

334-
double beta = sqrt(1. - 4. * m2Q2 * x / (1. - x));
334+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
335+
if (beta2 < 0.) beta2 = 0.;
336+
double beta = sqrt(beta2);
335337
double xi = 1. / m2Q2;
336338

337339
return xi * TR * beta / (1. + xi / 4.) / x;
@@ -348,7 +350,9 @@ double
348350
double
349351
ThresholdCoefficientFunction::CL_g1_threshold(double x, double m2Q2) const {
350352

351-
double beta = sqrt(1. - 4. * m2Q2 * x / (1. - x));
353+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
354+
if (beta2 < 0.) beta2 = 0.;
355+
double beta = sqrt(beta2);
352356
double beta3 = beta * beta * beta;
353357

354358
double xi = 1. / m2Q2;
@@ -368,7 +372,10 @@ double ThresholdCoefficientFunction::C2_g2_threshold_expansion(
368372
double x, double m2Q2, double m2mu2, int /*nf*/
369373
) const {
370374

371-
double beta = sqrt(1. - 4. * m2Q2 * x / (1. - x));
375+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
376+
if (beta2 < 0.) beta2 = 0.;
377+
double beta = sqrt(beta2);
378+
if (beta == 0.) return 0.;
372379

373380
double logb = log(beta);
374381
double log2b = logb * logb;
@@ -388,7 +395,10 @@ double ThresholdCoefficientFunction::CL_g2_threshold_expansion(
388395
double x, double m2Q2, double m2mu2, int /*nf*/
389396
) const {
390397

391-
double beta = sqrt(1. - 4. * m2Q2 * x / (1. - x));
398+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
399+
if (beta2 < 0.) beta2 = 0.;
400+
double beta = sqrt(beta2);
401+
if (beta == 0.) return 0.;
392402

393403
double logb = log(beta);
394404
double log2b = logb * logb;
@@ -449,7 +459,10 @@ double ThresholdCoefficientFunction::C2_g3_threshold_expansion(
449459
) const {
450460

451461
double xi = 1. / m2Q2;
452-
double beta = sqrt(1. - 4. * m2Q2 * x / (1. - x));
462+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
463+
if (beta2 < 0.) beta2 = 0.;
464+
double beta = sqrt(beta2);
465+
if (beta == 0.) return 0.;
453466

454467
double Lm = log(m2mu2);
455468
double Lm2 = Lm * Lm;
@@ -539,7 +552,10 @@ double ThresholdCoefficientFunction::C2_g3_threshold_expansion_const(
539552
double ThresholdCoefficientFunction::CL_g3_threshold_expansion(
540553
double x, double m2Q2, double m2mu2, int nf
541554
) const {
542-
double beta = sqrt(1. - 4. * m2Q2 * x / (1. - x));
555+
double beta2 = 1. - 4. * m2Q2 * x / (1. - x);
556+
if (beta2 < 0.) beta2 = 0.;
557+
double beta = sqrt(beta2);
558+
if (beta == 0.) return 0.;
543559

544560
double rhoq = -4. * m2Q2;
545561
double betaq = sqrt(1. - rhoq);

0 commit comments

Comments
 (0)