pandas 2.x read_csv loses up to 1e-12 on floats in [1e-4, 1e-2)
In pandas 2.2.3, df.to_csv() followed by pd.read_csv() is not a float round-trip. The default parser (float_precision=None/'high') appears to cap at about 17 digits counting the leading zeros after the decimal point. Python repr writes 0.0001129476226678916 in fixed notation, and it reads back as 0.0001129476226678. Measured on 100k log-uniform values per decade: [1e-4,1e-3) 99.9% inexact, max relative error 9.9e-13; [1e-3,1e-2) 9.9e-14; [1e-2,0.1) 9.9e-15; >=0.1 within 1-2 ulp; below 1e-4 (scientific notation) within 1 ulp. engine='python' gave the same 1.0e-12. Only float_precision='round_trip' was bit-exact. pandas 3.1.0 is bit-exact by default and deprecates float_precision. On 2.x, pass float_precision='round_trip' when CSV is an interchange or cache format for numeric results, or use parquet/npy.
Reproduced with 100k log-uniform values per decade (numpy default_rng(0)), comparing to_csv(index=False) -> read_csv against the originals. pandas 2.2.3 / numpy 2.5.4 / CPython 3.12.16, default parser: [1e-4,1e-3) 99.9% inexact, max rel 1.0e-12; [1e-3,1e-2) 99.3%, 9.9e-14; [1e-2,0.1) 93.7%, 9.9e-15; [0.1,1) 45.5%, 9.7e-16; [1,10) 14.0%, 2.5e-16; [1e-5,1e-4) (scientific) 17.3%, 2.2e-16. float_precision='round_trip' was 0.0% inexact in every decade. pandas 3.1.0 on CPython 3.14.10 was 0.0% inexact by default in every decade, and passing float_precision there emits
Pandas4Warning: The 'float_precision' argument is deprecated. So on 3.x, drop the argument when you upgrade instead of carrying it over.Author correction: '>=0.1 within 1-2 ulp' in the post is wrong for [0.1, 1). Re-measured in ulps (pandas 2.2.3, numpy 2.2.6, 100k log-uniform per decade, default_rng(0)): [1e-1,1) 45.5% inexact, max 7 ulp (rel 9.7e-16, as in the comment above); [1,10) and [1e3,1e4) 14.0%, max 2 ulp; [1e-2,1e-1) max 57 ulp; [1e-3,1e-2) 461; [1e-4,1e-3) 7378 (rel 1.0e-12); [1e-5,1e-4) (scientific notation) max 1 ulp. The error grows smoothly with each leading zero rather than jumping at 1e-4, consistent with a cap on total digits including leading zeros. The advice is unchanged.