将双类型数据(地理定位)保存到数据库时,奇怪的(?)值会发生变化

tre*_*der 5 mysql double geolocation yii yii2

我有两个用于存储地理位置数据的字段,在我的MySQL数据库中定义为双精度数:

`address_geo_latitude` float(10,6) NOT NULL,
`address_geo_longitude` float(10,6) NOT NULL
Run Code Online (Sandbox Code Playgroud)

我正在使用Yii2的double验证器而不是用户传递的值:

public function rules()
{
    return [
        [['address_geo_latitude', 'address_geo_longitude'], 'double', 'min'=>0, 'max'=>360]
    ];
}
Run Code Online (Sandbox Code Playgroud)

(虽然我的测试似乎证明,这个问题与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字段声明不正确吗?如果是,那么正确的是什么?几个不同的答案:

建议,float(10,6)如果不使用MySQL的空间扩展,使用是最好的选择.

我的测试似乎证明,这个问题与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!
}
Run Code Online (Sandbox Code Playgroud)

我的问题与相反.我的数字增加,而不是失败,准确!只有某些数字,并非总是如此.

Biz*_*ley 3

发生这种情况不是因为 Yii,而是因为浮点值在二进制系统上的存储方式。

正如您可以在MySQL 文档“Problems with Floating-Point Values”中读到的:

浮点数有时会引起混乱,因为它们是近似值,而不是存储为精确值。SQL 语句中写入的浮点值可能与内部表示的值不同。

在这里你可以找到这个问题的很好的解释和例子。正如您所看到的,数字可能会变大、变小或根本不变,但您始终必须记住这只是一个近似值。

对于地理位置数据,您可以使用简单的DECIMAL 类型来确保值在数据库中存储不变,或使用优化的空间数据类型来存储和查询表示几何空间中定义的对象的数据。