我正在使用Sqlalchemy来定义我的表格,这是我提出的一些代码:
locations = Table('locations', Base.metadata,
Column("lat", Float(Precision=64), primary_key=True),
Column("lng", Float(Precision=64), primary_key=True),
)
我读somewhere纬度和经度需要比浮点数更精确,通常是双精度。所以我手动将精度设置为64,这是否足够?矫枉过正?这对我的情况有帮助吗?
答案 0 :(得分:6)
此处没有其他人提供具体数字,证明浮点数lat / long的最坏情况精度。我需要知道我正在做的事情,所以这是我的分析,以防它帮助其他人。
单精度浮点在有效数字中提供24位精度(数字的二进制指数表示法)。随着数字的整个部分变大,小数点后的位数下降。因此,纬度或经度的最坏情况精度是当幅度尽可能远离0时。假设你将纬度限制在[-90,90]和经度(-180,180),最坏情况将是经度为180的赤道。
在二进制中,180要求24位可用的8位,在小数点后留下16位。因此,在该经度下连续可表示的值之间的距离将是2 ^ -16度(约1.526E-5)。将该数字(以弧度表示)乘以赤道(6,378,137米)的地球WGS-84半径,得出最坏情况下的精度:
2^-16 deg * 6,378,137 m * PI rad / 180 deg = 1.6986 m (5.5728 ft).
对以弧度存储的纬度/经线进行的相同分析得出以下结果:
2^-22 rad * 6,378,137 m = 1.5207 m (4.9891 ft)
最后,如果将纬度标准化为范围[-1,1]并将经度标准化为范围(-1,1),则可以达到以下最差情况精度:
2^-24 * PI rad * 6,378,137 m = 1.1943 m (3.9184 ft)
因此,以弧度为单位存储纬度/长度可以为您提供大约7英寸的额外精度,并以标准化形式存储它们可以在1	 8"在最坏的情况下,还有更高的准确性。
如果在双精度和单精度之间进行转换时,您舍入(而不是截断),则单精度值将在上面计算的两个连续值之间距离的一半之内。
答案 1 :(得分:4)
这取决于您使用数据的内容。如果你使用浮子,如果你只需要它到大约米的细节水平就可以了。如果用户放大到远,使用图形应用程序中的数据将导致抖动效果。有关抖动的更多信息,请参阅Precisions, Precisions。希望这会有所帮助。
答案 2 :(得分:2)
更新:杰夫的回答有更好的分析。然而...
改进杰夫的回答:
如果将实际角度以弧度除以π,从而以0到±1的比例编码角度,那么应该可以使用有效数字的所有数字(23位(24 - 1符号位) ))。那么精度将是:
2^-23 * 6,378,137 m = 0.7603 m (76 cm)
我的老答案:
32位浮点数可以表示精度约为7.2的十进制数字的数字。这是一个近似值,因为浮点数实际上是二进制的,当转换为十进制时,有效位数可能会有所不同。
如果我们把它作为精确度的6位十进制数(为了安全起见),如果我们以度为单位存储纬度和经度,那么我们得到的精度约为精度的1/1000在最坏的情况下约111米。在最好的情况下,如果我们得到7个十进制数字的精度,精度将是大约11.1米。
使用弧度作为单位可以获得更好的精度。在最坏的情况下,我们得到的精度为千万分之一弧度,大约63米。在最好的情况下,它将是一个大约6米的弧度的百万分之一。
毋庸置疑,64位浮点数非常精确(在最坏的情况下约为6微米)。
答案 3 :(得分:0)
TL; DR:如果可接受一米的分辨率,则可接受单精度浮点存储度。
这个答案对聚会来说有点晚了,但是我自己需要一个可靠的答案,因此破解了一些代码以快速获取它。当然,还有一些更优雅的方法可以执行此操作,但是它看起来很有效。如Jeff所述,最坏的情况是在经度+/- 180度(即日期线)上。
根据下面的代码,使用单精度浮子存储度,单精度浮子在日期行的精度为0.85米。当接近本初子午线时,精度显着提高(至w / in mm)。
#include <stdio.h>
// per wikipedia, earth's circumference is 40,075.017 KM
#define METERS_PER_DEG (40075017 / 360.0)
// worst case scenario is near +/-180.0 (ie, the date line)
#define LONGITUDE 180.0
int main()
{
// subtract very small but increasingly larger values from
// 180.0 and recast as float until it no longer equals 180.0
double step = 1.0e-10;
int ctr = 1;
while ((float) LONGITUDE == (float) (LONGITUDE - (double) ctr * step)) {
ctr++;
}
double delta = (double) ctr * step;
printf("Longitude %f\n", LONGITUDE);
printf("delta %f (%d steps)\n", delta, ctr);
printf("meters: %f\n", delta * METERS_PER_DEG);
return 0;
}
此代码的输出是
Longitude 180.000000
delta 0.000008 (76294 steps)
meters: 0.849301