Skip to content

between() gives wrong answers for some integer64 inputs #7164

@aitap

Description

@aitap

# Minimal reproducible example

Let's take these two perfectly normal (if somewhat large) 64-bit integers:

library(bit64)
a <- as.integer64('4630967054332067840')
b <- as.integer64('4631248529308778496')

...and test whether another integer lies between them:

library(data.table)
between(42L, a, b)
# [1] TRUE

That doesn't seem right.

When interpreted as doubles, these numbers turn out to be small integers:

unclass(c(a,b))
# [1] 41 43

...and so they pass the test for within_int32_repres(REAL(x)[i]):

data.table/src/utils.c

Lines 20 to 23 in 2f0d12f

const double *dx = REAL(x);
while (i<n &&
( ISNA(dx[i]) ||
(within_int32_repres(dx[i]) && dx[i]==(int)(dx[i])))) {

...which is enough to have them converted to integers, ignoring the integer64 class:

data.table/src/between.c

Lines 33 to 39 in 2f0d12f

if ((isInteger(lower) || fitsInInt32(lower)) &&
(isInteger(upper) || fitsInInt32(upper))) { // #3517 coerce to num to int when possible
if (!isInteger(lower)) {
lower = PROTECT(coerceVector(lower, INTSXP)); nprotect++;
}
if (!isInteger(upper)) {
upper = PROTECT(coerceVector(upper, INTSXP)); nprotect++;

Should fitsInInt32 return false when its argument inherits from integer64?

# Output of sessionInfo()

R Under development (unstable) (2025-07-11 r88405)
Platform: x86_64-pc-linux-gnu
Running under: Debian GNU/Linux 12 (bookworm)

Matrix products: default
BLAS/LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.21.so;  LAPACK version 3.11.0

locale:
 [1] LC_CTYPE=ru_RU.UTF-8       LC_NUMERIC=C
 [3] LC_TIME=ru_RU.UTF-8        LC_COLLATE=ru_RU.UTF-8
 [5] LC_MONETARY=ru_RU.UTF-8    LC_MESSAGES=ru_RU.UTF-8
 [7] LC_PAPER=ru_RU.UTF-8       LC_NAME=C
 [9] LC_ADDRESS=C               LC_TELEPHONE=C
[11] LC_MEASUREMENT=ru_RU.UTF-8 LC_IDENTIFICATION=C

time zone: Europe/Moscow
tzcode source: system (glibc)

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

other attached packages:
[1] data.table_1.17.99 bit64_4.6.0-1      bit_4.6.0

loaded via a namespace (and not attached):
[1] compiler_4.6.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions