diff --git a/NEWS.md b/NEWS.md index e6e1d54..938b683 100644 --- a/NEWS.md +++ b/NEWS.md @@ -41,6 +41,8 @@ 1. `as.integer64.integer64` returns a plain `integer64` vector stripped of any attributes. This is consistent with R like behavior, e.g. `as.integer.integer`. +1. `%/%` does not truncate towards zero any more. It now matches R behavior of truncating towards negative infinity. For example, `as.integer64(-10L) %/% as.integer64(7L)` now gives `-2L`, not `-1L`. This is consistent with `-10L %/% 7L` in base R. Consequently, `%%` is also affected, e.g. `as.integer64(-10L) %% as.integer64(7L)` now gives `4L`, not `-3L`, consistent with `-10L %% 7L` in base R. + ## NEW FEATURES 1. `anyNA` gets an `integer64` method. Thanks @hcirellu. diff --git a/src/integer64.h b/src/integer64.h index acda2a7..6f4c40c 100644 --- a/src/integer64.h +++ b/src/integer64.h @@ -165,6 +165,7 @@ else { \ naflag = TRUE; \ } +/* int division truncate to lower */ #define INTDIV64(e1,e2,ret,naflag) \ if (e1 == NA_INTEGER64 || e2 == NA_INTEGER64) \ ret = NA_INTEGER64; \ @@ -175,8 +176,11 @@ else { \ ret = e1 / e2; \ if (ret == NA_INTEGER64) \ naflag = TRUE; \ + else if (ret < 0 && ret*e2 != e1) \ + ret -= 1; \ } +/* int division truncate to lower */ #define MOD64(e1,e2,ret,naflag) \ if (e1 == NA_INTEGER64 || e2 == NA_INTEGER64) \ ret = NA_INTEGER64; \ @@ -187,8 +191,11 @@ else { \ ret = e1 / e2; \ if (ret == NA_INTEGER64) \ naflag = TRUE; \ - else \ + else { \ + if (ret < 0 && ret*e2 != e1) \ + ret -= 1; \ ret = e1 - e2 * ret; \ + } \ } #define MIN64(e1,e2,ret) \ diff --git a/tests/testthat/test-integer64.R b/tests/testthat/test-integer64.R index 93a865c..d483ae3 100644 --- a/tests/testthat/test-integer64.R +++ b/tests/testthat/test-integer64.R @@ -253,7 +253,15 @@ test_that("arithmetic & basic math works", { expect_identical(x %/% 2L, as.integer64(c(0L, 1L, 1L, 2L, 2L, 3L, 3L, 4L, 4L, 5L))) expect_identical(x %% 2L, as.integer64(rep_len(c(1L, 0L), 10L))) - + + x32 = c(10L, 10L, -10L, -10L, 10L, -10L) + y32 = c(3L, -3L, 3L, -3L, 0L, 0L) + x64 = as.integer64(x32) + y64 = as.integer64(y32) + expect_warning(expect_identical(as.integer64(x32) %/% as.integer64(y32), as.integer64(x32 %/% y32)), "NAs produced due to division by zero") + expect_warning(expect_identical(as.integer64(x32) %% as.integer64(y32), as.integer64(x32 %% y32)), "NAs produced due to division by zero") + expect_identical(suppressWarnings((x64%/%y64)*y64 + x64%%y64 == x64), c(rep(TRUE, 4L), rep(NA, 2L))) + expect_identical(sign(x - 6L), as.integer64(rep(c(-1L, 0L, 1L), c(5L, 1L, 4L)))) expect_identical(abs(x - 6.0), as.integer64(c(5:0, 1:4)))