英文:
What is causing rounding errors when querying data from MySQL in python
问题
我正在从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中浮点数的格式,例如FLOAT(M,D)
,但这并没有解决问题。一个解决方案是将列类型更改为TEXT,并在Python中将返回的字符串转换为浮点数,但这并不理想。
我看到一些关于二进制中小数点数值存在问题的内容。如何解决这个问题?
英文:
I'm querying data from a table(schema and example data below) in mysql(mysql-connector-python). In this table I have two float values "ourCostPerSegment" and "theirCostPerSegment" the values that are stored in mysql are 0.0069 and 0.02 respectively. When I query the data from python I get values like 0.006899999920278788 and 0.019999999552965164. These issues are causing a margin of error in calculation that is to large.
This is the table schema:
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 | |
+---------------------+------------+------+-----+---------+-------+
Table values:
SELECT * FROM companyProperties;
+---------------+------------+-------------------+---------------------+----------------+--------------+
| dateEffective | isAgeGated | ourCostPerSegment | theirCostPerSegment | monthlyBaseFee | friendlyName |
+---------------+------------+-------------------+---------------------+----------------+--------------+
| 2023-08-03 | 1 | 0.0069 | 0.02 | 250 | test |
+---------------+------------+-------------------+---------------------+----------------+--------------+
This is the code that is running the query:
This is part of an API request using the FastAPI framework.
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)
This is the response:
[{'dateEffective': datetime.date(2023, 8, 3), 'isAgeGated': 1, 'ourCostPerSegment': 0.006899999920278788, 'theirCostPerSegment': 0.019999999552965164, 'monthlyBaseFee': 250, 'friendlyName': 'test'}]
Server Info
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 |
+--------------------------+-------------------------+
I tried to strictly specify the format of the float in mySQL like FLOAT(M,D)
. This didn't fix the issue. One solution that did work was changing the column type to a TEXT and converting the string that is returned to a float in python but this is not ideal.
I have seen some things about decimal point numbers having issues in binary. How do I get around this issue?
答案1
得分: 1
欢迎来到浮点数的奇妙世界。问题在于大多数十进制数,如0.0069和0.02,在二进制中无法精确表示(就像1/3无法精确表示一样,小数会一直循环)。
MySQL有一个Decimal数据类型,可以存储精确的十进制值,如果浮点数的精度对你很重要,可以考虑使用它。
英文:
Welcome to the wonderful world of floating point numbers. The issue is that most decimal numbers, like 0.0069 and 0.02 are not representable exacly in binary (just like 1/3 is not exacly representable, the decimals go on forever).
MySQL has a Decimal data type that stores exact decimal values, look into using it if the floating point accuracy is an issue for you.
答案2
得分: 1
将这些字段的数据类型更改为decimal(10,2)。这将解决你的问题。
英文:
Change those fields datatype to decimal(10,2). This will solve your problem.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论