【问题标题】:Precision lost when storing CLLocationDegrees in MySQL在 MySQL 中存储 CLLocationDegrees 时精度丢失
【发布时间】:2013-02-03 15:58:02
【问题描述】:

我正在开发一个将 iOS 设备指定的 地标 存储到 MySQL 后端的小应用程序。当设备保存一个新的Placemark时,它会被插入到数据库中,并将新生成的 ID 发送回客户端。如果另一个设备尝试保存相同的 Placemark,服务器需要确定它已经存在于 DB 中,而不是插入并生成新 ID,它需要向客户端发送回该地标的现有 ID。

2 地标如果它们相同则相同:

  • 姓名
  • 纬度
  • 经度

因此,服务器尝试通过发出

来识别提交的地标是否已经存在

SELECT id FROM Placemark WHERE name=x, latitude=y, longitude=x

  • 在 iOS 中,latitudelongitude 以度为单位,类型为 CLLocationDegrees,由 <CoreLocation> 报告
  • 在 MySQL 中,latitudelongitude 定义为 DOUBLE


问题:
存储坐标时会丢失精度,例如:
50.09529561485427latidude 存储为50.0952956148543
-122.9893130423316longitude 存储为-122.989313042332

问题:
我可以在 MySQL 中使用不同的数据类型来完整地存储每个坐标吗?

注意事项:

  • 我无法将坐标存储为TEXTVARCHAR,因为我需要能够说出SELECT placemarks coordinates BETWEEN x AND y,或执行其他算术选择
  • 我不能使用 MySQL 的空间扩展,因为可移植性是一个问题,而且据我了解,空间数据类型在用作键时非常慢(而且我的用例需要按坐标选择)

任何帮助表示赞赏

【问题讨论】:

  • 除了你的问题,在谷歌地图中输入这两个坐标会给我一个几乎相同的位置(它相差几英尺)。你真的需要这么高的准确性吗?
  • 您好 DT。我建议将此问题作为stackoverflow.com/questions/12504208/… 的副本关闭——您可以很容易地使用 CLLocationDegrees 将该答案调整为您的问题。问候。
  • @Scott 请记住,我在 WHERE 子句中使用这些坐标。它们需要保持完整,不是因为我需要超级准确地识别地标,而是因为它们在后续搜索中用作键。
  • @DTs 浮点数据对于任何类型的键值都不是很好的选择——如果两个浮点数相同,甚至几乎不可能精确比较。您必须与 epsilon 进行比较。如果它依赖于保持精确值的浮点数,我会重新考虑你的程序架构。 - 如果它不用作键,而只是一个范围内的值,那么 scotts 推荐是有效的。

标签: mysql ios double core-location precision


【解决方案1】:

实际上进一步的测试揭示了以下奇怪的结果:当数据库驱动程序将数据绑定到查询语句时,精度丢失,数据实际插入数据库之前。

这有以下有趣的结果:即使我将键绑定到后续搜索查询,精度似乎也会以相同的方式丢失,因此几乎“意外”返回了正确的结果。即key(坐标)存储不正确,随后的selects也错误地转换了query key,但是以匹配的方式,因此找到了记录。鉴于由于精度损失导致的转换始终在同一平台(服务器)上执行,因此保持原样可能是安全的??或许不是,也许未来的迁移练习(即由于缩放)会使舍入误差变得明显。

Yawar 的指针将我引向 MySQL 的手册,该手册解释了浮点数可以在不损失精度的情况下存储为 DECIMAL:

“精确值数字文字有整数部分或小数部分,或两者兼有。它们可能有符号” http://dev.mysql.com/doc/refman/5.0/en/precision-math-decimal-changes.html

鉴于现有的解决方案似乎可行,那么问题就变成了,是保留 DB 数据类型 DOUBLE 还是切换到 DECIMAL 更好?

存储:
Latitude 的范围为 -90 to +90,而 iOS 似乎使用的精度为 14 decimals
Longitude 的范围为 -180 to +180,这就离开了iOS 上13 decimals 的精度

这意味着我们需要:
Latitude : DECIMAL(16,14),占用更少的 8 字节存储空间(每包 9d 4 字节)
Longitude:DECIMAL(16,13),同样需要少于 8 字节的存储空间

相比之下,DOUBLE 类型的列需要 8 个字节的存储空间。

速度(算术):
浮点运算几乎总是会更快,因为它是由硬件原生支持的

速度(搜索):
我相信DECIMAL 的索引与DOUBLE 的索引具有非常相似的运行时间。

结论:
切换到 DECIMAL 消除了精度错误,还减少了存储需求,在此用例中算术性能损失可以忽略不计。

【讨论】:

    【解决方案2】:

    不是将纬度和经度存储为双倍,而是乘以 1000000,转换为整数,然后存储。当然,如果您需要在应用中读取它们,请除以 1000000.0。

    这将为您提供足够的地标精度 (0.000001º),并消除您遇到的浮点转换和精度问题,并且占用的空间略少。我在自己的数据中使用它(它是二进制的,而不是 SQL)并将它们称为 MicroDegrees。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-13
      • 2016-08-22
      • 2018-12-08
      • 2013-06-17
      • 1970-01-01
      • 2012-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多