Repository: astropy/astropy

Issue:
Converting float64 to float32 rounds off data in hdu object
Hi,
Why do we round off the data to integers before changing the data type in this line?
https://github.com/astropy/astropy/blob/5f88a0ede0d03cf6329d9d5e0971d540275a8b55/astropy/io/fits/hdu/image.py#L549

To save hardisk space, I wanted to convert my float64 fits images to float32.
I used the `hdulist[0].scale('float32')` method to do that.
However, instead of changing float64 to float32, it rounded off to nearest integer.



Discussion:
github-actions[bot]: Thank you for your contribution to Astropy! 🌌 This checklist is meant to remind the package maintainers who will review this pull request of some common things to look for.

  - [ ] Do the proposed changes actually accomplish desired goals?
  - [ ] Do the proposed changes follow the [Astropy coding guidelines](https://docs.astropy.org/en/latest/development/codeguide.html)?
  - [ ] Are tests added/updated as required? If so, do they follow the [Astropy testing guidelines](https://docs.astropy.org/en/latest/development/testguide.html)?
  - [ ] Are docs added/updated as required? If so, do they follow the [Astropy documentation guidelines](https://docs.astropy.org/en/latest/development/docguide.html)?
  - [ ] Is rebase and/or squash necessary? If so, please provide the author with appropriate instructions. Also see instructions for [rebase](https://docs.astropy.org/en/latest/development/development_details.html#rebase-if-necessary) and [squash](https://docs.astropy.org/en/latest/development/development_details.html#squash-if-necessary).
  - [ ] Did the CI pass? If no, are the failures related? If you need to run daily and weekly cron jobs as part of the PR, please apply the "Extra CI" label. Codestyle issues can be fixed by the [bot](https://docs.astropy.org/en/latest/development/development_details.html#pre-commit).
  - [ ] Is a change log needed? If yes, did the change log check pass? If no, add the "no-changelog-entry-needed" label. If this is a manual backport, use the "skip-changelog-checks" label unless special changelog handling is necessary.
  - [ ] Is this a big PR that makes a "What's new?" entry worthwhile and if so, is (1) a "what's new" entry included in this PR and (2) the "whatsnew-needed" label applied?
  - [ ] At the time of adding the milestone, if the milestone set requires a backport to release branch(es), apply the appropriate "backport-X.Y.x" label(s) *before* merge.

Patch:
diff --git a/astropy/io/fits/fitsrec.py b/astropy/io/fits/fitsrec.py
index dedcfafeb1..f88a553b00 100644
--- a/astropy/io/fits/fitsrec.py
+++ b/astropy/io/fits/fitsrec.py
@@ -594,7 +594,6 @@ class FITS_rec(np.recarray):
         new = super().copy(order=order)
 
         new.__dict__ = copy.deepcopy(self.__dict__)
-        new._col_weakrefs = weakref.WeakSet()
         return new
 
     @property
diff --git a/astropy/io/fits/hdu/image.py b/astropy/io/fits/hdu/image.py
index de85594449..6559e30c3e 100644
--- a/astropy/io/fits/hdu/image.py
+++ b/astropy/io/fits/hdu/image.py
@@ -577,7 +577,10 @@ class _ImageBaseHDU(_ValidHDU):
             self._header["BLANK"] = blank
 
         if self.data.dtype.type != _type:
-            self.data = np.array(np.around(self.data), dtype=_type)
+            if issubclass(_type, np.floating):
+                self.data = np.array(self.data, dtype=_type)
+            else:
+                self.data = np.array(np.around(self.data), dtype=_type)
 
         # Update the BITPIX Card to match the data
         self._bitpix = DTYPE2BITPIX[self.data.dtype.name]
diff --git a/docs/changes/io.fits/16143.bugfix.rst b/docs/changes/io.fits/16143.bugfix.rst
deleted file mode 100644
index 8068886d0f..0000000000
--- a/docs/changes/io.fits/16143.bugfix.rst
+++ /dev/null
@@ -1,1 +0,0 @@
-Fix memory leak in ```BinTableHDU.copy()```
diff --git a/docs/changes/io.fits/17458.bugfix.rst b/docs/changes/io.fits/17458.bugfix.rst
new file mode 100644
index 0000000000..e51bb520f4
--- /dev/null
+++ b/docs/changes/io.fits/17458.bugfix.rst
@@ -0,0 +1,1 @@
+Fix ``ImageHDU.scale`` with float.


Test patch:
diff --git a/astropy/io/fits/tests/test_image.py b/astropy/io/fits/tests/test_image.py
index 9095c3cd5c..c02d157267 100644
--- a/astropy/io/fits/tests/test_image.py
+++ b/astropy/io/fits/tests/test_image.py
@@ -1127,6 +1127,13 @@ def test_scale_implicit_casting():
     hdu.scale(bzero=1.3)
 
 
+def test_scale_floats():
+    data = np.arange(10) / 10
+    hdu = fits.ImageHDU(data)
+    hdu.scale("float32")
+    np.testing.assert_array_equal(hdu.data, data.astype("float32"))
+
+
 def test_bzero_implicit_casting_compressed():
     # Regression test for an issue that occurred because Numpy now does not
     # allow implicit type casting during inplace operations. Astropy is
diff --git a/astropy/io/fits/tests/test_table.py b/astropy/io/fits/tests/test_table.py
index 4457b1cc65..a377123843 100644
--- a/astropy/io/fits/tests/test_table.py
+++ b/astropy/io/fits/tests/test_table.py
@@ -2858,27 +2858,6 @@ class TestTableFunctions(FitsTestCase):
             t3.teardown_class()
         del t3
 
-    @pytest.mark.skipif(not HAVE_OBJGRAPH, reason="requires objgraph")
-    def test_reference_leak_copyhdu(self):
-        """Regression test for https://github.com/astropy/astropy/issues/15649"""
-
-        def readfile(filename):
-            with fits.open(filename) as hdul:
-                hdu = hdul[1].copy()
-
-        with _refcounting("FITS_rec"):
-            readfile(self.data("memtest.fits"))
-
-    def test_converted_copy(self):
-        """
-        Test that the bintable converted arrays are copied when the fitsrec is.
-        Related to https://github.com/astropy/astropy/issues/15649
-        """
-
-        with fits.open(self.data("memtest.fits")) as hdul:
-            data = hdul[1].data.copy()
-            assert data._converted is not hdul[1].data._converted
-
     def test_dump_overwrite(self):
         with fits.open(self.data("table.fits")) as hdul:
             tbhdu = hdul[1]
@@ -3022,9 +3001,6 @@ class TestVLATables(FitsTestCase):
                 q = toto[1].data.field("QUAL_SPE")
                 assert (q[0][4:8] == np.array([0, 0, 0, 0], dtype=np.uint8)).all()
                 assert toto[1].columns[0].format.endswith("J(1571)")
-                # Test BINTableHDU copy
-                copytoto = toto[1].copy()
-                assert (toto[1].data.field("QUAL_SPE")[0][4:8] == q[0][4:8]).all()
 
         for code in ("PJ()", "QJ()"):
             test(code)