Spark

时间:2016-10-06 22:17:58

标签: scala csv apache-spark

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

val format = NumberFormat.getNumberInstance()

返回DecimalFormat,我在其上调用parse函数来获取我的数值。 DecimalFormat具有任意精度,所以我没有失去任何精度。但是,当数据被推送到Spark DataFrame时,它将使用DoubleType进行存储。在这一点上,我期待看到一些精确问题,但我没有。我尝试在我的CSV文件中输入0.1,0.01,0.001,...,1e-11的值,当我查看存储在Spark DataFrame中的值时,它们都被准确地表示(即不像0.099999999)。我对此行为感到惊讶,因为我不希望double值存储任意精度。任何人都可以帮我理解这里的魔力吗?

干杯!

1 个答案:

答案 0 :(得分:2)

这里可能存在两个问题:Double可以在其尾数中表示的有效位数;以及它的指数范围。

粗略地说,Double具有大约16(十进制)的精度数字,并且指数可以覆盖从大约10 ^ -308到10 ^ + 308的范围。 (显然,实际限制是由ieee754格式使用的二进制表示设置的。)

当您尝试存储1e-11之类的数字时,可以在尾数中可用的56位内精确近似。你会得到准确性问题的地方就是当你想要减去两个非常接近的数字时它们只相差少量的最低有效位(假设他们的尾数已经对齐移位以使它们的指数相同)

例如,如果你尝试(1e20 + 2) - (1e20 + 1),你希望得到1,但实际上你会得到零。这是因为Double没有足够的精度来表示所需的20(十进制)数字。但是,(1e100 + 2e90) - (1e100 + 1e90)计算得几乎正好是1e90,应该是。