我们正在向sql数据库(具体来说是sqlite3)写入数据。对于特定的列quantity
,它被指定为REAL
(浮点)列,因为我们将quantity
存储为1000的倍数(因此整数量除以1000
)。因此,存储的数量精确到小数点后第三位,但由于浮点精度,我们有时会在小数点后第三位看到随机的非零值。
我的同事正在尝试使用round
来处理这个问题,但我看不出这对解决这个问题有什么帮助。事实上,我不认为它对这个特殊的问题有任何帮助。
我的理解是,如果我们坚持使用浮点数,那么在编写时就没有办法真正解决这个问题。
3条答案
按热度按时间frebpwbc1#
选择铸件(数量 * 1000作为INT).....将截断第三位小数后的任何随机非零值。
utugiqy62#
这更像是一个FP问题,而不是一个SQL / python问题。
考虑这些众所周知的结果:
许多人使用十进制(
2 × 5
),而3与2和5没有公因子,因此在十进制记法中,我们必须求助于无限重复小数。.33
是正确答案吗?算是吧。是.333
吗?更近了。但你还没来得及写就没墨水了。在这种情况下,我们写下的总是比期望值小一个微小的单位。类似地,将
.1
或.2
表示为二进制分数将不可避免地导致无限重复的“十进制”二进制分数,因为5和2是互质的。所以当你写**.1
时,你想的是“十分之一”,但在这53位FP有效位中,它是一个重复的分数。重要的是,它是一个 * 截断 * 分数,在第53位截断。我们将存储最接近所需十分之一的那个。有时候,这是一个有点多,有时有点低于什么是期望。我们有+/-μ误差,当使用FP表示时,这是不可避免的。您不希望使用FP表示,因为很明显,对于您的业务用例来说,这个错误是个麻烦。
修复表示。使用INTEGER。或者使用sql DECIMAL,它只是使用指定的三位小数精度进行整数缩放。
当从不合适的表示转换为合适的表示时,使用ROUND()总是有意义的。如果您选择截断为int,请确保首先添加一个小的int。否则,有一半的时间你会有一个错误。
xiozqbni3#
我同意,如果数据库将数据存储为浮点数,那么在存储到数据库之前这样做听起来毫无意义。如果在数据库中使用定点精度(即十进制数据类型),则需要进行四舍五入。
如果存储为float,可以在SQL中使用BETWEEN,或者在Python中使用isclose。