You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Polars中Float64转Float32显示原数据不存在的额外精度值

关于Polars中Float64转Float32后显示额外精度位的问题

在使用Polars时发现,将Float64类型列向下转换为Float32后,输出显示的数值会出现原数据中不存在的额外精度位。实际对比数值时二者匹配,但该显示问题会干扰人工视觉检查。已知可通过显示配置限制精度,但好奇该现象的成因及额外填充数字的来源。最初是通过Schema覆盖读取CSV文件时发现此问题,对比文本编辑器中的CSV内容,Polars读取打印的数据看似异常。

复现代码及结果

import polars as pl
df1 = pl.DataFrame(
{
"col1":[2021.9952, 2024.0, 2024.25, 2024.456]
}
)
print("original values")
print(df1)

# 输出:
# shape: (4, 1)
# ┌───────────┐
# │ col1      │
# │ ---       │
# │ f64       │
# ╞═══════════╡
# │ 2021.9952 │
# │ 2024.0    │
# │ 2024.25   │
# │ 2024.456  │
# └───────────┘

diff1 = df1["col1"][1] -  df1["col1"][0]
print("Original: diff row1 - row0")
print(diff1)
# 输出:2.004799999999932

print("Original value equality")
print(df1["col1"][0] == 2021.9952)
# 输出:True

print("Downcasting to float 32")
print(df1.cast({"col1":pl.Float32}))

# 输出:
# shape: (4, 1)
# ┌─────────────┐
# │ col1        │
# │ ---         │
# │ f32         │
# ╞═════════════╡
# │ 2021.995239 │
# │ 2024.0      │
# │ 2024.25     │
# │ 2024.456055 │
# └─────────────┘

print("Downcasted: diff row1 - row0")
diff2 = df1.cast({"col1":pl.Float32})["col1"][1] -  df1.cast({"col1":pl.Float32})["col1"][0]
print(diff2)
# 输出:2.0048000812530518
print("Downcasted value equality")
print(df1.cast({"col1":pl.Float32})["col1"][0] == 2021.9952)
# 输出:True

预期显示结果

┌───────────┐
│ col1      │
│ ---       │
│ f32       │
╞═══════════╡
│ 2021.9952 │
│ 2024.0    │
│ 2024.25   │
│ 2024.456  │
└───────────┘

或者

┌─────────────┐
│ col1        │
│ ---         │
│ f32         │
╞═════════════╡
│ 2021.99520  │
│ 2024.00000  │
│ 2024.25000  │
│ 2024.45600  │
└─────────────┘

现象成因及额外数字来源

  1. 浮点数二进制存储特性:Float32(单精度)仅用23位存储有效尾数,远少于Float64的52位。大部分十进制小数无法被二进制浮点数精确表示,转换为Float32时,程序会选择最接近原数值的二进制浮点数近似值,这个近似值的十进制展开就会出现原数据没有的额外小数位。
  2. Polars默认打印逻辑:为了唯一标识每个浮点数,Polars打印Float32时会输出足够多的小数位,确保能准确区分不同的Float32值,而非截断到原输入的小数位数。而Float64的近似值通常可以用更少位数表示到和原输入一致的视觉效果,所以不会出现异常。
  3. 原Float64的隐性误差:从diff1的结果能看出,原Float64数值本身也存在微小存储误差,但Polars打印时会自动截断到看起来和原输入一致的位数,视觉上无异常。

解决方法

如果需要统一显示格式,可通过Polars配置限制浮点数打印精度:

pl.Config.set_fmt_float("fixed", precision=4)
print(df1.cast({"col1":pl.Float32}))

这样就能得到符合预期的截断显示效果。

内容的提问来源于stack exchange,提问作者ur.sal.vatore

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:34:51