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

PySpark保留两位小数时四舍五入异常问题求助

解决Databricks中round函数四舍五入异常问题

问题原因

你遇到的216.495被舍入为216.49而非216.50,核心原因有两个:

  • 浮点数精度丢失:多数十进制小数无法被二进制浮点数精确存储,216.495实际存储的可能是略小于它的近似值(如216.4949999999999...),导致round函数判定为需要舍去。
  • Spark round函数的默认规则:Spark原生round采用银行家舍入法(四舍六入五成双),当第三位小数为5且前一位为偶数时会舍去,但此场景下更可能是浮点数精度问题主导。

解决方案

方案1:用Decimal类型保证精确计算

将参与计算的列转换为Decimal类型(精确十进制类型),从根源避免浮点数精度丢失:

from pyspark.sql.types import DecimalType
from pyspark.sql.functions import col, coalesce, when, round

result = (
    round(
        coalesce(
            when(col('col').cast(DecimalType(18,3)) != 0, col('col').cast(DecimalType(18,3))),
            when(col('col').cast(DecimalType(18,3)) != 0, col('col').cast(DecimalType(18,3))),
            when(col('col').cast(DecimalType(18,3)) != 0, col('col').cast(DecimalType(18,3))),
            when(col('col').cast(DecimalType(18,3)) != 0, col('col').cast(DecimalType(18,3)))
        ) * col('col4').cast(DecimalType(18,3)) +
        when((col('col').cast(DecimalType(18,3)) > 0) & (col('col').cast(DecimalType(18,3)) > 0), 
             col('col').cast(DecimalType(18,3)) * col('col').cast(DecimalType(18,3))
            ).otherwise(col('col').cast(DecimalType(18,3))),
        2
    )
    .alias('col')
)

也可以在读取数据时直接指定列的Decimal类型,减少后续转换操作。

方案2:用format_number实现传统四舍五入

format_number函数遵循传统四舍五入规则格式化数值,转换为数值类型后即可使用:

from pyspark.sql.functions import format_number, col, coalesce, when
from pyspark.sql.types import DecimalType

result = (
    format_number(
        coalesce(
            when(col('col') != 0, col('col')),
            when(col('col') != 0, col('col')),
            when(col('col') != 0, col('col')),
            when(col('col') != 0, col('col'))
        ) * col('col4') +
        when((col('col') > 0) & (col('col') > 0), col('col') * col('col')).otherwise(col('col')),
        2
    )
    .cast(DecimalType(18,2))
    .alias('col')
)

方案3:自定义传统四舍五入UDF

如果需要更灵活的逻辑,可自定义UDF实现传统四舍五入:

from pyspark.sql.functions import udf
from pyspark.sql.types import DoubleType
from pyspark.sql.functions import col, coalesce, when

def traditional_round(num, decimals):
    return round(num + 10**(-decimals-1), decimals)

traditional_round_udf = udf(traditional_round, DoubleType())

result = (
    traditional_round_udf(
        coalesce(
            when(col('col') != 0, col('col')),
            when(col('col') != 0, col('col')),
            when(col('col') != 0, col('col')),
            when(col('col') != 0, col('col'))
        ) * col('col4') +
        when((col('col') > 0) & (col('col') > 0), col('col') * col('col')).otherwise(col('col')),
        2
    )
    .alias('col')
)

注意事项

  • 涉及金融、精确小数计算的场景,优先使用Decimal类型,彻底规避浮点数精度问题。
  • format_number返回的是字符串类型,需转换为数值类型才能进行后续计算。

内容的提问来源于stack exchange,提问作者Ashwini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:40:15