倒圆角和浮点精度

Round and floating point precision

提问人:roulette01 提问时间:10/17/2023 最后编辑:jarlhroulette01 更新时间:10/17/2023 访问量:103

问:

我们正在将数据写入 sql 数据库(具体来说是 sqlite3)。对于特定列,它被指定为(浮点)列,因为我们存储为 1000 的倍数(因此整数数量除以 )。所以存储的数量精确到小数点后第三位,但由于浮点精度,我们有时会在小数点后第三位之后看到随机的非零值。quantityREALquantity1000

我的同事正试图用它来解决这个问题,但我看不出这将如何帮助解决这个问题。事实上,我认为它对这个特定问题没有任何作用。round

我的理解是,如果我们坚持使用浮点数,那么在写作时就没有办法真正解决这个问题。

python sql sqlite 浮点 舍入

评论

0赞 jarlh 10/17/2023
我不会使用浮点数。对SQLite一无所知,但有十进制数据类型吗?
1赞 buran 10/17/2023
如果您 [想] 以精确到小数点后 3 位的精度保存数据,那么将数据保存为 1000 的倍数的原因是什么?这没有意义。即,如果存储 1.234 而不是 1234,您会得到什么?
0赞 roulette01 10/17/2023
@buran老实说,我不知道。我一直在问代码的原始作者同样的问题。我想将其更改为整数。但就这篇文章而言,我的问题有答案吗?
1赞 Nick ODell 10/17/2023
SQLite 没有真正的十进制类型,但您可以直接舍入输出。假设您的号码长度少于 15 位,则保证恢复放入数据库的原始号码,因为您的号码的 64 位浮点表示保证在 1.11e+16 中相差不超过 1 个部分。如果你的数字大于这个值,你就会悄无声息地失去精度。round(x, 3)
1赞 Nick ODell 10/17/2023
虽然 SQLite 没有真正的十进制类型,但它确实有 DECIMAL,它在内部实现为浮点数,但会为您处理所有舍入。更多信息: stackoverflow.com/questions/21757722/...

答:

0赞 DinoCoderSaurus 10/17/2023 #1

选择 CAST(数量 * 1000 作为 INT).....将截断小数点后第 3 位后的任何随机非零值。

0赞 J_H 10/17/2023 #2

这更像是一个 FP 问题,而不是 SQL/python 问题。

请考虑以下众所周知的结果:

Python 3.11.5 ...
>>>
>>> .1 + .2
0.30000000000000004
>>> 
>>> .3 - .1
0.19999999999999998
>>> 
>>>
>>>
>>> 1 / 3
0.3333333333333333

许多人使用以 10 为基数 (),而 3 有 没有2和5的公因数, 因此,在十进制表示法中,我们必须求助于 设置为无限重复的小数点。 正确的答案是什么?有点。 是?近。但是你的笔会跑 在你写下来之前就用完了墨水。 在这种情况下,我们写下的总是 比所需值小的微小ε。2 × 5.33.333

类似地,将 或 表示为 二进制分数将不可避免地导致 无限重复的“十进制”二进制分数, 因为五和二是相对素数。 所以当你写作时,你在想“十分之一”, 但在这 53 位 FP 有效中,它是一个重复的部分。 至关重要的是,它是一个截断的分数,在第 53 位处被断。 我们存储最接近所需十分之一数的那个。 有时这有点过头,有时有点低于预期。 我们有 +/- ε 错误,在使用 FP 表示时这是不可避免的。.1.2.1


您不想使用 FP 表示, 因为很明显,ε错误对您的业务用例来说是麻烦。

修复表示形式。使用 INTEGER。 或者使用 sql DECIMAL,它只是缩放的整数 使用指定的小数点后三位精度。

从不适当的表示转换为适当的表示时, 使用 ROUND() 总是有意义的。 如果改为选择截断为 int, 请务必先添加一个小的 epsilon。 否则,在一半的时间里,你会遇到一个差一的错误。

0赞 SmellyCat 10/17/2023 #3

我同意,如果数据库将数据存储为浮点数,那么在存储到数据库中之前这样做听起来毫无意义。如果在数据库中使用定点精度(即十进制数据类型),则需要四舍五入。

如果存储为 float,则可以在 SQL 中使用 BETWEEN 或在 Python 中使用 isclose