火花十进制类型精度损失

时间:2019-03-07 14:43:27

标签: scala apache-spark apache-spark-sql

我正在测试火花十进制类型的货币量度,并在设置刻度和精度时看到一些奇怪的精度结果,如下所示。我想确保在计算过程中不会丢失任何数据,但是下面的示例不能确保这一点。谁能告诉我为什么Spark sql会发生这种情况?当前版本为2.3.0

val sql = """select cast(cast(3 as decimal(38,14)) / cast(9 as decimal(38,14)) as decimal(38,14)) val"""
spark.sql(sql).show

这将返回

+----------------+
|             val|
+----------------+
|0.33333300000000|
+----------------+

2 个答案:

答案 0 :(得分:1)

这是当前的未解决问题,请参见SPARK-27089。建议的解决方法是调整以下设置。我验证了此设置为false的情况下,SQL语句是否可以按预期工作。

spark.sql.decimalOperations.allowPrecisionLoss=false

答案 1 :(得分:0)

使用BigDecimal避免精度损失。参见Double vs. BigDecimal?

示例:

scala> val df = Seq(BigDecimal("0.03"),BigDecimal("8.20"),BigDecimal("0.02")).toDS
df: org.apache.spark.sql.Dataset[scala.math.BigDecimal] = [value: decimal(38,18)]

scala> df.select($"value").show
+--------------------+
|               value|
+--------------------+
|0.030000000000000000|
|8.200000000000000000|
|0.020000000000000000|
+--------------------+

使用BigDecimal:

scala> df.select($"value" + BigDecimal("0.1")).show
+-------------------+
|      (value + 0.1)|
+-------------------+
|0.13000000000000000|
|8.30000000000000000|
|0.12000000000000000|
+-------------------+

如果您不使用BigDecimal,则会导致精度损失。在这种情况下,0.1是双精度

scala> df.select($"value" +  lit(0.1)).show
+-------------------+
|      (value + 0.1)|
+-------------------+
|               0.13|
|  8.299999999999999|
|0.12000000000000001|
+-------------------+