diff --git a/doc/NEWS.Rd b/doc/NEWS.Rd index 9ffc4b683c..e030cdb768 100644 --- a/doc/NEWS.Rd +++ b/doc/NEWS.Rd @@ -144,6 +144,10 @@ \item If \code{La_library()} is empty, \code{sessionInfo()} still reports \code{La_version()} when available. + \item \code{seq.int(from, to, by, ....)} when \eqn{|by| = 1} now + behaves as if \code{by} was omitted, and hence returns \code{from:to}, + possibly integer. + \item \code{seq.Date(from, to, by, ....)} and \code{seq.POSIXt(..)} now also work when \code{from} is missing and sufficient further arguments are provided, thanks to \I{Michael Chirico}'s report, patch diff --git a/src/main/seq.c b/src/main/seq.c index d4387a7e40..51cc2167da 100644 --- a/src/main/seq.c +++ b/src/main/seq.c @@ -1,6 +1,6 @@ /* * R : A Computer Language for Statistical Data Analysis - * Copyright (C) 1998-2023 The R Core Team. + * Copyright (C) 1998-2025 The R Core Team. * Copyright (C) 1995-1998 Robert Gentleman and Ross Ihaka * * This program is free software; you can redistribute it and/or modify @@ -109,7 +109,7 @@ static SEXP seq_colon(double n1, double n2, SEXP call) Rboolean useInt = (n1 <= INT_MAX) && (n1 == (int) n1); if(useInt) { - if(n1 <= INT_MIN || n1 > INT_MAX) + if(n1 <= INT_MIN) /* know n1 <= INT_MAX */ useInt = FALSE; else { /* r := " the effective 'to' " of from:to */ @@ -787,11 +787,12 @@ attribute_hidden SEXP do_rep(SEXP call, SEXP op, SEXP args, SEXP rho) /* - This is a primitive SPECIALSXP with internal argument matching, - implementing seq.int(). + This is a primitive SPECIALSXP with internal argument matching, implementing - 'along' has to be used on an unevaluated argument, and evalList - tries to evaluate language objects. + seq.int(from, to, by, length.out, along.with, ...) + + 'along' has to be used on an unevaluated argument, and evalList + tries to evaluate language objects. */ #define FEPS 1e-10 /* to match seq.default */ @@ -832,7 +833,7 @@ attribute_hidden SEXP do_seq(SEXP call, SEXP op, SEXP args, SEXP rho) errorcall(call, _("'%s' must be a finite number"), "from"); ans = seq_colon(1.0, rfrom, call); } - else if (lf) + else if (lf) // typically seq() , length() >= 2 ans = seq_colon(1.0, (double)lf, call); else ans = allocVector(INTSXP, 0); @@ -884,13 +885,16 @@ attribute_hidden SEXP do_seq(SEXP call, SEXP op, SEXP args, SEXP rho) ans = to; // is *not* missing in this case goto done; } - double n, rby = asReal(by); - Rboolean finite_del = R_FINITE(del); - if(finite_del) { - n = del/rby; - } else { // overflow in (to - from) when both are finite - n = rto/rby - rfrom/rby; + double rby = asReal(by); + if((rby == 1. && del > 0.) || + (rby == -1. && del < 0.)) { // --> treat as if missing (return integer) + ans = seq_colon(rfrom, rto, call); + goto done; } + Rboolean finite_del = R_FINITE(del); + double n = (finite_del) + ? del/rby + : rto/rby - rfrom/rby; /* overflow in (to - from) when both are finite */ if(!R_FINITE(n)) { if(del == 0.0 && rby == 0.0) { ans = miss_from ? ScalarReal(rfrom) : from; @@ -1047,7 +1051,7 @@ attribute_hidden SEXP do_seq(SEXP call, SEXP op, SEXP args, SEXP rho) done: UNPROTECT(1); return ans; -} +} // do_seq() attribute_hidden SEXP do_seq_along(SEXP call, SEXP op, SEXP args, SEXP rho) { diff --git a/tests/reg-tests-1d.R b/tests/reg-tests-1d.R index d67f0ada07..d6800b5a28 100644 --- a/tests/reg-tests-1d.R +++ b/tests/reg-tests-1d.R @@ -644,7 +644,7 @@ stopifnot(exprs = { ## had failed in R-devel for a few days D1 <- as.Date("2017-01-06") D2 <- as.Date("2017-01-12") -seqD1 <- seq.Date(D1, D2, by = "1 day") +seqD1 <- seq(D1, D2, by = "1 day") stopifnot(exprs = { identical(seqD1, seq(D1, D2)) # by = "days" implicit default since R >= 4.5 identical(seqD1, seq(D1, D2, by = "1 days"))