我正在测试火花十进制类型的货币量度,并在设置刻度和精度时看到一些奇怪的精度结果,如下所示。我想确保在计算过程中不会丢失任何数据,但是下面的示例不能确保这一点。谁能告诉我为什么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|
+----------------+
答案 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|
+-------------------+