From c4904e3b9d436215e0cc88934d06b9149823dc14 Mon Sep 17 00:00:00 2001 From: Bojidar Marinov Date: Tue, 8 Jul 2025 14:40:43 +0300 Subject: [PATCH 1/2] Write chunks with negative zero values and a zero fill value Fixes #3144 --- changes/3144.bugfix.rst | 1 + src/zarr/core/buffer/core.py | 6 ++++++ tests/test_array.py | 24 ++++++++++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 changes/3144.bugfix.rst diff --git a/changes/3144.bugfix.rst b/changes/3144.bugfix.rst new file mode 100644 index 0000000000..d640d4f162 --- /dev/null +++ b/changes/3144.bugfix.rst @@ -0,0 +1 @@ +For arrays with ``config={"write_empty_chunks: False}`` and ``fill_value=0.0`` (default), chunks containing negative zeroes are written out. diff --git a/src/zarr/core/buffer/core.py b/src/zarr/core/buffer/core.py index 19125b838f..89e34f82d0 100644 --- a/src/zarr/core/buffer/core.py +++ b/src/zarr/core/buffer/core.py @@ -523,6 +523,12 @@ def all_equal(self, other: Any, equal_nan: bool = True) -> bool: if other is None: # Handle None fill_value for Zarr V2 return False + if other == 0.0 and self._data.dtype.kind not in ("U", "S", "T", "O", "V"): + # Handle positive and negative zero + if np.any(self._data): # Check for any truthy value + return False + # Check signs: + return np.array_equiv(np.signbit(self._data), np.signbit(other)) # use array_equal to obtain equal_nan=True functionality # Since fill-value is a scalar, isn't there a faster path than allocating a new array for fill value # every single time we have to write data? diff --git a/tests/test_array.py b/tests/test_array.py index fe23bc1284..e16acc1b36 100644 --- a/tests/test_array.py +++ b/tests/test_array.py @@ -904,6 +904,30 @@ def test_write_empty_chunks_behavior( assert arr.nchunks_initialized == arr.nchunks +@pytest.mark.parametrize("store", ["memory"], indirect=True) +@pytest.mark.parametrize("fill_value", [0.0, -0.0]) +def test_write_empty_chunks_negative_zero( + zarr_format: ZarrFormat, store: MemoryStore, fill_value: float +) -> None: + # regression test for https://github.com/zarr-developers/zarr-python/issues/3144 + + arr = zarr.create_array( + store=store, + shape=(2,), + zarr_format=zarr_format, + dtype="f4", + fill_value=fill_value, + chunks=(1,), + config={"write_empty_chunks": False}, + ) + + assert arr.nchunks_initialized == 0 + + # initialize the with the negated fill value (-0.0 for +0.0, +0.0 for -0.0) + arr[:] = -fill_value + assert arr.nchunks_initialized == arr.nchunks + + @pytest.mark.parametrize( ("fill_value", "expected"), [ From 3f8c84fd99163abdc37a76481f9efeb6aa428c28 Mon Sep 17 00:00:00 2001 From: Davis Bennett Date: Wed, 9 Jul 2025 17:01:51 +0200 Subject: [PATCH 2/2] Update changes/3144.bugfix.rst --- changes/3144.bugfix.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changes/3144.bugfix.rst b/changes/3144.bugfix.rst index d640d4f162..8dde317bb8 100644 --- a/changes/3144.bugfix.rst +++ b/changes/3144.bugfix.rst @@ -1 +1 @@ -For arrays with ``config={"write_empty_chunks: False}`` and ``fill_value=0.0`` (default), chunks containing negative zeroes are written out. +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.```