From 26ea755cad30f6959cff6248dea62550764938fe Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:07:39 +0000 Subject: [PATCH 1/2] Fix rescale() silent divide-by-zero on constant/single-element input rescale(vec, from, upto) computed vec - min(vec), then divided by max(vec) of that shifted vector. For a constant vector (or any single-element vector), the shifted vector is all zeros, so max(vec) is 0, and dividing by it silently produces Inf/NaN for every element instead of an error or a meaningful value - no warning is raised. Fix: detect the zero-range case (max == min) up front and return the midpoint of the target range, (from + upto) / 2, for all non-NA elements instead. This matches the well-established convention used by scales::rescale() for the identical degenerate-input case (verified: scales::rescale(c(5,5,5), to = c(0,100)) returns c(50,50,50)) - using an existing, widely-used package's behavior as the precedent avoids guessing a novel convention for this edge case. Verified: normal (non-degenerate) input is unaffected; constant vectors and single-element vectors now return the range midpoint instead of all-NaN; NA elements are left as NA rather than being assigned the midpoint; a custom target range on constant input scales correctly too. Version bumped 2.8.16 -> 2.8.20 (distinct from sibling PRs #75/#76/#77, which also branch from the same 2.8.16 base and already claimed 2.8.17/2.8.18/2.8.19). --- DESCRIPTION | 2 +- Development/config.R | 2 +- R/CodeAndRoll2.R | 10 ++++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 227f9ee..444ef2d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: CodeAndRoll2 Title: CodeAndRoll2 for vector, matrix and list manipulations -Version: 2.8.16 +Version: 2.8.20 Authors@R: person("Abel", "Vertesy", , "av@imba.oeaw.ac.at", role = c("aut", "cre")) Description: CodeAndRoll2 is a set of more than 170 productivity functions diff --git a/Development/config.R b/Development/config.R index cc4bdcb..8b1745c 100644 --- a/Development/config.R +++ b/Development/config.R @@ -3,7 +3,7 @@ DESCRIPTION <- list( package.name = "CodeAndRoll2", - version = "2.8.16", + version = "2.8.20", title = "CodeAndRoll2 for vector, matrix and list manipulations", description = "CodeAndRoll2 is a set of more than 170 productivity functions for vector, matrix and list manipulations and math. Used by MarkdownReports, ggExpress, SeuratUtils, etc.", diff --git a/R/CodeAndRoll2.R b/R/CodeAndRoll2.R index efafc51..05bc70d 100644 --- a/R/CodeAndRoll2.R +++ b/R/CodeAndRoll2.R @@ -1273,8 +1273,14 @@ translate <- function(vec, old, new) { #' @param upto max, Default: 100 #' @export rescale <- function(vec, from = 0, upto = 100) { - vec <- vec - min(vec, na.rm = TRUE) - vec <- vec * ((upto - from) / max(vec, na.rm = TRUE)) + vmin <- min(vec, na.rm = TRUE) + vmax <- max(vec, na.rm = TRUE) + if (vmax == vmin) { + vec[!is.na(vec)] <- (from + upto) / 2 + return(vec) + } + vec <- vec - vmin + vec <- vec * ((upto - from) / (vmax - vmin)) vec <- vec + from return(vec) } # fun From e386a56546c95810b92e566c8992068e551ecdca Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 07:12:03 +0000 Subject: [PATCH 2/2] Fix overflow in rescale()'s constant-input midpoint calculation The constant-input branch computed (from + upto) / 2, which can overflow to Inf before the division when from and upto are both large finite numbers (e.g. from = 1e308, upto = 1.1e308 - their sum exceeds .Machine$double.xmax, so the "midpoint" was Inf instead of the correct finite 1.05e308). Fix: compute the midpoint as from + (upto - from) / 2 instead - the subtraction of two same-magnitude numbers doesn't overflow, and adding a bounded increment to from doesn't either. Verified: the flagged overflow case now returns the correct finite midpoint (1.05e+308) instead of Inf; normal constant-input and non-degenerate cases are unchanged. --- R/CodeAndRoll2.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/CodeAndRoll2.R b/R/CodeAndRoll2.R index 05bc70d..599dcf7 100644 --- a/R/CodeAndRoll2.R +++ b/R/CodeAndRoll2.R @@ -1276,7 +1276,7 @@ rescale <- function(vec, from = 0, upto = 100) { vmin <- min(vec, na.rm = TRUE) vmax <- max(vec, na.rm = TRUE) if (vmax == vmin) { - vec[!is.na(vec)] <- (from + upto) / 2 + vec[!is.na(vec)] <- from + (upto - from) / 2 return(vec) } vec <- vec - vmin