数据质量

坐标精度与浮点舍入误差

有一类坐标误差与底层地理编码的好坏毫无关系,而完全取决于得到的数字之后如何被存储、传输和计算。一组完全准确的坐标,仅仅因为在系统流转过程中的某个环节被表示为精度不足的数值类型,就可能产生明显的舍入误差。只要稍加有意识的注意,这类误差完全可以避免。

单精度浮点数(通常称为 float32)大约有七位有效十进制数字的精度。对于纬度或经度值,小数点前需要几位数字来表示整数度数部分,因此与双精度浮点数(通常称为 float64)表示同一数值相比,小数点后留下的真实精度位数明显更少。实际上,用 float32 而不是 float64 存储坐标,可能会引入一米或更大量级的舍入误差(具体取决于纬度),这与原始地理编码匹配本身存在的任何准确度限制完全无关,而且是叠加在其之上的。

这类误差很容易在不经意间引入,也很容易被忽略,因为它看起来一点也不像错误:得到的坐标仍然是一个合理、格式规范的数字,只是悄悄地偏离了原始值一点点。它通常通过以下途径混入:定义时数值精度不足的数据库列,默认使用比预期更窄数值类型的数据序列化格式,或者以低于管道其他部分的精度类型执行的中间计算,比如距离公式或坐标转换。

实用的建议很简单:在整个系统中端到端地使用双精度浮点数,或者具有足够位数的等效定点十进制类型来存储和计算坐标,而不仅仅是在首次接收坐标的环节这样做。请专门检查您的数据库结构,因为定义为比预期更窄类型的列,是造成这个问题最常见、也最容易被忽视的来源之一,它往往在项目早期引入,一旦运行得足以通过初始测试,就再也没人回头检查。同样也要检查系统之间的任何序列化层或 API 层,因为一些格式和库在没有明确指定的情况下默认使用单精度,恰恰在您最想不到去看的边界处悄悄降低了精度。

我们的正向逆地理编码端点返回的坐标带有完整的双精度十进制值。这种精度能否在您自己的存储和计算管道中保留下来,值得直接验证,而不是假定它会自动在每一步中都保持不变。