Neo4j浮点求和结果不同

时间:2019-06-14 13:36:58

标签: neo4j floating-point sum precision

我正在使用neo4j计算有关数据集的一些统计信息。为此,我经常在浮点值上使用sum。根据情况我会得到不同的结果。例如,执行此操作的查询:

...
WITH foo
ORDER BY foo.fooId
RETURN SUM(foo.Weight)

返回与简单执行总和的查询不同的结果

...
RETURN SUM(foo.Weight)

差异很小(293.07724195098984293.07724195099007)。但这足以使简单的相等性检查失败。另一个示例是数据库的另一个实例,使用相同的加载过程加载相同的数据会产生相同的问题(数据库可能不是1:1,某些关系的加载顺序可能会不同)。我采用neo4j求和的原始值(只需删除SUM()),并验证了它们在所有情况下都是相同的(不同的db和有序/无序)。

在这里我有什么选择?我不介意失去一些精度(我已经尝试将精度从15位小数点降低到12位,但这似乎不起作用),但是我需要结果匹配。

1 个答案:

答案 0 :(得分:2)

由于舍入错误,浮点数没有关联。 (a + b)+ c!= a +(b + c)。
将每个操作的结果四舍五入以适应float编码约束,并且(a + b)+ c实现为round(round(a(b + b)+ c),而a +(b + c)实现为round(a + round(b) + c))。

显而易见,考虑一下运算(2 ^ -100 + 1 -1)。如果将其解释为(2 ^ -100 + 1)-1,它将返回0,因为1 + 2 ^ -100对于IEEE754中的float或double编码要求的精度过大,并且只能编码为1.0。虽然(2 ^ -100 +(1-1))正确返回2 ^ -100,可以用浮点数或双精度数进行编码。
这是一个简单的示例,但是这些舍入错误可能在每次操作之后都存在,并解释了为什么浮点运算不具有关联性。

数据库通常不会按保证的顺序返回数据,并且根据实际顺序,操作会有所不同,这说明了您的行为。

通常,由于这个原因,对浮点数进行相等比较不是一个好主意。通常,建议将a == b替换为abs(a-b)足够小。
“足够”可能取决于您的算法。 float等于〜6-7个小数,并且翻倍为15-16个小数(我认为这是您的DB上使用的)。根据计算的数量,您可能会影响最近的1--3小数。
最好可能是使用
abs(a-b)<相对误差* max(abs(a),abs(b))
必须根据您的问题调整相对误差。大约10 ^ -13左右可能是正确的,但是您必须进行试验,因为舍入误差取决于计算次数,值的分散程度以及对您的问题认为“相等”的东西。

请看this site,以了解比较方法。并阅读David Goldberg的What Every Computer Scientist Should Know About Floating-Point Arithmetic,其中讨论了这些问题。