ChatGPT解决这个技术问题 Extra ChatGPT

存储纬度和经度的正确/最佳类型

在 C、C++ 或 D 等系统级编程语言中,存储纬度和经度的最佳类型/编码是什么?

我看到的选项是:

IEEE-754 FP 作为度数或弧度

度或弧度存储为 32 或 64 位 int 中的定点值

整数范围到度数范围的映射:-> deg = (360/2^32)*val

度、分、秒和小数秒作为位字段存储在 int 中

某种结构。

简单解决方案 (FP) 的主要缺点是它具有高度不均匀的分辨率(在英国的某个地方它可以以微米为单位进行测量,而在日本则不能)。这也有FP比较和诸如此类的所有问题。其他选项需要在数据生命周期的不同部分付出额外的努力。 (生成、演示、计算等)

一个有趣的选项是浮动精度类型,随着纬度的增加,它得到更多的位,而经度变得更少(当它们靠近两极时)。

不完全涵盖这一点的相关问题:

在 MySQL 中存储纬度/经度时使用的理想数据类型是什么

在 Java 中处理纬度/经度值

顺便说一句:32 位在赤道处为您提供约 0.3 英寸的 E/W 分辨率。这接近高级 GPS 设置可以工作的规模(IIRC 在某些模式下它们可以降至约 0.5 英寸)。

OTOH,如果 32 位均匀分布在地球表面,您可以索引一侧约 344m 的正方形,5 字节给出 21m、6B->1.3m 和 8B->5mm。

我现在还没有具体的用途,但以前曾使用过这种东西,并希望在某个时候再次使用。

您已经在几个答案评论和这个问题中提到了解决问题。你需要什么分辨率?还值得说明您还需要执行哪些操作。如果您要进行大圆计算,那么无论如何您都需要转换为双精度/浮点数。
64 位双精度浮点值不是比 32 位 int 更好的选择,因为它具有更大的粒度吗?这是你评论过的东西。它也更容易使用。

C
Community

最简单的方法是将其存储为度数的浮点数/双精度数。 N 和 E 为正,S 和 W 为负。请记住,分钟和秒是 60 分之内的(所以 31 45'N 是 31.75)。通过查看它们很容易理解这些值是什么,并且在必要时转换为弧度是微不足道的。

纬度和经度的计算(例如两个坐标之间的 Great Circle 距离)在很大程度上依赖于三角函数,该函数通常使用双精度数。任何其他格式将至少依赖于正弦、余弦、atan2 和平方根的另一种实现。任意精度数(例如 Java 中的 BigDecimal)对此不起作用。像 int 这样 2^32 均匀分布的东西也会有类似的问题。

几条评论都提到了一致性的问题。在这一点上,我将简单地指出,就经度而言,地球是不均匀的。北极圈的一角秒经度比赤道的距离短。双精度浮子在地球上的任何地方都能提供亚毫米级的精度。这还不够吗?如果不是,为什么不呢?

还值得注意的是,您希望如何处理这些信息,因为您需要的计算类型将对您使用的存储格式产生影响。


一个有效的观点,但没有解决我希望解决的问题。
这个答案也是我会给出的 - 如果它没有回答它,认为你需要澄清你的问题。
我同意这回答了所问的问题。我使用过的大多数商业系统都在内部使用 FP 度或弧度。缺乏或统一性是纬度和经度定义的函数,而不是它们的存储方式。
不要忘记 C(和大多数语言)中的数学函数需要以弧度表示的参数。任何以度为单位存储值的系统都需要在使用数学函数之前转换为弧度。这并不意味着以度数存储是错误的。事实上,这可能是最好的。但请注意。
J
John D. Cook

经度和纬度通常不会比 32 位浮点数更精确。因此,如果您担心存储空间,可以使用浮点数。但总的来说,将数字用作双精度数会更方便。

弧度对于理论数学来说更方便。 (例如,仅当您使用弧度时,正弦的导数才是余弦。)但是度数通常对人们来说更熟悉且更容易解释,因此您可能希望坚持使用度数。


一个有效的观点,但没有解决我希望解决的问题。 (我已经编辑了问题以澄清)
你需要什么分辨率?
@cletus,统一分辨率比高分辨率更有趣,但 32 位均匀分布在我认为需要的任何数量级之内。
请记住,至少在经度方面,地球并不统一。北极圈的 1 秒经度与赤道的距离不同。为什么你想要/需要统一性?
FP 之所以有效,是因为大多数情况下,该数字已知的分辨率与其大小成正比。对于纬度/经度,零点是完全任意的,因此不存在比例性。使用 n 位似乎很糟糕,然后在某些地方将其中一些用于无用的分辨率。
P
Pykler

根据这篇关于 Decimal Degrees 的维基百科文章,精度为 8 的十进制表示应该绰绰有余。

0 decimal places, 1.0 = 111 km
...
7 decimal places, 0.0000001 = 1.11 cm
8 decimal places, 0.00000001 = 1.11 mm

log_2(365*10^8) ~= 35 因此需要 ~70 位,四舍五入到字节:9 字节。均匀分布,9 个字节可以解析为 0.1 mm^2 的区域。
错什么?它需要 35 位,而 7 则需要不到 32 位,因此如果您在进行计算时将它们转换为双精度,则 int 足以存储 365 度和小数点后 7 位。
R
Roland Pihlakas

http://www.esri.com/news/arcuser/0400/wdside.html
在赤道,经度角秒大约等于纬度角秒,即 1/60 海里(或 101.27 英尺或 30.87 米)。

32 位浮点数包含 23 位显式数据。
180 * 3600 需要 log2(648000) = 19.305634287546711769425914064259 位数据。请注意,符号位是单独存储的,因此我们只需要计算 180 度。
如果将值 648000 标准化为 2 的某个幂,则适用以下计算。
在从 23 中减去 log2(648000) 的位后,我们剩下的额外 3.694365712453288230574085935741 位用于亚秒级数据。
即每秒 2 ^ 3.694365712453288230574085935741 = 12.945382716049382716049382716053 份。
因此,浮点数据类型在赤道处可以具有 30.87 / 12.945382716049382716049382716053 ~= 2.38 米的精度。

如果您将 180 度值标准化为 2 的某个幂,上述计算是精确的。否则假设亚度精度存储在小数点之后,浮点表示将物理上使用所有 8 位度数部分。这为亚度精度留下了 15 位。然后 15 - log2(3600) 使 3.1862188087829629413518832531256 位用于亚秒级数据,或 3.3914794921875 ~= 3.39 米的赤道精度。这比标准化所能提供的大约少一米。


V
V. Wheeler

好问题!

我知道这个问题现在已经有 9 年了,我只知道你正在寻找的答案的一部分,但我刚来这里有一个类似的问题,自从提出这个问题以来,很多事情都发生了变化,例如可用的硬件和 GPS .我经常在处理不同类型应用程序中不同类型 GPS 的固件中使用这个主题,并且已经忘记了我为我使用过的不同应用程序制定“最佳设计”所花费的时间(和天数)或发达。

与往常一样,不同的解决方案将提供收益和成本,最终,“最佳设计”始终是收益和成本与系统要求的“最佳匹配”。当我问同样的问题时,我必须考虑以下几点:

CPU时间成本

如果 CPU 没有内置的浮点协处理器(许多微控制器就是这种情况),那么处理“float”、“double”和“long double”可能会非常昂贵。例如,对于我经常使用的一个 16 位微控制器,使用“双”值的乘法需要 326 个 CPU 时钟周期,而除法需要 1193 个时钟周期。非常贵!

准确性权衡

在赤道,一个'float'(IEEE-754 32位浮点值),需要表示一个有符号度数,假设能表示7个“干净”的有效十进制数字,一个最低有效十进制数字的变化(例如从 179.9999 到 180.0000)将代表大约 11.12 米的距离。这可能满足也可能不满足硬系统精度要求。而“双”(表示 15 个“干净”的有效十进制数字,因此从 179.999999999999 变为 180.000000000000)表示大约 0.00011 毫米。

输入精度限制

如果您正在处理来自 GPS 的输入,您将获得多少位的真实准确度,以及您需要保留多少位?

开发时间成本

IEEE-754 64 位双精度值 ('double') 和 32 位单精度值 ('float') 在 C 语言中处理起来非常方便,因为几乎每个 C 编译器都附带了两者的数学库,并且通常非常可靠。如果您的 CPU 带有硬件浮点处理器,这是一个简单的选择。

RAM 和存储成本

如果您必须将大量这些值保存在 RAM(或存储,例如 MYSQL)中,可用 RAM(和存储空间)可能会影响解决方案的可操作性。

可用数据与所需数据

我在写这篇文章时处理的一个例子(我来这里回答这个问题的原因)是我正在处理一个 u-blox M8 GPS,它能够给我二进制 GPS 信息(节省翻译 ASCII NMEA 的 CPU 开销句子)。在这种二进制格式(称为“UBX 协议”)中,纬度和经度表示为带符号的 32 位整数,该表示能够表示(在赤道处)低至约 1.11 厘米的精度。例如,-105.0269805 度经度表示为 -1050269805(使用所有 32 位),一个 LSb 变化表示任何地方的纬度变化约 1.11 厘米,赤道经度变化 1.11 厘米(高纬度地区更小,与余弦成正比)纬度)。此 GPS 所在的应用程序执行导航任务,这(已经存在且经过良好测试的代码)需要“双重”数据类型。不幸的是,将此整数转换为 IEEE-754 64 位“双精度”并不容易,只需将整数的基数 2 位移动到“双精度”的内部表示位,因为要执行的小数移位是以 10 为底的十进制移位。如果它是一个以 2 为底的十进制移位,那么整数的以 2 为底的位可以移动到“双”的位域中,而只需要很少的翻译。但唉,这不是我有符号整数的情况。因此,在没有硬件浮点处理器的 CPU 上进行乘法运算将花费我:326 个 CPU 时钟周期。

double   ldLatitude;
int32_t  li32LatFromGps;
ldLatitude = (double)li32LatFromGps * 0.0000001;

请注意,此乘法是在此基础上选择的:

ldLatitude = (double)li32LatFromGps / 10000000.0;

因为在我正在处理的 CPU 上,“双”乘法比“双”除法快 3.6 倍。这就是微控制器世界的生活。 :-)

如果导航任务可以直接使用 32 位有符号整数来完成,那将是非常棒的(如果我能在周末抽出时间的话,将来可能会如此)!那么就不需要转换了……但是用这样一个整数做导航任务会不会花费更多? CPU成本,可能效率更高。开发时间成本?这是另一个问题,尤其是在已经使用 IEEE-754 64 位“双”值的经过充分测试的系统的情况下!另外,已经存在提供地图数据的软件(使用“双”度值),该软件也必须转换为使用有符号整数——这不是一夜之间的任务!

一个非常有趣的选择是使用原始纬度/经度整数直接(不进行平移)表示“矩形”(实际上是梯形,在两极处变成三角形)的近似值之间的交点。在赤道,这些矩形的东西尺寸约为 1.11 厘米,南北尺寸约为 1.11 厘米,而在英国伦敦的纬度上,尺寸约为东西尺寸 0.69 厘米,南北尺寸约为 1.11 厘米。这可能不容易处理,也可能不容易处理,这取决于应用程序需要什么。

无论如何,我希望这些想法和讨论能帮助其他正在关注这个主题的人,为他们的系统寻找“最佳设计”。

亲切的问候,维克


换句话说,双倍。
注意:我已经实现了导航任务以直接使用 32 位有符号整数而不是“双精度”。而且速度非常快!
a
aij

什么编码是“最好的”实际上取决于您的目标/要求。

如果您正在执行算术,浮点纬度,经度通常很方便。其他时候笛卡尔坐标(即x,y,z)可能更方便。例如,如果您只关心地球表面上的点,您可以使用 n-vector

至于长期存储,IEEE 浮点将浪费位用于您不关心的范围(对于纬度/经度)或在笛卡尔坐标的情况下您可能不关心的精度(除非您希望在原点有非常好的精度无论出于何种原因)。您当然可以将任一类型的坐标映射到您喜欢的大小的整数,这样整个整数范围就可以覆盖您关心的分辨率下您感兴趣的范围。

当然,除了在编码中不浪费比特之外,还有其他事情需要考虑。例如,(Geohashes)[https://en.wikipedia.org/wiki/Geohash] 有一个很好的特性,即在同一区域很容易找到其他 geohashes。 (大多数将具有相同的前缀,您可以计算其他的前缀。)不幸的是,它们在赤道附近和两极附近保持相同的经度精度。我目前正在使用 64 位 geohashes 进行存储,它在赤道处提供大约 3 m 的分辨率。

Maidenhead Locator System 具有一些相似的特征,但似乎更适合于在人与人之间交流位置,而不是存储在计算机上。 (存储 MLS 字符串会浪费大量位用于一些相当微不足道的错误检测。)

我发现确实以不同方式处理两极的一个系统是 Military Grid Reference System,尽管它似乎也更面向人类交流。 (从或转换为纬度/经度似乎很痛苦。)

根据您确切想要的内容,您可以在两极附近使用类似于 Universal polar sereographic coordinate system 的东西,以及在世界其他地方使用比 UTM 更合理的东西,并且最多使用一位来指示两个系统中的哪一个你正在使用。我最多说一点,因为您关心的大多数点不太可能在两极附近。例如,您可以使用“半位”,说 11 表示使用极坐标系统,而 00、01 和 10 表示使用其他系统,并且是表示的一部分。

对不起,这有点长,但我想保存我最近学到的东西。遗憾的是,我还没有找到任何标准、理智和有效的方法来以统一的精度表示地球上的一个点。

编辑:我发现另一种方法看起来更像你想要的,因为它更直接地利用了靠近两极的经度所需的较低精度。事实证明,有很多关于存储法线向量的研究。 Encoding Normal Vectors using Optimized Spherical Coordinates 描述了这样一种系统,用于对法线向量进行编码,同时保持最低水平的准确性,但它也可以用于地理坐标。


C
Christoph

您提到的浮点值问题可能会成为问题吗?如果答案是否定的,我建议只使用双精度的弧度值 - 如果您要进行三角计算,您将需要它。

如果使用双精度时可能存在精度损失问题,或者您不会进行三角函数,我建议您将解决方案映射到整数范围 - 这将为您提供最佳分辨率,可以轻松转换为任何显示格式您所在的语言环境将使用并且 - 在选择适当的 0 子午线后 - 可用于转换为高精度的浮点值。

PS:我一直想知道为什么似乎没有人使用地心球坐标——它们应该相当接近地理坐标,并且不需要所有这些关于球体的花哨数学来进行计算;为了好玩,我想将 Gauss-Krüger-Koordinaten(由德国 Katasteramt 使用)转换为 GPS 坐标 - 让我告诉你,这很难看:一个使用 Bessel 椭球,另一个 WGS84 和 Gauss-Krüger映射本身就很疯狂......


@Greg:Gauss-Krüger 坐标来自圆柱投影,但经过“增强”,因此在地图上使用标尺时可以获得有意义的结果(对于“有意义”的某些值;))。这一切都始于我想:嘿,这不应该太复杂......
G
Greg Hewgill

0.3 英寸的分辨率正在下降到几年后地震会产生影响的地步。您可能需要重新考虑为什么您认为在全球范围内需要如此精细的分辨率。

太平洋中的一些传播中心的变化幅度高达 15 cm/year


0.3 英寸适用于统一的情况。使用 32 位 FP,他知道你得到的东西,因为很多(大多数?)值不再有效。
J
John W. Phillips

一个 Java 程序,用于计算将 lat/long 值转换为 Float/Double 的最大舍入误差(以米为单位):

import java.util.*;
import java.lang.*;
import com.javadocmd.simplelatlng.*;
import com.javadocmd.simplelatlng.util.*;

public class MaxError {
  public static void main(String[] args) {
    Float flng = 180f;
    Float flat = 0f;
    LatLng fpos = new LatLng(flat, flng);
    double flatprime = Float.intBitsToFloat(Float.floatToIntBits(flat) ^ 1);
    double flngprime = Float.intBitsToFloat(Float.floatToIntBits(flng) ^ 1);
    LatLng fposprime = new LatLng(flatprime, flngprime);

    double fdistanceM = LatLngTool.distance(fpos, fposprime, LengthUnit.METER);
    System.out.println("Float max error (meters): " + fdistanceM);

    Double dlng = 180d;
    Double dlat = 0d;
    LatLng dpos = new LatLng(dlat, dlng);
    double dlatprime = Double.longBitsToDouble(Double.doubleToLongBits(dlat) ^ 1);
    double dlngprime = Double.longBitsToDouble(Double.doubleToLongBits(dlng) ^ 1);
    LatLng dposprime = new LatLng(dlatprime, dlngprime);

    double ddistanceM = LatLngTool.distance(dpos, dposprime, LengthUnit.METER);
    System.out.println("Double max error (meters): " + ddistanceM);
  }
}

输出:

Float max error (meters): 1.7791213425235692
Double max error (meters): 0.11119508289500799

A
Alex Medveshchek

正如@Roland Pihlakas 已经指出的那样,这取决于您要使用坐标的精度。

我只是建议另一种观点:

地球的赤道周长(周长)为 40.000 公里;

这等于 40M 米,即 40 亿厘米;

32 位变量包含 2^32 或约 42 亿个不同的值,这比所提到的周长中的厘米数多一点。

这意味着,如果我们为纬度和经度选择 32 位整数值,它将允许我们以 < 1 厘米的精度定位地球上的一个点。

使用浮点值:float32 包含 23 个有效位 => ~4.7 米精度 float64 包含 52 个有效位 => < 1 mm 精度

float32 包含 23 个有效位 => ~4.7 米精度

float64 包含 52 个有效位 => < 1 mm 精度


n
natevw

如果“存储”是指“保存在记忆中”,那么真正的问题是:你打算如何处理它们?

我怀疑在这些坐标做任何有趣的事情之前,它们会通过 math.h 中的函数以弧度的形式汇集。除非您计划实现相当多的超越函数,这些函数在打包到位字段中的 Deg/Min/Secs 上运行。

那么,为什么不让事情变得简单,并按照您的要求将它们存储在 IEEE-754 度或弧度中呢?


因为在记忆中,是的,没有多少能打败 IEEE。另一方面,如果您在磁盘上存储大量点(例如高分辨率矢量图)或通过电线传送它们......
A
Augustin

以下代码将 WGS84 坐标无损地打包成一个无符号长整数(即 8 个字节):

using System;
using System.Collections.Generic;
using System.Text;

namespace Utils
{
    /// <summary>
    /// Lossless conversion of OSM coordinates to a simple long.
    /// </summary>
    unsafe class CoordinateStore
    {
        private readonly double _lat, _lon;
        private readonly long _encoded;

        public CoordinateStore(double lon,double lat)
        {
            // Ensure valid lat/lon
            if (lon < -180.0) lon = 180.0+(lon+180.0); else if (lon > 180.0) lon = -180.0 + (lon-180.0);
            if (lat < -90.0) lat = 90.0 + (lat + 90.0); else if (lat > 90.0) lat = -90.0 + (lat - 90.0);

            _lon = lon; _lat = lat;

            // Move to 0..(180/90)
            var dlon = (decimal)lon + 180m;
            var dlat = (decimal)lat + 90m;

            // Calculate grid
            var grid = (((int)dlat) * 360) + ((int)dlon);

            // Get local offset
            var ilon = (uint)((dlon - (int)(dlon))*10000000m);
            var ilat = (uint)((dlat - (int)(dlat))*10000000m);

            var encoded = new byte[8];
            fixed (byte* pEncoded = &encoded[0])
            {
                ((ushort*)pEncoded)[0] = (ushort) grid;
                ((ushort*)pEncoded)[1] = (ushort)(ilon&0xFFFF);
                ((ushort*)pEncoded)[2] = (ushort)(ilat&0xFFFF);
                pEncoded[6] = (byte)((ilon >> 16)&0xFF);
                pEncoded[7] = (byte)((ilat >> 16)&0xFF);

                _encoded = ((long*) pEncoded)[0];
            }
        }

        public CoordinateStore(long source)
        {
            // Extract grid and local offset
            int grid;
            decimal ilon, ilat;
            var encoded = new byte[8];
            fixed(byte *pEncoded = &encoded[0])
            {
                ((long*) pEncoded)[0] = source;
                grid = ((ushort*) pEncoded)[0];
                ilon = ((ushort*)pEncoded)[1] + (((uint)pEncoded[6]) << 16);
                ilat = ((ushort*)pEncoded)[2] + (((uint)pEncoded[7]) << 16);
            }

            // Recalculate 0..(180/90) coordinates
            var dlon = (uint)(grid % 360) + (ilon / 10000000m);
            var dlat = (uint)(grid / 360) + (ilat / 10000000m);

            // Returns to WGS84
            _lon = (double)(dlon - 180m);
            _lat = (double)(dlat - 90m);
        }

        public double Lon { get { return _lon; } }
        public double Lat { get { return _lat; } }
        public long   Encoded { get { return _encoded; } }


        public static long PackCoord(double lon,double lat)
        {
            return (new CoordinateStore(lon, lat)).Encoded;
        }
        public static KeyValuePair<double, double> UnPackCoord(long coord)
        {
            var tmp = new CoordinateStore(coord);
            return new KeyValuePair<double, double>(tmp.Lat,tmp.Lon);
        }
    }
}

来源:http://www.dupuis.me/node/35


您甚至不能将两个双精度数(104 位)的尾数“无损”打包成 64 位。鸽巢原理。
@BCS:但是 GPS 并没有利用双打的全部可能范围。
你没说GPS。上述保存器可能比典型的 GPS 提供的精度更高,但这不是你所说的。 -- 另请注意,均匀分布的 8 个字节在地球表面上的最大精度约为 5 毫米,接近高端 GPS 实际可获得的约 10 毫米(并且比通过其他工具可获得的更长)。 -- 另外,我知道 GPS 不使用全范围,这就是为什么我只计算尾数位。
A
AlejandroAlis

最小尺寸的最佳精度是 int32。

存储 7 个小数位(1.11 厘米误差)经度双精度数为您提供 +/-1.800.000.000 的数字,非常适合存储在 int32 中,您只需将双精度数乘以 10M 即可

int32_t lng = (int32_t)(double_lng * 10000000);

说明 (wikipedia)

赤道被划分为 360 度经度,因此赤道处的每一度代表 111,319.5 米(111.32 公里)。然而,当一个人从赤道向极点移动时,经度的一个度数乘以纬度的余弦,距离减小,在极点接近零。赤道处 1 厘米精度所需的小数位数为 7。如果您需要将 180º 和 7 位小数存储在整数中,则结果将是 1.800.000.000 数字,该数字在 32 位整数范围内。

正如您在 Google 地图中看到的,当您单击任何位置时,Golge 会为您提供适合 32 位整数的 6 位小数浮点数。

比较:

vs double -> Half size vs float -> Float 没有足够的精度 vs 24 位建议:任何 32 位或 64 位处理器都无法寻址 24 位,您必须获取三个字节,然后转换为 int32 或 double an then操作,丢失了很多 cicles 和许多行代码


这不涉及纬度。 32 位均匀分布在地球表面,粒度约为 0.1 km^2; 〜300米。这是相当精细的。扩展您的编码以对纬度执行相同的操作需要 64 位,可以解析到 27mm^2,这大约是您的编码所能提供的一半。大约 1cm 分辨率的理想编码应该可以使用大约 62 位。
是什么让每个维度有 6-7 个摘要是理想的?如果您不介意约 2m 的精度,您可以使用 4-5(即 24bits/dim)并节省两个字节。为什么不理想?我并不是说您的编码不起作用,我是说您(几乎)没有试图说明为什么应该使用它而不是替代品。
FWIW:在 C/C++ 中使用位字段允许在任何位使用干净的语法进行紧凑存储,并且对于许多现代 CPU,如果数据已经在 L1 缓存中,则只有在流水线后才能看到提取未对齐值的位旋转,并且那时可能还没有。
t
tegtmeye

在自己寻找答案后遇到这个问题后,这是基于一些先例的另一种可能的方案。

网络工作组 RFC 3825 为 DHCP(即在网络上分发 IP 地址的系统)提出了基于坐标的地理位置选项。请参阅https://tools.ietf.org/rfc/rfc3825.txt

在该方案中,纬度和经度以度为单位编码,具有定点值,其中前 9 位是有符号度,25 位是小数度,6 位用于精度。精度位的值表示被认为是准确的 25 个小数位的数量(例如,通过消费者 GPS 与高精度测量员 GPS 收集的坐标)。使用 WGS84,精度为 8 位十进制数字,无论您在地球上的哪个位置,都可以达到大约一毫米。

正如其他一些人所发布的那样,浮点编码确实不适合这种类型的事情。是的,它可以表示非常多的小数位数,但准确性要么被忽略,要么必须在其他地方处理。例如,打印具有全浮点精度的浮点数或双精度数会导致带有十进制数字的数字不太可能是远程准确的。同样,简单地输出具有 8 或 10 位精度的浮点数或双精度数,根据浮点数的计算方式,很多都不是源值的真实表示(例如,为什么 1.2-1.0 不等于 0.2 使用浮点算术) .

有关为什么您应该关心坐标系精度的幽默示例,请参阅 https://xkcd.com/2170/

当然,RFC 3825 中使用的 40 位编码在 32 或 64 位世界中几乎不方便,但这种风格可以很容易地扩展到 64 位数字,其中 9 位用于有符号度,6 位用于精度,保留 49 位作为小数部分。这会产生 15 位十进制数字的精度,这基本上比任何人都需要的多(参见幽默示例)。


b
bluish

您可以使用 decimal 数据类型:

CREATE TABLE IF NOT EXISTS `map` (
  `latitude` decimal(18,15) DEFAULT NULL,
  `longitude` decimal(18,15) DEFAULT NULL 
);