Skip to content

Commit 7ee5826

Browse files
author
maechler
committed
dbinom(*, size=Inf, ..) fixing also dnbinom(x, size, *) [normal case] with large x and size
git-svn-id: https://svn.r-project.org/R/trunk@88185 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 7b3de84 commit 7ee5826

File tree

3 files changed

+40
-8
lines changed

3 files changed

+40
-8
lines changed

doc/NEWS.Rd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@
107107

108108
\item \code{dnbinom(<large>, <muchlarger>, ..)} now is \code{0}
109109
correctly, instead of \code{NaN} or \code{Inf} sometimes.
110+
111+
\item \code{dbinom(<large>, n=Inf, ..)} is \code{0} now correctly,
112+
instead of \code{NaN} which also fixes many \code{dnbinom()} cases,
113+
notably those mentioned in \PR{16727} comment #5.
110114
}
111115
}
112116
}

src/nmath/dbinom.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Merge in to R and further tweaks :
77
* notably using log1p() and pow1p(), thanks to Morten Welinder, PR#18642
88
*
9-
* Copyright (C) 2000-2024 The R Core Team
9+
* Copyright (C) 2000-2025 The R Core Team
1010
* Copyright (C) 2008 The R Foundation
1111
*
1212
* This program is free software; you can redistribute it and/or modify
@@ -60,8 +60,9 @@ double pow1p(double x, double y)
6060
/* naive algorithm in two cases: (1) when 1+x is exact (compiler should not over-optimize !),
6161
* and (2) when |x| > 1/2 and we have no better algorithm.
6262
*/
63-
if ((x + 1) - 1 == x || fabs(x) > 0.5 || isnan(x))
64-
return pow(1 + x, y);
63+
volatile double xp1 = x + 1., x_ = xp1 - 1.; // compiler should *not* optimize these
64+
if (x_ == x || fabs(x) > 0.5 || isnan(x)) {
65+
return pow(xp1, y);
6566
else /* not perfect, e.g., for small |x|, non-huge y, use
6667
binom expansion 1 + y*x + y(y-1)/2 x^2 + .. */
6768
return exp(y * log1p(x));
@@ -88,6 +89,11 @@ double dbinom_raw(double x, double n, double p, double q, int give_log)
8889
}
8990
if (x < 0 || x > n) return( R_D__0 );
9091

92+
if(!R_FINITE(n)) {
93+
if(R_FINITE(x)) return( R_D__0 ); /* finite x << n = Inf */
94+
else n = DBL_MAX; // helps ? extreme dnbinom() cases
95+
}
96+
9197
// TODO? Improve accuracy in these cases:
9298
#ifdef _NO_LOG_DBINOM_
9399
if(!give_log) { // more accurate *not* going via log when result is much much smaller than 1

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -576,12 +576,15 @@ xL <- c(2^(1000+ c(1:23, 23.5, 23.9, 24-1e-13)), L, MxM, Inf)
576576
(pP <- ppois(xL, mu)) # all 1
577577
stopifnot(dP == 0, pP == 1, identical(pP, pgamma(mu, xL + 1, 1., lower.tail=FALSE)))
578578
## cbind(xL, dP, pP)
579-
579+
## dbinom(*, size=Inf, ..):
580+
stopifnot(dbinom(2^c(0:1023, 1023.999), size=Inf, prob = .1) == 0) # were all NaN
580581
(dLmI <- dnbinom(xL, mu = 1, size = Inf)) # all == 0
581-
## FIXME (boundary case, still!); MxM/2 seems +- ok ??
582-
(dLmM <- dnbinom(xL, mu = 1, size = MxM)) # all NaN but the last
583-
(dLpI <- dnbinom(xL, prob=1/2, size = Inf))# ditto
584-
(dLpM <- dnbinom(xL, prob=1/2, size = MxM))# ditto
582+
stopifnot(exprs = { ## boundary case, had all NaN (but the last one)
583+
dLmI == 0
584+
dnbinom(xL, mu = 1, size = MxM) == 0
585+
dnbinom(xL, prob=1/2, size = Inf) == 0
586+
dnbinom(xL, prob=1/2, size = MxM) == 0
587+
})
585588

586589
d <- dnbinom(x, mu = mu, size = Inf) # gave NaN (for 0 and L), now 0 for large x
587590
p <- pnbinom(x, mu = mu, size = Inf) # gave all NaN, now uses ppois(x, mu)
@@ -607,6 +610,25 @@ stopifnot( exprs = {# the x < 1e-10*size case; "easily" fixed now
607610
## size = Inf (and not so large x
608611
dnbinom(x=10^(0:298), size=Inf, prob=.999) == 0 # had NaN from 10^155 on
609612
})
613+
## Now, more size=<Large> (normal case, mostly x >= 1e-10*size)
614+
prob <- 0.999
615+
mu <- 5
616+
str(x <- MxM*2^seq(-4, 0, by = 1/8))# MxM/16 .... MxM
617+
cat(format(head(log2(x), 4)), " .. ", format(tail(log2(x), 3)),"\n")
618+
head(x. <- outer(x, 2^-c(8, 4, 0))); tail(x., 3)
619+
stopifnot( exprs = {# the x < 1e-10*size case; "easily" fixed now
620+
dnbinom(x, prob=prob, size = Inf ) == 0 # was all NaN
621+
dnbinom(x, prob=prob, size = MxM ) == 0 # " "
622+
dnbinom(x, prob=prob, size = MxM/4) == 0 # was 0 ... 0 NaN NaN NaN NaN
623+
dnbinom(x, prob=prob, size = MxM/8) == 0 # was 0 ... 0 0 0 NaN NaN
624+
## the "same" with mu
625+
dnbinom(x., mu=mu, size = Inf ) == 0 # (already)
626+
dnbinom(x., mu=mu, size = MxM ) == 0 # was NaN
627+
dnbinom(x., mu=mu, size = MxM/2) == 0 # most 0, some NaN
628+
dnbinom(x., mu=mu, size = MxM/4) == 0 # 0 0 ... 0 NaN NaN NaN NaN
629+
dnbinom(x., mu=mu, size = MxM/8) == 0 # 0 0 ... 0 0 0 NaN NaN
630+
})
631+
610632
options(op)
611633
## size = Inf -- mostly gave NaN in R <= 3.2.3
612634

0 commit comments

Comments
 (0)