将双类型数据(地理定位)保存到数据库时发生奇怪的(?)值变化
Strange (?) value change when saving double-type data (geolocation) into database
我有两个字段用于存储地理位置数据,在我的 MySQL 数据库中定义为双精度:
`address_geo_latitude` float(10,6) NOT NULL,
`address_geo_longitude` float(10,6) NOT NULL
我正在使用 Yii2 的 double
验证器来验证用户传递的值:
public function rules()
{
return [
[['address_geo_latitude', 'address_geo_longitude'], 'double', 'min'=>0, 'max'=>360]
];
}
(虽然我的测试似乎证明,这个问题与 Yii2 验证器无关)
在测试期间,我观察到值的奇怪(?)变化,即:
359.90
变成359.899994
(0,000006
区别),
359.80
变成359.799988
(0,000012
区别),
311.11
变成311.109985
(0,000015
区别),
255.55
变成255.550003
(-0,000003
区别),
205.205
变成205.205002
(-0,000002
区别),
105.105
变为 105.105003
(-0,000003
差异)。
但是:
359.899994
仍然是 359.899994
,
311.109985
仍然是 311.109985
,
311
仍然是 311
,
255
仍然是 255
,
200
仍然是 200
,
75.75
仍然是 75.75
,
11.11
仍然是 11.11
。
我错过了什么?我看不到这些背后的任何模式或逻辑。
这是因为我对这种数据的 MySQL 字段声明不正确吗?如果是,那么正确的是什么?几个不同的答案:
- Database/SQL: How to store longitude/latitude data?
- What datatype to use when storing latitude and longitude data in SQL databases?
- What is the ideal data type to use when storing latitude / longitudes in a MySQL database?
建议,如果不使用 MySQL 的 spatial extensions.
,则使用 float(10,6)
是最佳选择
我的测试似乎证明,这个问题与 Yii2 验证器无关,因为值在从数据库重新读取之前一直保持正确:
print_r(Yii::$app->request->post()); //Correct!
print_r($lab->address_geo_latitude); //Correct!
if ($lab->load(Yii::$app->request->post(), 'Lab') && $lab->save()) {
print_r($lab->address_geo_latitude); //Correct!
$lab2 = $this->findModel($lab->id);
print_r($lab2->address_geo_latitude); //<-- HERE! Incorrect!
}
我的问题与this one相反。我的数字 增加 ,不输,准确!并且只针对某些数字,并非总是如此。
这不是因为 Yii,而是因为浮点值在二进制系统中的存储方式。
您可以在 MySQL documentation "Problems with Floating-Point Values" 中阅读:
Floating-point numbers sometimes cause confusion because they are
approximate and not stored as exact values. A floating-point value as
written in an SQL statement may not be the same as the value
represented internally.
Here you can find the great explanation 这个问题有例子。如您所见,数字可能会变大、变小或根本不变,但您始终必须记住,这只是一个近似值。
对于地理定位数据,您可以使用简单的 DECIMAL type to make sure values are stored unchanged in database or use Spacial Data type 优化来存储和查询表示在几何 space 中定义的对象的数据。
我有两个字段用于存储地理位置数据,在我的 MySQL 数据库中定义为双精度:
`address_geo_latitude` float(10,6) NOT NULL,
`address_geo_longitude` float(10,6) NOT NULL
我正在使用 Yii2 的 double
验证器来验证用户传递的值:
public function rules()
{
return [
[['address_geo_latitude', 'address_geo_longitude'], 'double', 'min'=>0, 'max'=>360]
];
}
(虽然我的测试似乎证明,这个问题与 Yii2 验证器无关)
在测试期间,我观察到值的奇怪(?)变化,即:
359.90
变成359.899994
(0,000006
区别),359.80
变成359.799988
(0,000012
区别),311.11
变成311.109985
(0,000015
区别),255.55
变成255.550003
(-0,000003
区别),205.205
变成205.205002
(-0,000002
区别),105.105
变为105.105003
(-0,000003
差异)。
但是:
359.899994
仍然是359.899994
,311.109985
仍然是311.109985
,311
仍然是311
,255
仍然是255
,200
仍然是200
,75.75
仍然是75.75
,11.11
仍然是11.11
。
我错过了什么?我看不到这些背后的任何模式或逻辑。
这是因为我对这种数据的 MySQL 字段声明不正确吗?如果是,那么正确的是什么?几个不同的答案:
- Database/SQL: How to store longitude/latitude data?
- What datatype to use when storing latitude and longitude data in SQL databases?
- What is the ideal data type to use when storing latitude / longitudes in a MySQL database?
建议,如果不使用 MySQL 的 spatial extensions.
,则使用float(10,6)
是最佳选择
我的测试似乎证明,这个问题与 Yii2 验证器无关,因为值在从数据库重新读取之前一直保持正确:
print_r(Yii::$app->request->post()); //Correct!
print_r($lab->address_geo_latitude); //Correct!
if ($lab->load(Yii::$app->request->post(), 'Lab') && $lab->save()) {
print_r($lab->address_geo_latitude); //Correct!
$lab2 = $this->findModel($lab->id);
print_r($lab2->address_geo_latitude); //<-- HERE! Incorrect!
}
我的问题与this one相反。我的数字 增加 ,不输,准确!并且只针对某些数字,并非总是如此。
这不是因为 Yii,而是因为浮点值在二进制系统中的存储方式。
您可以在 MySQL documentation "Problems with Floating-Point Values" 中阅读:
Floating-point numbers sometimes cause confusion because they are approximate and not stored as exact values. A floating-point value as written in an SQL statement may not be the same as the value represented internally.
Here you can find the great explanation 这个问题有例子。如您所见,数字可能会变大、变小或根本不变,但您始终必须记住,这只是一个近似值。
对于地理定位数据,您可以使用简单的 DECIMAL type to make sure values are stored unchanged in database or use Spacial Data type 优化来存储和查询表示在几何 space 中定义的对象的数据。