Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3afc6f0
range() wrong for multiple inputs if one is non-finite (#142)
hcirellu Oct 15, 2025
d4bbefd
range() wrong for multiple inputs if one is non-finite (#142)
hcirellu Oct 15, 2025
cce1548
Merge branch 'main' of https://github.com/hcirellu/bit64
hcirellu Oct 15, 2025
bee2094
typos in documentation
hcirellu Oct 15, 2025
c7a7489
minor fix and adding of regression tests
hcirellu Oct 15, 2025
66b692f
bug fix, not NOTE
MichaelChirico Oct 15, 2025
01cc808
fixed tests in test-bit64-package regarding min, max, range
hcirellu Oct 16, 2025
72d1f80
#include <stdbool.h>
hcirellu Oct 16, 2025
0b19ba9
typos fix applied to man pages
hcirellu Oct 19, 2025
5f2fda9
re-use variable
MichaelChirico Oct 21, 2025
087c994
Use a helper for complex condition
MichaelChirico Oct 21, 2025
5d88d3a
missing na.rm
MichaelChirico Oct 22, 2025
66ed2d3
save unnecessary calls of helper
hcirellu Oct 22, 2025
694f437
added allNA() and anyNA()
hcirellu Oct 23, 2025
85591b8
missing parameter recursive
hcirellu Oct 23, 2025
19da38c
do not export allNA
hcirellu Oct 29, 2025
bf15e4c
bit64.dev -> bit64
hcirellu Oct 29, 2025
83eec36
remove helper empty_or_all_na_values_with_naRm and use allNA directly
hcirellu Oct 30, 2025
32fb764
reintroduce `empty_or_all_na_with_naRm()`
hcirellu Oct 30, 2025
6c1cff6
reintroduce `empty_or_all_na_with_naRm()`
hcirellu Oct 30, 2025
50b08bf
Merge branch 'main' of https://github.com/hcirellu/bit64
hcirellu Oct 30, 2025
5906f33
`allNA(<empty>)` must be `TRUE`
hcirellu Oct 31, 2025
46c1969
simplify & rename
MichaelChirico Nov 7, 2025
0bf43ca
map the name to the variable even more tightly
MichaelChirico Nov 7, 2025
ccceb70
refine NEWS
MichaelChirico Nov 7, 2025
c011895
friendlier whitespace in tests
MichaelChirico Nov 7, 2025
05304fb
remove private API tests
MichaelChirico Nov 7, 2025
8176d12
reorganize slightly
MichaelChirico Nov 7, 2025
14faac4
more thoroughly reorganize tests
MichaelChirico Nov 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ S3method(as.integer64,integer64)
S3method(as.integer64,logical)
S3method(as.list,integer64)
S3method(as.logical,integer64)
S3method(base::anyNA,integer64)
S3method(c,integer64)
S3method(cbind,integer64)
S3method(ceiling,integer64)
Expand Down
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
Because there was no recorded direct usage for any of these, I am opting to just rip the band-aid
off and un-export them in this release as opposed to waiting a full cycle more to do so.

## NEW FEATURES

1. `anyNA` gets an `integer64` method. Thanks @hcirellu.

## BUG FIXES

1. `min.integer64`, `max.integer64` and `range.integer64` now support `na.rm=TRUE` correctly when combining across mutliple inputs like `min(x, NA_integer64_, na.rm=TRUE)` (#142).

## NOTES

1. {bit64} no longer prints any start-up messages through an `.onAttach()` hook (#106). Thanks @hadley for the request.
Expand Down
113 changes: 87 additions & 26 deletions R/integer64.R
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ NULL
#'
#' @examples
#' c(as.integer64(1), 2:6)
#' cbind(1:6, as.integer(1:6))
#' rbind(1:6, as.integer(1:6))
#' cbind(1:6, as.integer64(1:6))
#' rbind(1:6, as.integer64(1:6))
#' @name c.integer64
NULL

Expand All @@ -305,7 +305,7 @@ NULL
#'
#' Generating sequence of integer64 values
#'
#' @param from integer64 scalar (in order to dispatch the integer64 method of [seq()]
#' @param from integer64 scalar (in order to dispatch the integer64 method of [seq()])
Comment thread
MichaelChirico marked this conversation as resolved.
#' @param to scalar
#' @param by scalar
#' @param length.out scalar
Expand Down Expand Up @@ -1387,74 +1387,129 @@ prod.integer64 <- function(..., na.rm=FALSE) {
}
}

# not exactly analogous to anyNA, but convenient for min/max/range
has_no_values = function(x, na.rm) {
if (!length(x)) return(TRUE)
if (!na.rm) return(FALSE)
if (is.integer64(x)) {
.Call(C_r_ram_integer64_all_na, x=x)
} else {
all(is.na(x))
}
}

#' @rdname sum.integer64
#' @export
min.integer64 = function(..., na.rm=FALSE) {
l = list(...)
na.rm = isTRUE(na.rm)
ret = NULL
no_values = NULL

if (length(l) == 1L) {
ret = .Call(C_min_integer64, l[[1L]], na.rm, double(1L))
oldClass(ret) = "integer64"
if (length(l[[1]]) > 0L) {
ret = .Call(C_min_integer64, l[[1L]], na.rm, double(1L))
oldClass(ret) = "integer64"
}
} else {
ret = vapply(l, FUN.VALUE=integer64(1L), function(e) {
ret = vapply(Filter(length, l), FUN.VALUE=integer64(1L), function(e) {
if (is.integer64(e)) {
.Call(C_min_integer64, e, na.rm, double(1L))
} else {
as.integer64(min(e, na.rm=na.rm))
suppressWarnings(as.integer64(min(e, na.rm=na.rm)))
}
})
oldClass(ret) = "integer64"
ret = min(ret, na.rm=na.rm)
no_values = has_no_values(ret, na.rm)
if (!no_values) {
ret = min(ret, na.rm=na.rm)
no_values = NULL
}
}
if (is.null(no_values))
no_values = has_no_values(ret, na.rm)
if (no_values) {
ret = lim.integer64()[2L]
warning("no non-NA value, returning the highest possible integer64 value +", ret)
}
if (!any(lengths(l)))
warning("no non-NA value, returning the highest possible integer64 value +", lim.integer64()[2L])
ret
}

#' @rdname sum.integer64
#' @export
max.integer64 = function(..., na.rm=FALSE) {
l = list(...)
na.rm = isTRUE(na.rm)
ret = NULL
no_values = NULL

if (length(l) == 1L) {
ret = .Call(C_max_integer64, l[[1L]], na.rm, double(1L))
oldClass(ret) = "integer64"
if (length(l[[1]]) > 0L) {
ret = .Call(C_max_integer64, l[[1L]], na.rm, double(1L))
oldClass(ret) = "integer64"
}
} else {
ret <- vapply(l, FUN.VALUE=integer64(1L), function(e) {
ret = vapply(Filter(length, l), FUN.VALUE=integer64(1L), function(e) {
if (is.integer64(e)) {
.Call(C_max_integer64, e, na.rm, double(1L))
} else {
as.integer64(max(e, na.rm=na.rm))
suppressWarnings(as.integer64(max(e, na.rm=na.rm)))
}
})
oldClass(ret) = "integer64"
ret = max(ret, na.rm=na.rm)
no_values = has_no_values(ret, na.rm)
if (!no_values) {
ret = max(ret, na.rm=na.rm)
no_values = NULL
}
}
if (is.null(no_values))
no_values = has_no_values(ret, na.rm)
if (no_values) {
ret = lim.integer64()[1L]
warning("no non-NA value, returning the lowest possible integer64 value ", ret)
}
if (!any(lengths(l)))
warning("no non-NA value, returning the lowest possible integer64 value ", lim.integer64()[1L])
ret
}

#' @rdname sum.integer64
#' @export
range.integer64 = function(..., na.rm=FALSE, finite=FALSE) {
if (finite)
l = list(...)
if (isTRUE(finite)) {
na.rm = TRUE
l <- list(...)
} else {
na.rm = isTRUE(na.rm)
}
ret = NULL
no_values = NULL

if (length(l) == 1L) {
ret = .Call(C_range_integer64, l[[1L]], na.rm, double(2L))
oldClass(ret) = "integer64"
if (length(l[[1]]) > 0L) {
ret = .Call(C_range_integer64, l[[1L]], na.rm, double(2L))
oldClass(ret) = "integer64"
}
} else {
ret <- vapply(l, FUN.VALUE=integer64(2L), function(e) {
ret = vapply(Filter(length, l), FUN.VALUE=integer64(2L), function(e) {
if (is.integer64(e)) {
.Call(C_range_integer64, e, na.rm, double(2L))
} else {
as.integer64(range(e, na.rm=na.rm))
suppressWarnings(as.integer64(range(e, na.rm=na.rm)))
}
})
oldClass(ret) = "integer64"
ret = range(ret, na.rm=na.rm)
no_values = has_no_values(ret, na.rm)
if (!no_values) {
ret = range(ret, na.rm=na.rm)
no_values = NULL
}
}
if (is.null(no_values))
no_values = has_no_values(ret, na.rm)
if (no_values) {
ret = c(lim.integer64()[2L], lim.integer64()[1L])
warning("no non-NA value, returning c(+", ret[1L], ", ", ret[2L], ")")
}
if (!any(lengths(l)))
warning("no non-NA value, returning c(+", lim.integer64()[2L], ", ", lim.integer64()[1L], ")")
ret
}

Expand Down Expand Up @@ -1704,3 +1759,9 @@ as.list.integer64 <- function(x, ...) {
ret <- NextMethod("as.list", x, ...)
.Call(C_as_list_integer64, ret)
}


#' @exportS3Method base::anyNA integer64
anyNA.integer64 = function(x, recursive) {
.Call(C_r_ram_integer64_any_na, x=x)
}
4 changes: 2 additions & 2 deletions man/c.integer64.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/seq.integer64.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ extern SEXP r_ram_integer64_issorted_asc(SEXP);
extern SEXP r_ram_integer64_mergeorder(SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP r_ram_integer64_mergesort(SEXP, SEXP, SEXP, SEXP);
extern SEXP r_ram_integer64_mergesortorder(SEXP, SEXP, SEXP, SEXP, SEXP);
extern SEXP r_ram_integer64_all_na(SEXP);
extern SEXP r_ram_integer64_any_na(SEXP);
extern SEXP r_ram_integer64_nacount(SEXP);
extern SEXP r_ram_integer64_orderdup_asc(SEXP, SEXP, SEXP, SEXP);
extern SEXP r_ram_integer64_orderfin_asc(SEXP, SEXP, SEXP, SEXP, SEXP);
Expand Down Expand Up @@ -180,6 +182,8 @@ static const R_CallMethodDef CallEntries[] = {
{"r_ram_integer64_mergeorder", (DL_FUNC) &r_ram_integer64_mergeorder, 5},
{"r_ram_integer64_mergesort", (DL_FUNC) &r_ram_integer64_mergesort, 4},
{"r_ram_integer64_mergesortorder", (DL_FUNC) &r_ram_integer64_mergesortorder, 5},
{"r_ram_integer64_all_na", (DL_FUNC) &r_ram_integer64_all_na, 1},
{"r_ram_integer64_any_na", (DL_FUNC) &r_ram_integer64_any_na, 1},
{"r_ram_integer64_nacount", (DL_FUNC) &r_ram_integer64_nacount, 1},
{"r_ram_integer64_orderdup_asc", (DL_FUNC) &r_ram_integer64_orderdup_asc, 4},
{"r_ram_integer64_orderfin_asc", (DL_FUNC) &r_ram_integer64_orderfin_asc, 5},
Expand Down
32 changes: 28 additions & 4 deletions src/integer64.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <math.h> // floor
#include <stdint.h>
#include <stdlib.h> // strtoll
#include <stdbool.h> // for boolean

#include <R.h>
#include <Rdefines.h>
Expand Down Expand Up @@ -680,61 +681,79 @@ SEXP min_integer64(SEXP e1_, SEXP na_rm_, SEXP ret_){
long long i, n = LENGTH(e1_);
long long * e1 = (long long *) REAL(e1_);
long long * ret = (long long *) REAL(ret_);
bool onlyNas = true;
ret[0] = MAX_INTEGER64;
if (asLogical(na_rm_)){
for(i=0; i<n; i++){
if (e1[i]!=NA_INTEGER64 && e1[i]<ret[0]){
if (e1[i]!=NA_INTEGER64){
onlyNas = false;
if (e1[i]<ret[0]){
ret[0] = e1[i];
}
}
}
}
}else{
for(i=0; i<n; i++){
if (e1[i]==NA_INTEGER64){
ret[0] = NA_INTEGER64;
return ret_;
}else{
onlyNas = false;
if (e1[i]<ret[0])
ret[0] = e1[i];
}
}
}
if (onlyNas){
ret[0] = NA_INTEGER64;
}
return ret_;
}

SEXP max_integer64(SEXP e1_, SEXP na_rm_, SEXP ret_){
long long i, n = LENGTH(e1_);
long long * e1 = (long long *) REAL(e1_);
long long * ret = (long long *) REAL(ret_);
bool onlyNas = true;
ret[0] = MIN_INTEGER64;
if (asLogical(na_rm_)){
for(i=0; i<n; i++){
if (e1[i]!=NA_INTEGER64 && e1[i]>ret[0]){
if (e1[i]!=NA_INTEGER64){
onlyNas = false;
if (e1[i]>ret[0]){
ret[0] = e1[i];
}
}
}
}
}else{
for(i=0; i<n; i++){
if (e1[i]==NA_INTEGER64){
ret[0] = NA_INTEGER64;
return ret_;
}else{
onlyNas = false;
if (e1[i]>ret[0])
ret[0] = e1[i];
}
}
}
if (onlyNas){
ret[0] = NA_INTEGER64;
}
return ret_;
}

SEXP range_integer64(SEXP e1_, SEXP na_rm_, SEXP ret_){
long long i, n = LENGTH(e1_);
long long * e1 = (long long *) REAL(e1_);
long long * ret = (long long *) REAL(ret_);
bool onlyNas = true;
ret[0] = MAX_INTEGER64;
ret[1] = MIN_INTEGER64;
if (asLogical(na_rm_)){
for(i=0; i<n; i++){
if (e1[i]!=NA_INTEGER64){
onlyNas = false;
if (e1[i]<ret[0])
ret[0] = e1[i];
if (e1[i]>ret[1])
Expand All @@ -747,13 +766,18 @@ SEXP range_integer64(SEXP e1_, SEXP na_rm_, SEXP ret_){
ret[0] = ret[1] = NA_INTEGER64;
return ret_;
}else{
onlyNas = false;
if (e1[i]<ret[0])
ret[0] = e1[i];
if (e1[i]>ret[1])
ret[1] = e1[i];
}
}
}
if (onlyNas){
ret[0] = NA_INTEGER64;
ret[1] = NA_INTEGER64;
}
return ret_;
}

Expand Down
Loading