Describe the bug
_resolve_nodata in xrspatial/resample.py (line 1148) casts the nodata sentinel through float(), then _apply_nodata_mask (line 1168) compares the data array against that float. For int64 values above 2**53 the cast is lossy, so distinct integers collide after rounding and valid cells get masked to NaN.
Repro
import numpy as np
import xarray as xr
from xrspatial import resample
# nodata = 2**60 + 1, valid cell at 2**60 are distinct in int64.
nodata = (1 << 60) + 1
data = np.full((4, 4), nodata, dtype=np.int64)
data[1, 1] = 1 << 60 # valid value, not nodata
agg = xr.DataArray(data, dims=('y', 'x'))
out = resample(agg, scale_factor=1.0, method='nearest', nodata=nodata)
# The valid 2**60 cell comes back as NaN because float(2**60+1) == 2**60.
print(out.values[1, 1]) # nan, even though the input was valid
Expected behavior
The cell holding 2**60 should survive masking. Only cells whose integer value equals the sentinel 2**60 + 1 should become NaN.
Additional context
The float round-trip drops the low bits whenever the magnitude exceeds 2**53 (the float64 mantissa width). Fix: keep the sentinel in the input's native dtype when the input is integer, and only cast through float for floating-point inputs (where NaN semantics matter). The masking helper feeds every backend (numpy / cupy / dask+numpy / dask+cupy), so the change lives in one place.
Describe the bug
_resolve_nodatainxrspatial/resample.py(line 1148) casts the nodata sentinel throughfloat(), then_apply_nodata_mask(line 1168) compares the data array against that float. For int64 values above 2**53 the cast is lossy, so distinct integers collide after rounding and valid cells get masked to NaN.Repro
Expected behavior
The cell holding
2**60should survive masking. Only cells whose integer value equals the sentinel2**60 + 1should become NaN.Additional context
The float round-trip drops the low bits whenever the magnitude exceeds 2**53 (the float64 mantissa width). Fix: keep the sentinel in the input's native dtype when the input is integer, and only cast through float for floating-point inputs (where NaN semantics matter). The masking helper feeds every backend (numpy / cupy / dask+numpy / dask+cupy), so the change lives in one place.