我有两个用于存储地理位置数据的字段,在我的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字段声明不正确吗?如果是,那么正确的是什么?几个不同的答案:
建议,如果不使用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相反。我的数字获得,而不是失败,准确!并且仅限于某些数字,并非总是如此。
答案 0 :(得分:2)
这不是因为Yii,而是因为浮点值如何存储在二进制系统上。
正如您可以阅读MySQL documentation“浮点值问题”:
浮点数有时会引起混淆,因为它们是 近似值并未存储为精确值。浮点值为 用SQL语句编写的值可能与值不同 内部代表。
Here you can find the great explanation通过示例解决了这个问题。正如你所看到的那样,数字可以变得更大,更小或者根本没有变化,但你总是要记住这只是一个近似值。
对于凝胶定位数据,您可以使用简单DECIMAL type来确保值在数据库中保持不变,或者使用Spacial Data type优化来存储和查询表示几何空间中定义的对象的数据。