Skip to content

Commit 1264a4d

Browse files
bojidar-bgd-v-b
andauthored
Write chunks with negative zero values and a zero fill value (#3216)
* Write chunks with negative zero values and a zero fill value Fixes #3144 * Update changes/3144.bugfix.rst * Use bit patterns for comparing zeroes instead of signbit Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com> * fixup: Make sure fill value is a float before checking if it's == 0 * fixup: Make sure we don't copy arrays as we check for zeroes * Attempt using structured void dtypes for CuPy --------- Co-authored-by: Davis Bennett <davis.v.bennett@gmail.com>
1 parent f087c56 commit 1264a4d

File tree

3 files changed

+34
-0
lines changed

3 files changed

+34
-0
lines changed

changes/3144.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Ensure that -0.0 is not considered equal to 0.0 when checking if all the values in a chunk are equal to an array's fill value.```

src/zarr/core/buffer/core.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,15 @@ def all_equal(self, other: Any, equal_nan: bool = True) -> bool:
523523
if other is None:
524524
# Handle None fill_value for Zarr V2
525525
return False
526+
# Handle positive and negative zero by comparing bit patterns:
527+
if (
528+
np.asarray(other).dtype.kind == "f"
529+
and other == 0.0
530+
and self._data.dtype.kind not in ("U", "S", "T", "O", "V")
531+
):
532+
_data, other = np.broadcast_arrays(self._data, np.asarray(other, self._data.dtype))
533+
void_dtype = "V" + str(_data.dtype.itemsize)
534+
return np.array_equal(_data.view(void_dtype), other.view(void_dtype))
526535
# use array_equal to obtain equal_nan=True functionality
527536
# Since fill-value is a scalar, isn't there a faster path than allocating a new array for fill value
528537
# every single time we have to write data?

tests/test_array.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,30 @@ def test_write_empty_chunks_behavior(
870870
assert arr.nchunks_initialized == arr.nchunks
871871

872872

873+
@pytest.mark.parametrize("store", ["memory"], indirect=True)
874+
@pytest.mark.parametrize("fill_value", [0.0, -0.0])
875+
@pytest.mark.parametrize("dtype", ["f4", "f2"])
876+
def test_write_empty_chunks_negative_zero(
877+
zarr_format: ZarrFormat, store: MemoryStore, fill_value: float, dtype: str
878+
) -> None:
879+
# regression test for https://github.com/zarr-developers/zarr-python/issues/3144
880+
881+
arr = zarr.create_array(
882+
store=store,
883+
shape=(2,),
884+
zarr_format=zarr_format,
885+
dtype=dtype,
886+
fill_value=fill_value,
887+
chunks=(1,),
888+
config={"write_empty_chunks": False},
889+
)
890+
assert arr.nchunks_initialized == 0
891+
892+
# initialize the with the negated fill value (-0.0 for +0.0, +0.0 for -0.0)
893+
arr[:] = -fill_value
894+
assert arr.nchunks_initialized == arr.nchunks
895+
896+
873897
@pytest.mark.parametrize(
874898
("fill_value", "expected"),
875899
[

0 commit comments

Comments
 (0)