这是我数据库中的一个非常简短的示例。
CREATE TEMPORARY TABLE temp_ledger(
book_entry INT,
credit DOUBLE(24, 8),
debit DOUBLE(24, 8)
);
INSERT INTO
temp_ledger(book_entry, credit, debit)
VALUES
(1, 17.54500000, 0.00000000),
(1, 0.00000000, 14.50000000),
(1, 0.00000000, 3.04500000),
(2, 0.00000000, 99.85500000),
(2, 95.10000000, 0.00000000),
(2, 4.75500000, 0.00000000);
SELECT
book_entry,
SUM(ROUND(debit, 2)) as sum_of_rounded_debit,
SUM(ROUND(credit, 2)) as sum_of_rounded_credit,
ROUND(SUM(debit), 2) as round_of_summed_debit,
ROUND(SUM(credit), 2) as round_of_summed_credit,
SUM(debit) as summed_debit,
SUM(credit) as summed_credit
FROM
temp_ledger
GROUP BY
book_entry;
DROP TEMPORARY TABLE temp_ledger;
输出
临时账本
图书条目 | 借方舍入总和 | 舍入信用总和 | 借记总和轮次 | 信用总和轮次 | 借方总和 | 总信用额 |
---|---|---|---|---|---|---|
1 | 17,54 | 17,55 | 17,55 | 17,55 | 17,54500000 | 17,54500000 |
2 | 99,86 | 99,86 | 99,86 | 99,85 | 99,85500000 | 99,85500000 |
我不明白为什么sum_of_rounded_debit
图书条目 1 是17.54:
- 14.50四舍五入应为14.50
- 3.045四舍五入应为3.05
对于round_of_summed_credit
书籍条目 2 来说,如果 summed_credit 是99.855,那么为什么舍入给我的是99.85而不是99.86
我知道有时小数可能很挑剔,但round_of_summed_credit
特别让我想知道“什么?”。
这是试图在 Dolibarr 的 llx_accounting_bookkeeping 表中查找错误,因为总和给出了贷方和借方之间不匹配的某些行,而总和给出了一组不同的行。
使用 MariaDB 10.5.8
浮点数以 2 为基数工作,因此与 10 基数之间的转换总是会引入微小的错误。当它们转换为以 10 为基数进行显示时,这(在某种程度上且通常但并非总是)通过四舍五入到小于完整位数而被隐藏......但如果您期望浮点是精确的,则它将无法工作。
例如,数字“3.045”无法编码为浮点双精度,因此使用最接近的可用表示形式:
3.04499999999999992895
当使用小数位数为 2 的 round() 时,四舍五入为:
3.04000000000000003553
此结果是正确的,因为 3.044999...(四舍五入为 3.04)不是 3.045(四舍五入为 3.05)。问题是您认为将 3.045 转换为双精度浮点会得到等于 3.045 的结果。它不是。
Python 演示:
浮点数的非精确性质意味着它们永远不应该被用来表示精确的以 10 为基数的数字,尤其是在会计领域。
幸运的是,这是一个已解决的问题,因为您的数据库提供了精确的定点类型:Numeric/Decimal。
您可以根据需要指定这些 Decimal 类型的精度。通常会计中的最小单位是分,不可能用小数分进行银行转帐或支票,因此数字的指定精度为小数点后 2 位数字。在其他情况下,例如加密货币,$DOGE 的不幸所有者出售给您,您可能会收到 0.000002 BTC 的转账,因此您可能希望添加更多数字。
重点是,表中存储的值是交易中转移的确切金额,而不是近似转换为浮动金额。
一旦完成,所有计算都将是正确的。
我不知道 sum(round()) 应该实现什么。如果您想要付款的 sum(),那么您应该对付款进行 sum(),而不是在求和之前对其进行四舍五入。
有一个可能的解释:该数据库的设计者使用浮点数进行会计,这意味着他们不知道自己在做什么。因此,他们使用 round() 来尝试修复因使用错误数据类型而引入的错误。
这是行不通的。您必须使用正确的数据类型,否则您的结果将始终是错误的。
请注意,由于表中的数据数据类型错误,转换为十进制可能会带来问题。例如,如果存储值“3.045”(实际上是 3.04499999999999992895),并将其转换为 Decimal(8,2),则应该检查它是否给出了您想要的结果。
由于整个应用程序是用 php 编写的,并且 php 没有 Decimal 类型(只有浮点数)...在 php 中执行此操作的通常方法是将所有内容转换为美分并仅使用整数。因此应用程序中进行的计算也可能是错误的。症状包括从 php 计算的总和与在数据库中计算的总和不同。