Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
137 changes: 60 additions & 77 deletions src/integer64.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# C-Code
# S3 atomic 64bit integers for R
# (c) 2011-2024 Jens Oehlschägel
# (c) 2025 Michael Chirico
# (c) 2025-2026 Michael Chirico
# Licence: GPL2
# Provided 'as is', use at your own risk
# Created: 2011-12-11
Expand Down Expand Up @@ -227,11 +227,13 @@ SEXP as_integer64_bitstring(SEXP x_, SEXP ret_){
for(i=0; i<n; i++){
str = CHAR(STRING_ELT(x_, i));
l = strlen(str);
if (l>BITS_INTEGER64){
// # nocov start: only reachable with invalid bitstring input
if (l > BITS_INTEGER64){
ret[i] = NA_INTEGER64;
naflag = TRUE;
break;
}
// # nocov end
mask = 1;
v = 0;
for (k=l-1; k>=0; k--){
Expand All @@ -243,13 +245,13 @@ SEXP as_integer64_bitstring(SEXP x_, SEXP ret_){
ret[i] = v;
R_CheckUserInterrupt();
}
if (naflag)warning(BITSTRING_OVERFLOW_WARNING);
if (naflag)warning(BITSTRING_OVERFLOW_WARNING); // # nocov
return ret_;
}



__attribute__((no_sanitize("signed-integer-overflow"))) SEXP plus_integer64(SEXP e1_, SEXP e2_, SEXP ret_){
SEXP plus_integer64(SEXP e1_, SEXP e2_, SEXP ret_){
long long i, n = LENGTH(ret_);
long long i1, n1 = LENGTH(e1_);
long long i2, n2 = LENGTH(e2_);
Expand All @@ -264,7 +266,7 @@ __attribute__((no_sanitize("signed-integer-overflow"))) SEXP plus_integer64(SEXP
return ret_;
}

__attribute__((no_sanitize("signed-integer-overflow"))) SEXP minus_integer64(SEXP e1_, SEXP e2_, SEXP ret_){
SEXP minus_integer64(SEXP e1_, SEXP e2_, SEXP ret_){
long long i, n = LENGTH(ret_);
long long i1, n1 = LENGTH(e1_);
long long i2, n2 = LENGTH(e2_);
Expand All @@ -279,7 +281,7 @@ __attribute__((no_sanitize("signed-integer-overflow"))) SEXP minus_integer64(SEX
return ret_;
}

__attribute__((no_sanitize("signed-integer-overflow"))) SEXP diff_integer64(SEXP x_, SEXP lag_, SEXP n_, SEXP ret_){
SEXP diff_integer64(SEXP x_, SEXP lag_, SEXP n_, SEXP ret_){
long long i, n = *((long long *) REAL(n_));
long long * x = (long long *) REAL(x_);
long long * lag = (long long *) REAL(lag_);
Expand Down Expand Up @@ -326,7 +328,7 @@ SEXP mod_integer64(SEXP e1_, SEXP e2_, SEXP ret_){
}


__attribute__((no_sanitize("signed-integer-overflow"))) SEXP times_integer64_integer64(SEXP e1_, SEXP e2_, SEXP ret_){
SEXP times_integer64_integer64(SEXP e1_, SEXP e2_, SEXP ret_){
long long i, n = LENGTH(ret_);
long long i1, n1 = LENGTH(e1_);
long long i2, n2 = LENGTH(e2_);
Expand Down Expand Up @@ -612,36 +614,31 @@ SEXP sum_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_);
long long cumsum, tempsum;
cumsum = 0;
if (asLogical(na_rm_)){
for(i=0; i<n; i++){
if (e1[i]!=NA_INTEGER64){
tempsum = cumsum + e1[i];
if (!GOODISUM64(cumsum, e1[i], tempsum)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
cumsum = tempsum;
}
long long cumsum = 0;
if (asLogical(na_rm_)){
for(i=0; i<n; i++){
if (e1[i]!=NA_INTEGER64){
if (add64_overflow(cumsum, e1[i], &cumsum)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
}else{
for(i=0; i<n; i++){
if (e1[i]==NA_INTEGER64){
ret[0] = NA_INTEGER64;
return ret_;
}else{
tempsum = cumsum + e1[i];
if (!GOODISUM64(cumsum, e1[i], tempsum)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
cumsum = tempsum;
}
}
}
}else{
for(i=0; i<n; i++){
if (e1[i]==NA_INTEGER64){
ret[0] = NA_INTEGER64;
return ret_;
}else{
if (add64_overflow(cumsum, e1[i], &cumsum)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
}
}
}
ret[0] = cumsum;
return ret_;
}
Expand Down Expand Up @@ -678,36 +675,31 @@ SEXP prod_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_);
long long cumprod, tempprod;
cumprod = 1;
if (asLogical(na_rm_)){
for(i=0; i<n; i++){
if (e1[i]!=NA_INTEGER64){
tempprod = cumprod * e1[i];
if (!GOODIPROD64(cumprod, e1[i], tempprod)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
cumprod = tempprod;
}
long long cumprod = 1;
if (asLogical(na_rm_)){
for(i=0; i<n; i++){
if (e1[i]!=NA_INTEGER64){
if (mul64_overflow(cumprod, e1[i], &cumprod)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
}else{
for(i=0; i<n; i++){
if (e1[i]==NA_INTEGER64){
ret[0] = NA_INTEGER64;
return ret_;
}else{
tempprod = cumprod * e1[i];
if (!GOODIPROD64(cumprod, e1[i], tempprod)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
cumprod = tempprod;
}
}
}
}else{
for(i=0; i<n; i++){
if (e1[i]==NA_INTEGER64){
ret[0] = NA_INTEGER64;
return ret_;
}else{
if (mul64_overflow(cumprod, e1[i], &cumprod)){
warning(INTEGER64_OVERFLOW_WARNING);
ret[0] = NA_INTEGER64;
return ret_;
}
}
}
}
ret[0] = cumprod;
return ret_;
}
Expand Down Expand Up @@ -1065,7 +1057,7 @@ SEXP as_list_integer64(SEXP x_){
return x_;
}

__attribute__((no_sanitize("signed-integer-overflow"))) SEXP matmult_integer64_integer64(SEXP x_, SEXP y_, SEXP ret_){
SEXP matmult_integer64_integer64(SEXP x_, SEXP y_, SEXP ret_){
long long i, j, k;
// get dimension of x
SEXP dim1 = getAttrib(x_, R_DimSymbol);
Expand All @@ -1080,7 +1072,7 @@ __attribute__((no_sanitize("signed-integer-overflow"))) SEXP matmult_integer64_i
long long * y = (long long *) REAL(y_);
long long * ret = (long long *) REAL(ret_);
Rboolean naflag = FALSE;
long long cumsum, tempsum, addValue;
long long cumsum, addValue;

for(i=0; i<nrow1; i++){
for(j=0; j<ncol2; j++){
Expand All @@ -1091,16 +1083,11 @@ __attribute__((no_sanitize("signed-integer-overflow"))) SEXP matmult_integer64_i
cumsum = NA_INTEGER64;
break;
}
tempsum = cumsum + addValue;
// for some reason GOODISUM64(cumsum, addValue, tempsum) does not work properly on macos-latest, compared to the others
// therefore a workaround is tried here by adding the GOODISUM64 logic with long double casting
if(!GOODISUM64(cumsum, addValue, tempsum) ||
!((cumsum > 0) ? (((long double) addValue) < ((long double) tempsum)) : ! (((long double) addValue) < ((long double) tempsum)))){
if(add64_overflow(cumsum, addValue, &cumsum)){
naflag = TRUE;
cumsum = NA_INTEGER64;
break;
}
cumsum = tempsum;
}
ret[i + j*nrow1] = cumsum;
}
Expand All @@ -1125,7 +1112,7 @@ SEXP matmult_double_integer64(SEXP x_, SEXP y_, SEXP ret_){
long long * y = (long long *) REAL(y_);
long long * ret = (long long *) REAL(ret_);
Rboolean naflag = FALSE;
long long cumsum, tempsum, addValue;
long long cumsum, addValue;
long double longret;

for(i=0; i<nrow1; i++){
Expand All @@ -1137,13 +1124,11 @@ SEXP matmult_double_integer64(SEXP x_, SEXP y_, SEXP ret_){
cumsum = NA_INTEGER64;
break;
}
tempsum = cumsum + addValue;
if(!GOODISUM64(cumsum, addValue, tempsum)){
if(add64_overflow(cumsum, addValue, &cumsum)){
naflag = TRUE;
cumsum = NA_INTEGER64;
break;
}
cumsum = tempsum;
}
ret[i + j*nrow1] = cumsum;
}
Expand All @@ -1167,7 +1152,7 @@ SEXP matmult_integer64_double(SEXP x_, SEXP y_, SEXP ret_){
double * y = REAL(y_);
long long * ret = (long long *) REAL(ret_);
Rboolean naflag = FALSE;
long long cumsum, tempsum, addValue;
long long cumsum, addValue;
long double longret;

for(i=0; i<nrow1; i++){
Expand All @@ -1179,13 +1164,11 @@ SEXP matmult_integer64_double(SEXP x_, SEXP y_, SEXP ret_){
cumsum = NA_INTEGER64;
break;
}
tempsum = cumsum + addValue;
if(!GOODISUM64(cumsum, addValue, tempsum)){
if(add64_overflow(cumsum, addValue, &cumsum)){
naflag = TRUE;
cumsum = NA_INTEGER64;
break;
}
cumsum = tempsum;
}
ret[i + j*nrow1] = cumsum;
}
Expand Down
Loading
Loading