Skip to content

Commit f185cda

Browse files
author
maechler
committed
YA tweak to bd0(<large>,<large>): prevent overflow in 2*x*v
git-svn-id: https://svn.r-project.org/R/trunk@88193 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent b7a17d3 commit f185cda

File tree

2 files changed

+24
-7
lines changed

2 files changed

+24
-7
lines changed

src/nmath/bd0.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,20 +58,20 @@ attribute_hidden double bd0(double x, double np)
5858
n_ = ldexp(np,-2);
5959
v = (x_ - n_)/(x_ + n_);
6060
}
61-
double s = d * v;
62-
if(fabs(s) < DBL_MIN) return s;
63-
double ej = x * ldexp(v, 1); // = 2*x*v;
61+
double s = ldexp(d, -1) * v; // was d * v
62+
if(fabs(s) < DBL_MIN*0.5) return ldexp(s, 1);// CARE: assumes subnormal numbers
63+
double ej = x * v; // as 2*x*v could overflow: v > 1/2 <==> ej = 2xv > x
6464
v *= v; // "v = v^2"
6565
for (int j = 1; j < 1000; j++) { /* Taylor series; 1000: no infinite loop
66-
as |v| < .1, v^2000 is "zero" */
67-
ej *= v;// = 2 x v^(2j+1)
66+
as |v| < .1, v^2000 is "zero" */
67+
ej *= v;// = x v^(2j+1)
6868
double s_ = s;
6969
s += ej/((j<<1)+1);
7070
if (s == s_) { /* last term was effectively 0 */
7171
#ifdef DEBUG_bd0
72-
REprintf("bd0(%g, %g): T.series w/ %d terms -> bd0=%g\n", x, np, j, s);
72+
REprintf("bd0(%g, %g): T.series w/ %d terms -> bd0=%g\n", x, np, j, ldexp(s, 1));
7373
#endif
74-
return s;
74+
return ldexp(s, 1); // 2*s ; as we dropped '2 *' above
7575
}
7676
}
7777
/* ---- the following should _never_ happen ------------ */

tests/d-p-q-r-tst-2.R

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,23 @@ stopifnot(all.equal(tolerance = 1e-11,
655655
134.598198071, 55.4909088367, 10.1000515546, 1.6625043907, 36.710476479,
656656
127.476528317, 297.82558994, 600.93919587, 1195.32578926, 3368.52998705), db))
657657

658+
## db0() tweak (against overflow of ej = 2*x*v):
659+
dbArg <- cbind(
660+
x = c(1.465e+308, 1.4715e+308, 1.4762e+308, 1.4822e+308, 1.4869e+308, 1.4949e+308, 1.5034e+308,
661+
1.5137e+308, 1.523e+308, 1.5305e+308, 1.5416e+308, 1.5486e+308, 1.5653e+308, 1.5853e+308, 1.639e+308),
662+
size=c(1.6574e+308, 1.6514e+308, 1.7035e+308, 1.679e+308, 1.6531e+308, 1.6285e+308, 1.6993e+308,
663+
1.6661e+308, 1.6801e+308, 1.6873e+308, 1.7506e+308, 1.7052e+308, 1.6752e+308, 1.6885e+308, 1.731e+308),
664+
prob=c(27, 27, 26, 27, 28, 29, 28, 29, 29, 30, 29, 30, 32, 33, 35)/128)
665+
(db <- apply(dbArg, 1, \(v3) do.call(dbinom, c(v3, list(log=TRUE))))) ## was all -Inf !
666+
## dput(signif(db, 6))
667+
stopifnot(
668+
all.equal(db,
669+
c(-1.73031e+308, -1.76399e+308, -1.73534e+308, -1.74653e+308, -1.7615e+308,
670+
-1.79181e+308, -1.7259e+308, -1.77688e+308, -1.77981e+308, -1.74055e+308,
671+
-1.70236e+308, -1.76548e+308, -1.79598e+308, -1.79126e+308, -1.79514e+308), tolerance = 1e-5))
672+
## all == -Inf previously
673+
674+
658675
## qpois(p, *) for invalid 'p' should give NaN -- PR#16972
659676
stopifnot(is.nan(suppressWarnings(c(qpois(c(-2,3, NaN), 3), qpois(1, 3, log.p=TRUE),
660677
qpois(.5, 0, log.p=TRUE), qpois(c(-1,pi), 0)))))

0 commit comments

Comments
 (0)