Skip to content

Commit c24cbaa

Browse files
author
maechler
committed
optimize(); replace -Inf by *negative*; warning msg w/ more detail when replacing NA or +/-Inf
git-svn-id: https://svn.r-project.org/R/trunk@87693 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent 82fc32e commit c24cbaa

File tree

3 files changed

+56
-16
lines changed

3 files changed

+56
-16
lines changed

doc/NEWS.Rd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@
191191
192192
\item \code{unique()}'s default method now also deals with
193193
\code{"difftime"} objects.
194+
195+
\item \code{optimize(f, *)} when \code{f(x)} is not finite says
196+
more about the value in its \code{warning} message. It no longer
197+
replaces \code{-Inf} by the largest \emph{positive} finite number.
194198
}
195199
}
196200

src/library/stats/src/optimize.c

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/*
22
* R : A Computer Language for Statistical Data Analysis
3+
* Copyright (C) 1998--2025 The R Core Team
34
* Copyright (C) 1995, 1996 Robert Gentleman and Ross Ihaka
45
* Copyright (C) 2003-2004 The R Foundation
5-
* Copyright (C) 1998--2023 The R Core Team
66
*
77
* This program is free software; you can redistribute it and/or modify
88
* it under the terms of the GNU General Public License as published by
@@ -219,8 +219,13 @@ static double fcn1(double x, void *arg_info)
219219
case REALSXP:
220220
if (length(s) != 1) goto badvalue;
221221
if (!R_FINITE(REAL(s)[0])) {
222-
warning(_("NA/Inf replaced by maximum positive value"));
223-
return DBL_MAX;
222+
if(REAL(s)[0] == R_NegInf) { // keep sign for root finding !
223+
warning(_("-Inf replaced by maximally negative value"));
224+
return -DBL_MAX;
225+
} else {
226+
warning(_("%s replaced by maximum positive value"), ISNAN(REAL(s)[0]) ? "NA/NaN" : "Inf");
227+
return DBL_MAX;
228+
}
224229
}
225230
else return REAL(s)[0];
226231
break;
@@ -232,33 +237,31 @@ static double fcn1(double x, void *arg_info)
232237
return 0;/* for -Wall */
233238
}
234239

235-
/* fmin(f, xmin, xmax tol) */
240+
/* Called from optimize() as
241+
* .External2(C_do_fmin, function(arg) +/- f(arg, ...), lower, upper, tol)
242+
* fmin(f, xmin, xmax tol) */
236243
SEXP do_fmin(SEXP call, SEXP op, SEXP args, SEXP rho)
237244
{
238-
double xmin, xmax, tol;
239-
SEXP v, res;
240-
struct callinfo info;
241-
242245
args = CDR(args);
243246
PrintDefaults();
244247

245248
/* the function to be minimized */
246249

247-
v = CAR(args);
250+
SEXP v = CAR(args);
248251
if (!isFunction(v))
249252
error(_("attempt to minimize non-function"));
250253
args = CDR(args);
251254

252255
/* xmin */
253256

254-
xmin = asReal(CAR(args));
257+
double xmin = asReal(CAR(args));
255258
if (!R_FINITE(xmin))
256259
error(_("invalid '%s' value"), "xmin");
257260
args = CDR(args);
258261

259262
/* xmax */
260263

261-
xmax = asReal(CAR(args));
264+
double xmax = asReal(CAR(args));
262265
if (!R_FINITE(xmax))
263266
error(_("invalid '%s' value"), "xmax");
264267
if (xmin >= xmax)
@@ -267,13 +270,14 @@ SEXP do_fmin(SEXP call, SEXP op, SEXP args, SEXP rho)
267270

268271
/* tol */
269272

270-
tol = asReal(CAR(args));
273+
double tol = asReal(CAR(args));
271274
if (!R_FINITE(tol) || tol <= 0.0)
272275
error(_("invalid '%s' value"), "tol");
273276

277+
struct callinfo info;
274278
info.R_env = rho;
275279
PROTECT(info.R_fcall = lang2(v, R_NilValue));
276-
PROTECT(res = allocVector(REALSXP, 1));
280+
SEXP res = PROTECT(allocVector(REALSXP, 1));
277281
REAL(res)[0] = Brent_fmin(xmin, xmax, fcn1, &info, tol);
278282
UNPROTECT(2);
279283
return res;
@@ -309,7 +313,7 @@ static double fcn2(double x, void *arg_info)
309313
warning(_("-Inf replaced by maximally negative value"));
310314
return -DBL_MAX;
311315
} else {
312-
warning(_("NA/Inf replaced by maximum positive value"));
316+
warning(_("%s replaced by maximum positive value"), ISNAN(REAL(s)[0]) ? "NA/NaN" : "Inf");
313317
return DBL_MAX;
314318
}
315319
}
@@ -527,8 +531,13 @@ static void fcn(int n, double *x, double *f, void *arg_state)
527531
case REALSXP:
528532
if (length(s) != 1) goto badvalue;
529533
if (!R_FINITE(REAL(s)[0])) {
530-
warning(_("NA/Inf replaced by maximum positive value"));
531-
*f = DBL_MAX;
534+
if(REAL(s)[0] == R_NegInf) { // keep sign for root finding !
535+
warning(_("-Inf replaced by maximally negative value"));
536+
*f = -DBL_MAX;
537+
} else {
538+
warning(_("%s replaced by maximum positive value"), ISNAN(REAL(s)[0]) ? "NA/NaN" : "Inf");
539+
*f = DBL_MAX;
540+
}
532541
}
533542
else *f = REAL(s)[0];
534543
break;

tests/reg-tests-1e.R

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,33 @@ stopifnot(inherits(unidt, "difftime"), length(unidt) <= 2) # '2': allow "inaccur
18061806
## unique() lost the class in R < 4.5.0
18071807

18081808

1809+
## optimize(f(x), *) message when f(x) is not finite
1810+
ff <- function(x) ifelse(x < -10, (x+10)*exp(x^2),
1811+
ifelse(x > 100, NaN,
1812+
ifelse(x > 30, exp((x-20)^2),
1813+
(4 - x)^2)))
1814+
cf <- as.data.frame(curve(ff, -20, 120, ylim = c(-2,200)))
1815+
str(ok <- optimize(ff, c(-10, 10)))
1816+
stopifnot(all.equal(list(minimum = 4, objective = 0), ok))
1817+
op <- options(warn=0)
1818+
str(of2 <- optimize(ff, c(-140, 250))); summary(warnings()); uw2 <- unique(warnings())
1819+
## NA/NaN and -Inf (no +Inf)
1820+
str(of3 <- optimize(ff, c(-20, 120))); summary(warnings()); uw3 <- unique(warnings())
1821+
## only 1 Inf
1822+
str(of4 <- optimize(ff, c(-10, 180))); summary(warnings()); uw4 <- unique(warnings())
1823+
## +Inf and many NA/NaN
1824+
c(uw2, uw3, uw4)
1825+
stopifnot(all.equal(of3, ok),
1826+
identical(c(2:1,2L), lengths(list(uw2, uw3, uw4))))
1827+
if(englishMsgs)
1828+
stopifnot(identical(c("-Inf replaced by maximally negative value",
1829+
"Inf replaced by maximum positive value",
1830+
"NA/NaN replaced by maximum positive value"),
1831+
sort(unique(c(names(uw2), names(uw3), names(uw4))))))
1832+
options(op)# reverting
1833+
## in R < 4.4.z only *one* message .. "NA/Inf replaced by ...."
1834+
1835+
18091836

18101837
## keep at end
18111838
rbind(last = proc.time() - .pt,

0 commit comments

Comments
 (0)