reposting here so that search engines can find this discussion for the future
We’ve noticed a bug/glitch in the way floating point values are written to header cards (in our usecase, through fits.setval). This is probably an underlying glitch in the C library.
Our institution requires having floating-point keyword values in a given precision format.
One said values happens to be -99.9, to be written as %.1f format.
A call to fits.setval(file, ‘D_APDTI’, -99.9) results in the file header showing:
D_APDTI = -99.90000000000001 / APD coolant inlet temperature (degC)
Where
D_APDTI = -99.9 / APD coolant inlet temperature (degC)
is expected.
Writing a string is not appropriate, e.g. fits.setval(file, ‘D_APDTI’, ‘%.2f’ % (-99.9,), as it results in a single-quoted string in the header:
D_APDTI = ‘-99.9’ / APD coolant inlet temperature (degC)
Please let us know of the appropriate way to enforce float formatting, or of a known workaround. This issue may very well be a classic one, and I apologize for the inconvenience in that case.
Also, instead of fits.setval(file, ‘D_APDTI’, -99.9) you could try to set the header directly header['D_APDTI'] = -99.9. I don’t know if that makes a difference; I’ve never looked into code inside of the fits module, but that’s the things I will try.
Here is a minimal example for other trying to reproduce the problem to help with debugging:
from astropy.io import fits
# Just use table to quickly make a short fits file to experiment on
from astropy.table import Table
tab = Table({'a': [1,2]})
tab.write('text.fits')
fits.setval('text.fits', 'D_APDTI', value=-99.9)
fits.setval('text.fits', 'D_APDTI2', value=23)
Then, outside of Python (e.g. less text.fits), I see:
SIMPLE = T / conforms to FITS standard
BITPIX = 8 / array data type
NAXIS = 0 / number of array dimensions EXTEND = T
D_APDTI = -99.90000000000001
D_APDTI2= 23
END
So, I can reproduce the problem (Python 3.9, astropy 5.0) but I don’t have a solution.
-99.9 is not the only value where this happens; one can get that with several other numbers. It’s just one of the numbers that happens to off in binary representation just enough to show up here.
I think it’s one of those cases where you can’t have a solution: If you want to control exactly how it’s formatted, you need to use a string. If you can’t use a string, you’ll get the binary representation as good as it gets. Depending on your machine architecture, you might be able to use higher precision numbers to avoid that issue (e.g. numpy.float128), but on my computer 64-bit floats is the best that numpy offers me.
If you disagree and believe that this is a bug that should be fixed, we’d appreciate a bug report on Issues · astropy/astropy · GitHub (feel free to copy my minimal example above into the issue description).