Scala Spark中双值的精度

Scala Spark中双值的精度,scala,csv,apache-spark,Scala,Csv,Apache Spark,我正在从CSV文件中读取一些数据,我有自定义代码将字符串值解析为不同的数据类型。对于数字,我使用: val format = NumberFormat.getNumberInstance() 它返回一个DecimalFormat,我调用parse函数来获取我的数值DecimalFormat具有任意精度,因此我不会丢失任何精度。但是,当数据被推入Spark数据框时,它将使用DoubleType存储。在这一点上,我希望看到一些精度问题,但我没有。我尝试在我的CSV文件中输入0.1、0.01、0.0

我正在从CSV文件中读取一些数据,我有自定义代码将字符串值解析为不同的数据类型。对于数字,我使用:

val format = NumberFormat.getNumberInstance()
它返回一个
DecimalFormat
,我调用
parse
函数来获取我的数值
DecimalFormat
具有任意精度,因此我不会丢失任何精度。但是,当数据被推入Spark数据框时,它将使用
DoubleType
存储。在这一点上,我希望看到一些精度问题,但我没有。我尝试在我的CSV文件中输入0.1、0.01、0.001、…、1e-11的值,当我查看存储在Spark数据框中的值时,它们都被精确表示(即,与0.09999999不同)。我对这种行为感到惊讶,因为我不希望双值存储任意精度。有人能帮我理解这里的魔力吗


干杯

这里可能有两个问题:双精度在尾数中可以表示的有效位数;以及它的指数范围

大约,双精度大约有16位(十进制)精度,指数可以覆盖大约10^-308到10^+308的范围。(显然,实际限制是由格式使用的二进制表示设置的。)

当您尝试存储像1e-11这样的数字时,可以在尾数中可用的56位内精确地近似计算。当你想减去两个非常接近的数字时,你会遇到精度问题,这两个数字之间的差值只有最低有效位的一小部分(假设它们的尾数已经对齐移位,所以它们的指数是相同的)


例如,如果您尝试(1e20+2)-(1e20+1),您希望得到1,但实际上会得到零。这是因为双精度不足以表示所需的20(十进制)位数。然而,(1e100+2e90)-(1e100+1e90)被计算为几乎完全是1e90,正如它应该的那样。

我猜它只是一个表示。尝试一些接近double能处理的极限的东西。另外
Double
s可以很好地表示值,只要这些值在其范围内。当您对使用double表示的任意精度数字执行操作时,问题就开始了。我认为double可以准确地表示支持范围内的整数,但不是整数之间的所有十进制值。这就是我发现的令人困惑的地方。另外,如果你反复乘以非常小的数字,这在很多情况下都会发生,比如小分币的利息。那么使用哪种数据类型来获得大于16位(十进制)的精度呢