双精度的总和给出了奇怪的结果

Luc*_*man 1 postgresql sum

我一直在计算包含大约 500.000 条双精度数字记录的列的总和。数据库中的所有数字通常应该是句点后面的两个密码。但是,在计算总和后,我得到了 6 个数字:123123123.549977

要么我的数据库中有错误的数据,其中在句点之后有更多数字的记录,要么我遗漏了 sum 函数。

所以我的问题是:

  • sum 函数是否有任何可能导致这种情况的舍入属性?
  • 有没有办法选择句点后包含两个以上数字的所有记录?

Dav*_*ett 8

这是浮点数无处不在的常见问题。

存储在计算机系统中的浮点数应该只被认为是近似值,因为有些数字很容易用十进制表示,当转换为二进制时,它们的长度超过了可用精度(有时它们实际上是永无止境的)。有关更多详细信息,请参阅 ypercube 的链接和/sf/ask/41160311/以及许多其他参考资料。

给出的最常见示例(如 StackOverflow 链接中所示)是 0.1+0.2,而不是恰好0.3。您必须应用额外的舍入或灵活的边界检查(在这两种情况下都会降低有效精度)以获得您期望的行为。

由于您的数据具有固定的小数位数(或固定的最大值)为 2,因此使用固定位小数/数字类型或类似类型会更好。这些实际上作为缩放整数存储和处理,避免了内部需要任何浮点表示,从而避免了近似问题(假设您有足够的数字/位,所有整数都可以以 10 为基数和以 2 为基数准确表示)。例如,0.1 和 0.2 可能会存储为 1000 和 2000,因此加法结果为 3000,当转换为字符串进行显示时,它会变成 0.3,而不是浮点计算中可能会得到的 0.3000000004,当然,与 3 的比较准确将缩放到 3000 的相同类型。

有没有办法选择句点后包含两个以上数字的所有记录?

您可以转换为字符串并计算小数点后的字符数(或逗号,取决于您的本地系统)。在 TSQL 中,这会找到在以二进制浮点格式存储然后转换回十进制后以超过两位小数结束的值:

SELECT *
FROM   myTable
WHERE  CHARINDEX('.', REVERSE(CAST(floatValue AS NVARCHAR(MAX)))>3
Run Code Online (Sandbox Code Playgroud)

(您可能需要调整 postgres 的函数名称和相关语法)。

  • 现代 Postgres 使用 8 字节整数表示 `timestamp`,使用 4 字节整数表示`date`。计算结果*精确*。Postgres 中没有 `DATEDIFF()` 并且不需要强制转换。 (2认同)