在python中从MySQL查询数据时导致舍入错误的原因是什么

What is causing rounding errors when querying data from MySQL in python

提问人:Weston Simon 提问时间:8/9/2023 最后编辑:Weston Simon 更新时间:8/9/2023 访问量:28

问:

我正在从mysql(mysql-connector-python)中的表(下面的架构和示例数据)中查询数据。在此表中,我有两个浮点值“ourCostPerSegment”和“theirCostPerSegment”,存储在 mysql 中的值分别为 0.0069 和 0.02。当我从 python 查询数据时,我得到 0.006899999920278788 和 0.019999999552965164 等值。这些问题导致计算中的误差幅度过大。

这是表架构:

DESCRIBE companyProperties;
+---------------------+------------+------+-----+---------+-------+
| Field               | Type       | Null | Key | Default | Extra |
+---------------------+------------+------+-----+---------+-------+
| dateEffective       | date       | NO   |     | NULL    |       |
| isAgeGated          | tinyint(1) | NO   |     | 0       |       |
| ourCostPerSegment   | float      | NO   |     | NULL    |       |
| theirCostPerSegment | float      | NO   |     | NULL    |       |
| monthlyBaseFee      | int        | NO   |     | NULL    |       |
| friendlyName        | text       | NO   |     | NULL    |       |
+---------------------+------------+------+-----+---------+-------+

表值:

SELECT * FROM companyProperties;
+---------------+------------+-------------------+---------------------+----------------+--------------+
| dateEffective | isAgeGated | ourCostPerSegment | theirCostPerSegment | monthlyBaseFee | friendlyName |
+---------------+------------+-------------------+---------------------+----------------+--------------+
| 2023-08-03    |          1 |            0.0069 |                0.02 |            250 | test         |
+---------------+------------+-------------------+---------------------+----------------+--------------+

这是运行查询的代码: 这是使用 FastAPI 框架的 API 请求的一部分。

python3 --version
Python 3.10.12
conn = db.cursor(dictionary=True, prepared=True)
getCompanyProperties = "SELECT * FROM `{}`.companyProperties ORDER BY dateEffective DESC LIMIT 1".format(companyKey["companyKey"])
conn.execute(getCompanyProperties, [])
companyPropertiesObject = conn.fetchall()
print(companyPropertiesObject)

这是响应:

[{'dateEffective': datetime.date(2023, 8, 3), 'isAgeGated': 1, 'ourCostPerSegment': 0.006899999920278788, 'theirCostPerSegment': 0.019999999552965164, 'monthlyBaseFee': 250, 'friendlyName': 'test'}]

服务器信息

SHOW VARIABLES LIKE "%version%";
+--------------------------+-------------------------+
| Variable_name            | Value                   |
+--------------------------+-------------------------+
| admin_tls_version        | TLSv1.2,TLSv1.3         |
| immediate_server_version | 999999                  |
| innodb_version           | 8.0.33                  |
| original_server_version  | 999999                  |
| protocol_version         | 10                      |
| replica_type_conversions |                         |
| slave_type_conversions   |                         |
| tls_version              | TLSv1.2,TLSv1.3         |
| version                  | 8.0.33-0ubuntu0.22.04.2 |
| version_comment          | (Ubuntu)                |
| version_compile_machine  | x86_64                  |
| version_compile_os       | Linux                   |
| version_compile_zlib     | 1.2.13                  |
+--------------------------+-------------------------+

我试图严格指定mySQL中浮点数的格式,例如.这并没有解决问题。一种有效的解决方案是将列类型更改为 TEXT 并将返回的字符串转换为 python 中的浮点数,但这并不理想。FLOAT(M,D)

我已经看到一些关于小数点数字在二进制中存在问题的事情。如何解决此问题?

mysql-连接器-python

评论


答:

1赞 M.O. 8/9/2023 #1

欢迎来到浮点数的美妙世界。问题在于,大多数十进制数,如 0.0069 和 0.02 都不能精确地表示为二进制(就像 1/3 不能精确表示一样,小数会永远存在)。

MySQL有一个十进制数据类型,可以存储精确的十进制值,如果浮点精度对你来说是一个问题,可以考虑使用它。

1赞 Sudipto Bhattacharya 8/9/2023 #2

将这些字段的数据类型更改为 decimal(10,2)。这将解决您的问题。