Skip to content

Commit

Permalink
Improve int64 coercion behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
hadley committed Oct 23, 2024
1 parent 89c68fb commit 2c95a28
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 9 deletions.
23 changes: 17 additions & 6 deletions R/num_equal.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ num_equal <- function(x, y, tolerance = default_tol()) {
}

if (is_int64(x) || is_int64(y)) {
in_range <-
(!is.double(x) || all((x >= 2^63 & x <= 2^63 - 1) | is.na(x))) &&
(!is.double(y) || all((y >= 2^63 & y <= 2^63 - 1) | is.na(x)))
if (isTRUE(in_range)) {
if (can_int64(x) && can_int64(y)) {
x <- bit64::as.integer64(x)
y <- bit64::as.integer64(y)
} else {
x <- as.double(x)
y <- as.double(y)
cli::cli_abort(c(
"No way to coerce to compatible numeric type.",
i = "Try again without setting `tolerance`."
))
}
} else {
attributes(x) <- NULL
Expand All @@ -46,3 +45,15 @@ num_equal <- function(x, y, tolerance = default_tol()) {

avg_diff < tolerance
}


can_int64 <- function(x) {
if (is.integer(x) || inherits(x, "int64")) {
return(TRUE)
}

in_range <- x >= -2^53 & x <= 2^53 - 1
is_whole <- trunc(x) == x
is_missing <- is.na(x)
all((in_range & is_whole) | is_missing)
}
9 changes: 9 additions & 0 deletions tests/testthat/_snaps/num_equal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# can't can't compare large integers

Code
num_equal(9007199254740992, bit64::as.integer64(1))
Condition
Error in `num_equal()`:
! No way to coerce to compatible numeric type.
i Try again without setting `tolerance`.

9 changes: 6 additions & 3 deletions tests/testthat/test-num_equal.R
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ test_that("NaN is equal to NA_real_ unless tolerance is NULL", {
expect_true(num_equal(NA_real_, NA_real_))
})

test_that("coerce large integers to doubles not int64", {
expect_no_warning(num_equal(36893488147419103232, bit64::as.integer64(1)))
expect_no_warning(num_equal(bit64::as.integer64(1), 36893488147419103232))
test_that("can't can't compare large integers", {
expect_snapshot(
num_equal(9007199254740992, bit64::as.integer64(1)),
error = TRUE
)
expect_false(num_equal(9007199254740991, bit64::as.integer64(1)))

expect_no_error(num_equal(NA, bit64::as.integer64(1)))
expect_no_error(num_equal(bit64::as.integer64(1), NA))
Expand Down

0 comments on commit 2c95a28

Please sign in to comment.