Skip to content

Commit 4ba4369

Browse files
author
maechler
committed
tweak bd0(<large>,<small>) to prevent overflow in x/np, also fixing dbinom(*, prob=<subnormal_small>, log=TRUE)
git-svn-id: https://svn.r-project.org/R/trunk@88208 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 9857527 commit 4ba4369

File tree

2 files changed

+19
-8
lines changed

2 files changed

+19
-8
lines changed

src/nmath/bd0.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ attribute_hidden double bd0(double x, double np)
5959
v = (x_ - n_)/(x_ + n_);
6060
}
6161
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
62+
if(fabs(ldexp(s, 1)) < DBL_MIN) return ldexp(s, 1);
6363
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
@@ -79,8 +79,11 @@ attribute_hidden double bd0(double x, double np)
7979
x, np, s, ej/((1000<<1)+1));
8080
}
8181
/* else: | x - np | is not too small */
82-
return (x > np) ? x*(log(x/np) -1.) + np
83-
: x* log(x/np) + np -x;
82+
/* NB: x/np |--> inf (overflow) doesn't happen when called from rpois_raw() */
83+
#define lg_x_n (R_FINITE(x/np) ? log(x/np) : (log(x) - log(np)))
84+
return (x > np) ? x*(lg_x_n -1.) + np
85+
: x* lg_x_n + np -x;
86+
#undef lg_x_n
8487
}
8588

8689

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -665,11 +665,19 @@ dbArg <- cbind(
665665
(db <- apply(dbArg, 1, \(v3) do.call(dbinom, c(v3, list(log=TRUE))))) ## was all -Inf !
666666
## dput(signif(db, 6))
667667
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
668+
all.equal(db, tolerance = 1e-5,
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)))
672+
## all == -Inf in R <= 4.5.0
673+
674+
x <- c(12:20, 100*c(1,3,10,20,50)) # dbinom for very small prob (did overflow in bd0())
675+
(db <- dbinom(x, size=x+1, prob = 2^-1024.1, log = TRUE))
676+
stopifnot(
677+
all.equal(c(-8515.66, -9225.44, -9935.22, -10645, -11354.8, -12064.6, -12774.4,
678+
-13484.2, -14194, -70980.6, -212950, -709845, -1419700, -3549250),
679+
db, tolerance = 1e-5))
680+
## all but the first two where -Inf in R <= 4.5.0
673681

674682

675683
## qpois(p, *) for invalid 'p' should give NaN -- PR#16972

0 commit comments

Comments
 (0)