In a system level programming language like C, C++ or D, what is the best type/encoding for storing latitude and longitude?
在C,C ++或D等系统级编程语言中,存储纬度和经度的最佳类型/编码是什么?
The options I see are:
我看到的选项是:
- IEEE-754 FP as degrees or radians
- degrees or radians stored as a fixed point value in an 32 or 64 bit int
- mapping of an integer range to the degree range: ->
deg = (360/2^32)*val
- degrees, minutes, seconds and fractional seconds stored as bit fields in an int
- a struct of some kind.
IEEE-754 FP为度或弧度
度或弧度存储为32或64位int中的固定点值
将整数范围映射到度数范围: - > deg =(360/2 ^ 32)* val
度,点,秒和小数秒存储为int中的位字段
某种结构。
The easy solution (FP) has the major down side that it has highly non uniform resolution (somewhere in England it can measure in microns, over in Japan, it can't). Also this has all the issues of FP comparison and whatnot. The other options require extra effort in different parts of the data's life cycle. (generation, presentation, calculations etc.)
简易解决方案(FP)具有主要的缺点,它具有高度不均匀的分辨率(在英格兰的某个地方,它可以以微米为单位,在日本可以测量,但不能)。此外,还有FP比较的所有问题和诸如此类的问题。其他选项需要在数据生命周期的不同部分进行额外的努力。 (代,演示,计算等)
One interesting option is a floating precision type that where as the Latitude increase it gets more bits and the Longitude gets less (as they get closer together towards the poles).
一个有趣的选择是浮动精度类型,其中随着纬度增加它获得更多位并且经度变得更少(当它们朝向极点靠近时)。
Related questions that don't quite cover this:
相关问题并未完全涵盖此问题:
- What is the ideal data type to use when storing latitude / longitudes in a MySQL
- Working with latitude/longitude values in Java
在MySQL中存储纬度/经度时使用的理想数据类型是什么
在Java中使用纬度/经度值
BTW: 32 bits gives you an E/W resolution at the equator of about 0.3 in. This is close to the scale that high grade GPS setups can work at (IIRC they can get down to about 0.5 in in some modes).
顺便说一句:32位在赤道上的E / W分辨率约为0.3英寸。这接近于高等级GPS设置可以工作的规模(IIRC,它们在某些模式下可以降至约0.5英寸)。
OTOH if the 32 bits is uniformly distributed over the earth's surface, you can index squares of about 344m on a side, 5 Bytes give 21m, 6B->1.3m and 8B->5mm.
OTOH如果32位均匀分布在地球表面,则可以在一侧为大约344m的正方形,5 Bytes给出21m,6B-> 1.3m和8B-> 5mm。
I don't have a specific use in mind right now but have worked with this kind of thing before and expect to again, at some point.
我现在没有特定的用途,但之前已经使用过这种东西,并且在某些时候再次期待。
12 个解决方案
#1
The easiest way is just to store it as a float/double in degrees. Positive for N and E, negative for S and W. Just remember that minutes and seconds are out of 60 (so 31 45'N is 31.75). Its easy to understand what the values are by looking at them and, where necessary, conversion to radians is trivial.
最简单的方法是将其存储为浮点数/双精度。 N和E为正,S和W为负。只需记住分数和秒数超过60(因此31 45'N为31.75)。通过查看它们很容易理解值是什么,并且在必要时,转换为弧度是微不足道的。
Calculations on latitudes and longitudes such as the Great Circle distance between two coordinates rely heavily on trigonometric functions, which typically use doubles. Any other format is going to rely on another implementation of sine, cosine, atan2 and square root, at a minimum. Arbitrary precision numbers (eg BigDecimal in Java) won't work for this. Something like the int where 2^32 is spread uniformly is going to have similar issues.
纬度和经度的计算,例如两个坐标之间的大圆距离,很大程度上依赖于三角函数,三角函数通常使用双精度。任何其他格式都将依赖于正弦,余弦,atan2和平方根的另一种实现。任意精度数字(例如Java中的BigDecimal)都不适用于此。类似于int ^ 2 32统一传播的东西会有类似的问题。
The point of uniformity has come up in several comments. On this I shall simply note that the Earth, with respect to longitude, isn't uniform. One arc-second longitude at the Arctic Circle is a shorter distance than at the Equator. Double precision floats give sub-millimetre precision anywhere on Earth. Is this not sufficient? If not, why not?
一些评论中提出了统一性。在此,我将简单地指出,地球在经度方面并不统一。北极圈的一弧秒经度比赤道的距离短。双精度浮标可在地球上的任何位置提供亚毫米级精度。这还不够吗?如果没有,为什么不呢?
It'd also be worth noting what you want to do with that information as the types of calculations you require will have an impact on what storage format you use.
同样值得注意的是您要对该信息做什么,因为您需要的计算类型会对您使用的存储格式产生影响。
#2
Longitudes and latitudes are not generally known to any greater precision than a 32-bit float. So if you're concerned about storage space, you can use floats. But in general it's more convenient to work with numbers as doubles.
通常不知道经度和纬度比32位浮点更精确。因此,如果您担心存储空间,可以使用浮动。但总的来说,将数字作为双精度数更方便。
Radians are more convenient for theoretical math. (For example, the derivative of sine is cosine only when you use radians.) But degrees are typically more familiar and easier for people to interpret, so you might want to stick with degrees.
Radians对理论数学更方便。 (例如,只有当你使用弧度时,正弦的导数才是余弦。)但是度数通常更熟悉,更容易让人们解释,所以你可能想要坚持学位。
#3
A Decimal representation with precision of 8 should be more than enough according to this wikipedia article on 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
#4
Might the problems you mentioned with floating point values become an issue? If the answer is no, I'd suggest just using the radians value in double precision - you'll need it if you'll be doing trigonometric calculations anyway.
您提到的浮点值问题可能成为问题吗?如果答案是否定的,我建议只使用双精度的弧度值 - 如果你要进行三角计算,你将需要它。
If there might be an issue with precision loss when using doubles or you won't be doing trigonometry, I'd suggest your solution of mapping to an integer range - this will give you the best resolution, can easily be converted to whatever display format you're locale will be using and - after choosing an appropriate 0-meridian - can be used to convert to floating point values of high precision.
如果在使用双精度时可能存在精度损失问题,或者您不会进行三角测量,我建议您将映射到整数范围的解决方案 - 这将为您提供最佳分辨率,可以轻松转换为任何显示格式你是locale将使用和 - 在选择合适的0子午线后 - 可用于转换为高精度的浮点值。
PS: I've always wondered why there seems to be no one who uses geocentric spherical coordinates - they should be reasonably close to the geographical coordinates, and won't require all this fancy math on spheroids to do computations; for fun, I wanted to convert Gauss-Krüger-Koordinaten (which are in use by the German Katasteramt) to GPS coordinates - let me tell you, that was ugly: one uses the Bessel ellipsoid, the other WGS84, and the Gauss-Krüger mapping itself is pretty crazy on it's own...
PS:我一直想知道为什么似乎没有人使用地心球坐标 - 它们应该合理地接近地理坐标,并且不需要对球体进行所有这些花哨的数学计算;为了好玩,我想将Gauss-Krüger-Koordinaten(由德国Katasteramt使用)转换为GPS坐标 - 让我告诉你,这很难看:一个使用贝塞尔椭圆体,另一个使用WGS84,以及Gauss-Krüger映射本身对它自己来说非常疯狂......
#5
0.3 inch resolution is getting down to the point where earthquakes over a few years make a difference. You may want to reconsider why you believe you need such fine resolution worldwide.
0.3英寸的分辨率正在降低到几年来地震产生影响的程度。您可能想重新考虑为什么您认为自己在全球范围内需要这么好的分辨率。
Some of the spreading centres in the Pacific Ocean change by as much as 15 cm/year.
太平洋的一些扩散中心每年变化15厘米。
#6
What encoding is "best" really depends on your goals/requirements.
什么编码“最好”实际上取决于您的目标/要求。
If you are performing arithmetic, floating point latitude,longitude is often quite convenient. Other times cartesian coordinates (ie x,y,z) can be more convenient. For example, if you only cared about points on the surface of earth, you could use an n-vector.
如果你正在执行算术,浮点纬度,经度往往很方便。其他时候笛卡尔坐标(即x,y,z)可以更方便。例如,如果你只关心地球表面上的点,你可以使用n向量。
As for longer term storage, IEEE floating point will waste bits for ranges you don't care about (for lat/lon) or for precision you may not care about in the case of cartesian coordinates (unless you want very good precision at the origin for whatever reason). You can of course map either type of coordinates to ints of your preferred size, such that the entire range of said ints covers the range you are interested in at the resolution you care about.
对于长期存储,IEEE浮点会浪费你不关心的范围(对于纬度/经度)或者在笛卡尔坐标的情况下你可能不关心的精度(除非你想要在原点有很好的精度无论出于何种原因)。您当然可以将任何类型的坐标映射到您的首选大小的整数,以便所述整数范围涵盖您感兴趣的分辨率范围。
There are of course other things to think about than merely not wasting bits in the encoding. For example, (Geohashes)[https://en.wikipedia.org/wiki/Geohash] have the nice property that it is easy to find other geohashes in the same area. (Most will have the same prefix, and you can compute the prefix the others will have.) Unfortunately, they maintain the same precision in degrees longitude near the equator as near the poles. I'm currently using 64-bit geohashes for storage, which gives about 3 m resolution at the equator.
当然还有其他事情要考虑,而不仅仅是在编码中浪费比特。例如,(Geohashes)[https://en.wikipedia.org/wiki/Geohash]具有很好的属性,很容易在同一区域找到其他地理位置。 (大多数将具有相同的前缀,并且您可以计算其他人将具有的前缀。)不幸的是,它们在靠近极点的赤道附近保持相同的经度。我目前正在使用64位地理数据进行存储,在赤道上提供大约3米的分辨率。
The Maidenhead Locator System has some similar characteristics, but seems more optimized for communicating locations between humans rather than storing on a computer. (Storing MLS strings would waste a lot of bits for some rather trivial error detection.)
Maidenhead定位系统具有一些类似的特性,但似乎更适合于在人与人之间进行通信而不是存储在计算机上。 (存储MLS字符串会浪费很多比特来进行一些相当简单的错误检测。)
The one system I found that does handle the poles differently is the Military Grid Reference System, although it too seems more human-communications oriented. (And it seems like a pain to convert from or to lat/lon.)
我发现的一个系统确实能够处理两极不同的是军事网格参考系统,尽管它看起来更像人类通信。 (转换为lat / lon似乎很痛苦。)
Depending on what you want exactly, you could use something similar to the Universal polar sereographic coordinate system near the poles along with something more computationally sane than UTM for the rest of the world, and use at most one bit to indicate which of the two systems you're using. I say at most one bit, because it's unlikely most of the points you care about would be near the poles. For example, you could use "half a bit" by saying 11 indicates use of the polar system, while 00, 01, and 10 indicate use of the other system, and are part of the representation.
根据你想要的东西,你可以使用类似于极点附近的通用极地立体坐标系统的东西,以及比世界其他地方的UTM计算更健全的东西,并且最多使用一位来指示两个系统中的哪一个你正在使用。我最多说一点,因为你关心的大部分点都不太可能靠近两极。例如,您可以使用“半位”,表示11表示极性系统的使用,而00,01和10表示使用另一个系统,并且是表示的一部分。
Sorry this is a bit long, but I wanted to save what I had learned recently. Sadly I have not found any standard, sane, and efficient way to represent a point on earth with uniform precision.
对不起,这有点长,但我想保存最近学到的东西。遗憾的是,我没有找到任何标准,合理和有效的方法来统一精确地表示地球上的一个点。
Edit: I found another approach which looks a lot more like what you wanted, since it more directly takes advantage of the lower precision needed for longitude closer to the poles. It turns out there is a lot of research on storing normal vectors. Encoding Normal Vectors using Optimized Spherical Coordinates describes such a system for encoding normal vectors while maintaining a minimum level of accuracy, but it could just as well be used for geographical coordinates.
编辑:我发现了另一种看起来更像你想要的方法,因为它更直接地利用了靠近极点的经度所需的较低精度。事实证明,有很多关于存储法向量的研究。使用优化球面坐标编码法线向量描述了这样一种用于编码法向量的系统,同时保持最低精度水平,但它也可以用于地理坐标。
#7
http://www.esri.com/news/arcuser/0400/wdside.html
At the equator, an arc-second of longitude approximately equals an arc-second of latitude, which is 1/60th of a nautical mile (or 101.27 feet or 30.87 meters).
32-bit float contains 23 explicit bits of data.
180 * 3600 requires log2(648000) = 19.305634287546711769425914064259 bits of data. Note that sign bit is stored separately and therefore we need to amount only for 180 degrees.
After subtracting from 23 the bits for log2(648000) we have remaining extra 3.694365712453288230574085935741 bits for sub-second data.
That is 2 ^ 3.694365712453288230574085935741 = 12.945382716049382716049382716053 parts per second.
Therefore a float data type can have 30.87 / 12.945382716049382716049382716053 ~= 2.38 meters precision at equator.
http://www.esri.com/news/arcuser/0400/wdside.html在赤道,经度的弧秒约等于纬度的弧秒,即海里的1/60(或101.27)英尺或30.87米)。 32位浮点包含23个显式位数据。 180 * 3600需要log2(648000)= 19.305634287546711769425914064259位数据。请注意,符号位是单独存储的,因此我们只需要180度的数量。在从23减去log2(648000)的位之后,我们为亚秒数据保留了额外的3.694365712453288230574085935741位。那是2 ^ 3.694365712453288230574085935741 = 12.945382716049382716049382716053每秒零件。因此浮点数据类型在赤道上的精度可以达到30.87 / 12.945382716049382716049382716053~ = 2.38米。
#8
If by "storing" you mean "holding in memory", the real question is: what are you going to do with them?
如果通过“存储”来表示“留在记忆中”,真正的问题是:你打算用它们做什么?
I suspect that before these coordinates do anything interesting, they will have been funnelled as radians through the functions in math.h. Unless you plan on implementing quite a few transcendental functions that operate on Deg/Min/Secs packed into a bit field.
我怀疑在这些坐标做任何有趣的事情之前,它们将通过math.h中的函数作为弧度漏斗。除非你计划实现相当多的超越函数,这些函数在Deg / Min / Secs上运行,并且包含在一个位域中。
So why not keep things simple and just store them in IEEE-754 degrees or radians at the precision of your requirements?
那么为什么不保持简单,只需按照您要求的精度将它们存储在IEEE-754度或弧度中?
#9
A Java program for comuting max rounding error in meters from casting lat/long values into Float/Double:
用于计算最大舍入误差(以米为单位)的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);
}
}
Output:
Float max error (meters): 1.7791213425235692
Double max error (meters): 0.11119508289500799
#10
The following code packs the WGS84 coordinates losslessly coordinates into an unsigned long (i.e. into 8 bytes):
下面的代码将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);
}
}
}
Source: http://www.dupuis.me/node/35
#11
You can use decimal
datatype:
您可以使用decimal数据类型:
CREATE TABLE IF NOT EXISTS `map` (
`latitude` decimal(18,15) DEFAULT NULL,
`longitude` decimal(18,15) DEFAULT NULL
);
#12
Great question!
I know this question is 9 years old now, and I only know a part of the answer you were seeking, but I just came here having a similar question, and many things have changed since that question was asked, such as hardware and GPSes available. I work with this subject frequently in firmware dealing with different kinds of GPSes in different kinds of applications, and have lost count of the hours (and days) I have spent working out "the best design" for different applications that I have worked with or developed.
我知道这个问题现在已经有9年了,我只知道你要找的答案的一部分,但我刚来这里有类似的问题,自从提出这个问题后,很多事情都发生了变化,例如硬件和GPS可用。我经常在不同类型的应用程序中处理不同类型的GPS的固件中使用这个主题,并且已经花费了我为与我合作过的不同应用程序制定“最佳设计”的时间(和天)的数量。发达。
As always, different solutions are going to provide benefits and costs, and ultimately, a "best design" is always going to be a "best fit" of the benefits and costs against system requirements. Here are some things that I have to consider when I ask the same question:
与往常一样,不同的解决方案将提供优势和成本,最终,“最佳设计”始终是“最适合”系统要求的优势和成本。当我提出同样的问题时,我需要考虑以下几点:
CPU Time Cost
CPU时间成本
If CPU does not have a built-in floating-point co-processor (as is the case with many microcontrollers), then dealing with 'float', 'double', and 'long double' can be extremely costly. For example, with one 16-bit microcontroller I work with regularly, a multiplication using 'double' values costs 326 CPU clock cycles, and a division costs 1193 clock cycles. Very expensive!
如果CPU没有内置的浮点协处理器(就像许多微控制器一样),那么处理'float','double'和'long double'可能会非常昂贵。例如,我定期使用一个16位微控制器,使用“双”值的乘法需要326个CPU时钟周期,而一个分区需要1193个时钟周期。非常贵!
Accuracy Trade-Off
At the equator, a 'float' (IEEE-754 32-bit floating point value), needing to represent a signed degree value, assuming 7 "clean" significant decimal digits able to be represented, the change of one least-significant decimal digit (e.g. from 179.9999 to 180.0000) is going to represent a distance of about 11.12 meters. This may or may not meet hard system accuracy requirements. Whereas a 'double' (with 15 "clean" significant decimal digits represented, thus a change from 179.999999999999 to 180.000000000000) represents about 0.00011 mm.
在赤道,“浮动”(IEEE-754 32位浮点值),需要表示有符号度数值,假设7“干净”有效十进制数字能够表示,一个最低有效十进制数字的变化(例如从179.9999到180.0000)将代表大约11.12米的距离。这可能符合或不符合硬系统精度要求。而“双”(表示15“干净”有效小数位,因此从179.999999999999变为180.000000000000)代表约0.00011mm。
Input Accuracy Limitations
输入精度限制
If you're dealing with input from a GPS, how many digits of real accuracy are you getting, and how many do you need to preserve?
如果您正在处理来自GPS的输入,您获得的真实准确度有多少位数,您需要保留多少位数?
Development Time Costs
开发时间成本
An IEEE-754 64-bit double-precision value ('double') and 32-bit single-precision value ('float') are VERY convenient to deal with in the C language since math libraries for both come with virtually every C compiler, and are usually very reliable. If your CPU comes with a hardware floating-point processor, this is an easy choice.
IEEE-754 64位双精度值('double')和32位单精度值('float')在C语言中非常方便,因为几乎每个C编译器都有数学库。 ,通常非常可靠。如果您的CPU配有硬件浮点处理器,这是一个简单的选择。
RAM and Storage Costs
RAM和存储成本
If you have to keep a large number of these values in RAM (or storage e.g. MYSQL), available RAM (and storage space) might have an impact on the workability of the solution.
如果必须在RAM(或存储器,例如MYSQL)中保留大量这些值,则可用的RAM(和存储空间)可能会影响解决方案的可用性。
Available Data vs Required Data
可用数据与所需数据
One example I'm dealing with at this writing (the reason I came here to this question) is that I am dealing with a u-blox M8 GPS which is able to give me binary GPS information (saving the CPU overhead of translating ASCII NMEA sentences). In this binary format (called "UBX Protocol") latitude and longitude are represented as signed 32-bit integers, which representation is able to represent accuracy (at the equator) of down to about 1.11 cm. For example, -105.0269805 degrees longitude is represented as -1050269805 (using all 32 bits) and one LSb change represents about 1.11 cm change in latitude anywhere, and 1.11 cm longitude at the equator (and less at higher latitudes, in proportion to the cosine of the latitude). The application this GPS is in does navigation tasks, which (already existing and well-tested code) requires 'double' data types. Unfortunately, converting this integer to an IEEE-754 64-bit 'double' cannot be easily done just by moving the base-2 bits of the integer into the internal representation bits of the 'double' since the decimal shift to be performed is a base-10 decimal shift. Were it a base-2 decimal shift instead, then the base-2 bits of the integer could be moved into the bit-fields of the 'double' with very little translation required. But alas, this is not the case with the signed integer I have. So it is going to cost me a multiplication on a CPU that doesn't have a hardware floating-point processor: 326 CPU clock cycles.
我在写这篇文章时遇到的一个例子(我来到这个问题的原因)是我正在处理一个u-blox M8 GPS,它能够给我二进制GPS信息(节省转换ASCII NMEA的CPU开销)句子)。在这种二进制格式(称为“UBX协议”)中,纬度和经度表示为带符号的32位整数,该表示能够表示低至约1.11cm的精度(在赤道处)。例如,-105.0269805度经度表示为-1050269805(使用全部32位),一个LSb变化表示任何地方纬度变化约1.11厘米,赤道1.11厘米经度(较低纬度处较少,与余弦成比例)纬度)。 GPS导入的应用程序执行导航任务(已经存在且经过良好测试的代码)需要“双重”数据类型。不幸的是,仅仅通过将整数的基数2位移动到'double'的内部表示位,就不能轻易地将此整数转换为IEEE-754 64位'double',因为要执行的小数移位是基数为10的十进制。如果它是基数为2的十进制移位,那么整数的基数2位可以移动到“双”的位字段中,只需要很少的转换。但是,我所拥有的有符号整数不是这种情况。所以它会让我在没有硬件浮点处理器的CPU上成倍增加:326个CPU时钟周期。
double ldLatitude;
int32_t li32LatFromGps;
ldLatitude = (double)li32LatFromGps * 0.0000001;
Note this multiplication was chosen over this:
注意这个乘法是在这个选择:
ldLatitude = (double)li32LatFromGps / 10000000.0;
because 'double' multiplication is about 3.6X faster than 'double' division on the CPU that I'm dealing with. Such is life in the microcontroller world. :-)
因为'double'乘法比我正在处理的CPU上的'double'除法快约3.6倍。这就是微控制器世界的生命。 :-)
What would have been BRILLIANT (and may be in the future if I can spare the time on weekends) is if the navigation tasks could be done directly with the 32-bit signed integer! Then no conversion would be needed.... But would it cost more to do the navigation tasks with such an integer? CPU costs, probably much more efficient. Development time costs? That's another question, especially with a well-tested system already in place, that uses IEEE-754 64-bit 'double' values! Plus there is already-existing software that provides map data (using 'double' degree values), which software would have to be converted to use the signed integer as well -- not an overnight task!
如果导航任务可以直接使用32位有符号整数完成,那么BRILLIANT(如果我可以在周末节省时间)可能是什么?然后不需要转换....但是使用这样的整数执行导航任务会花费更多吗? CPU成本,可能更高效。开发时间成本?这是另一个问题,特别是对于已经过充分测试的系统,使用IEEE-754 64位“双”值!此外,已有的软件提供地图数据(使用“双度”值),必须将软件转换为使用带符号的整数 - 而不是一夜之间的任务!
One VERY interesting option is to directly (without translation) represent intersections between approximations of "rectangles" (actually trapezoids, which become triangles at the poles) using the raw latitude/longitude integers. At the equator these rectangles would have dimensions of approximately 1.11 cm east-west by 1.11 cm north-south, whereas at a latitude of say London, England, the dimensions would be approximately 0.69 cm east-west by 1.11 cm north-south. That may or may not be easy to deal with, depending on what the application needs.
一个非常有趣的选择是直接(没有平移)表示使用原始纬度/经度整数的“矩形”(实际上是梯形,在极点上变为三角形)的近似值之间的交叉点。在赤道,这些矩形的东西长约1.11厘米,南北长1.11厘米,而在英国伦敦的纬度,尺寸约为东西向0.69厘米,南北长1.11厘米。根据应用程序的需要,这可能会或可能不容易处理。
Anyway, I hope these thoughts and discussion help others who are looking at this topic for "the best design" for their system.
无论如何,我希望这些想法和讨论可以帮助那些正在研究这个主题的人为他们的系统“最好的设计”。
Kind regards, Vic
亲切的问候,维克
#1
The easiest way is just to store it as a float/double in degrees. Positive for N and E, negative for S and W. Just remember that minutes and seconds are out of 60 (so 31 45'N is 31.75). Its easy to understand what the values are by looking at them and, where necessary, conversion to radians is trivial.
最简单的方法是将其存储为浮点数/双精度。 N和E为正,S和W为负。只需记住分数和秒数超过60(因此31 45'N为31.75)。通过查看它们很容易理解值是什么,并且在必要时,转换为弧度是微不足道的。
Calculations on latitudes and longitudes such as the Great Circle distance between two coordinates rely heavily on trigonometric functions, which typically use doubles. Any other format is going to rely on another implementation of sine, cosine, atan2 and square root, at a minimum. Arbitrary precision numbers (eg BigDecimal in Java) won't work for this. Something like the int where 2^32 is spread uniformly is going to have similar issues.
纬度和经度的计算,例如两个坐标之间的大圆距离,很大程度上依赖于三角函数,三角函数通常使用双精度。任何其他格式都将依赖于正弦,余弦,atan2和平方根的另一种实现。任意精度数字(例如Java中的BigDecimal)都不适用于此。类似于int ^ 2 32统一传播的东西会有类似的问题。
The point of uniformity has come up in several comments. On this I shall simply note that the Earth, with respect to longitude, isn't uniform. One arc-second longitude at the Arctic Circle is a shorter distance than at the Equator. Double precision floats give sub-millimetre precision anywhere on Earth. Is this not sufficient? If not, why not?
一些评论中提出了统一性。在此,我将简单地指出,地球在经度方面并不统一。北极圈的一弧秒经度比赤道的距离短。双精度浮标可在地球上的任何位置提供亚毫米级精度。这还不够吗?如果没有,为什么不呢?
It'd also be worth noting what you want to do with that information as the types of calculations you require will have an impact on what storage format you use.
同样值得注意的是您要对该信息做什么,因为您需要的计算类型会对您使用的存储格式产生影响。
#2
Longitudes and latitudes are not generally known to any greater precision than a 32-bit float. So if you're concerned about storage space, you can use floats. But in general it's more convenient to work with numbers as doubles.
通常不知道经度和纬度比32位浮点更精确。因此,如果您担心存储空间,可以使用浮动。但总的来说,将数字作为双精度数更方便。
Radians are more convenient for theoretical math. (For example, the derivative of sine is cosine only when you use radians.) But degrees are typically more familiar and easier for people to interpret, so you might want to stick with degrees.
Radians对理论数学更方便。 (例如,只有当你使用弧度时,正弦的导数才是余弦。)但是度数通常更熟悉,更容易让人们解释,所以你可能想要坚持学位。
#3
A Decimal representation with precision of 8 should be more than enough according to this wikipedia article on 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
#4
Might the problems you mentioned with floating point values become an issue? If the answer is no, I'd suggest just using the radians value in double precision - you'll need it if you'll be doing trigonometric calculations anyway.
您提到的浮点值问题可能成为问题吗?如果答案是否定的,我建议只使用双精度的弧度值 - 如果你要进行三角计算,你将需要它。
If there might be an issue with precision loss when using doubles or you won't be doing trigonometry, I'd suggest your solution of mapping to an integer range - this will give you the best resolution, can easily be converted to whatever display format you're locale will be using and - after choosing an appropriate 0-meridian - can be used to convert to floating point values of high precision.
如果在使用双精度时可能存在精度损失问题,或者您不会进行三角测量,我建议您将映射到整数范围的解决方案 - 这将为您提供最佳分辨率,可以轻松转换为任何显示格式你是locale将使用和 - 在选择合适的0子午线后 - 可用于转换为高精度的浮点值。
PS: I've always wondered why there seems to be no one who uses geocentric spherical coordinates - they should be reasonably close to the geographical coordinates, and won't require all this fancy math on spheroids to do computations; for fun, I wanted to convert Gauss-Krüger-Koordinaten (which are in use by the German Katasteramt) to GPS coordinates - let me tell you, that was ugly: one uses the Bessel ellipsoid, the other WGS84, and the Gauss-Krüger mapping itself is pretty crazy on it's own...
PS:我一直想知道为什么似乎没有人使用地心球坐标 - 它们应该合理地接近地理坐标,并且不需要对球体进行所有这些花哨的数学计算;为了好玩,我想将Gauss-Krüger-Koordinaten(由德国Katasteramt使用)转换为GPS坐标 - 让我告诉你,这很难看:一个使用贝塞尔椭圆体,另一个使用WGS84,以及Gauss-Krüger映射本身对它自己来说非常疯狂......
#5
0.3 inch resolution is getting down to the point where earthquakes over a few years make a difference. You may want to reconsider why you believe you need such fine resolution worldwide.
0.3英寸的分辨率正在降低到几年来地震产生影响的程度。您可能想重新考虑为什么您认为自己在全球范围内需要这么好的分辨率。
Some of the spreading centres in the Pacific Ocean change by as much as 15 cm/year.
太平洋的一些扩散中心每年变化15厘米。
#6
What encoding is "best" really depends on your goals/requirements.
什么编码“最好”实际上取决于您的目标/要求。
If you are performing arithmetic, floating point latitude,longitude is often quite convenient. Other times cartesian coordinates (ie x,y,z) can be more convenient. For example, if you only cared about points on the surface of earth, you could use an n-vector.
如果你正在执行算术,浮点纬度,经度往往很方便。其他时候笛卡尔坐标(即x,y,z)可以更方便。例如,如果你只关心地球表面上的点,你可以使用n向量。
As for longer term storage, IEEE floating point will waste bits for ranges you don't care about (for lat/lon) or for precision you may not care about in the case of cartesian coordinates (unless you want very good precision at the origin for whatever reason). You can of course map either type of coordinates to ints of your preferred size, such that the entire range of said ints covers the range you are interested in at the resolution you care about.
对于长期存储,IEEE浮点会浪费你不关心的范围(对于纬度/经度)或者在笛卡尔坐标的情况下你可能不关心的精度(除非你想要在原点有很好的精度无论出于何种原因)。您当然可以将任何类型的坐标映射到您的首选大小的整数,以便所述整数范围涵盖您感兴趣的分辨率范围。
There are of course other things to think about than merely not wasting bits in the encoding. For example, (Geohashes)[https://en.wikipedia.org/wiki/Geohash] have the nice property that it is easy to find other geohashes in the same area. (Most will have the same prefix, and you can compute the prefix the others will have.) Unfortunately, they maintain the same precision in degrees longitude near the equator as near the poles. I'm currently using 64-bit geohashes for storage, which gives about 3 m resolution at the equator.
当然还有其他事情要考虑,而不仅仅是在编码中浪费比特。例如,(Geohashes)[https://en.wikipedia.org/wiki/Geohash]具有很好的属性,很容易在同一区域找到其他地理位置。 (大多数将具有相同的前缀,并且您可以计算其他人将具有的前缀。)不幸的是,它们在靠近极点的赤道附近保持相同的经度。我目前正在使用64位地理数据进行存储,在赤道上提供大约3米的分辨率。
The Maidenhead Locator System has some similar characteristics, but seems more optimized for communicating locations between humans rather than storing on a computer. (Storing MLS strings would waste a lot of bits for some rather trivial error detection.)
Maidenhead定位系统具有一些类似的特性,但似乎更适合于在人与人之间进行通信而不是存储在计算机上。 (存储MLS字符串会浪费很多比特来进行一些相当简单的错误检测。)
The one system I found that does handle the poles differently is the Military Grid Reference System, although it too seems more human-communications oriented. (And it seems like a pain to convert from or to lat/lon.)
我发现的一个系统确实能够处理两极不同的是军事网格参考系统,尽管它看起来更像人类通信。 (转换为lat / lon似乎很痛苦。)
Depending on what you want exactly, you could use something similar to the Universal polar sereographic coordinate system near the poles along with something more computationally sane than UTM for the rest of the world, and use at most one bit to indicate which of the two systems you're using. I say at most one bit, because it's unlikely most of the points you care about would be near the poles. For example, you could use "half a bit" by saying 11 indicates use of the polar system, while 00, 01, and 10 indicate use of the other system, and are part of the representation.
根据你想要的东西,你可以使用类似于极点附近的通用极地立体坐标系统的东西,以及比世界其他地方的UTM计算更健全的东西,并且最多使用一位来指示两个系统中的哪一个你正在使用。我最多说一点,因为你关心的大部分点都不太可能靠近两极。例如,您可以使用“半位”,表示11表示极性系统的使用,而00,01和10表示使用另一个系统,并且是表示的一部分。
Sorry this is a bit long, but I wanted to save what I had learned recently. Sadly I have not found any standard, sane, and efficient way to represent a point on earth with uniform precision.
对不起,这有点长,但我想保存最近学到的东西。遗憾的是,我没有找到任何标准,合理和有效的方法来统一精确地表示地球上的一个点。
Edit: I found another approach which looks a lot more like what you wanted, since it more directly takes advantage of the lower precision needed for longitude closer to the poles. It turns out there is a lot of research on storing normal vectors. Encoding Normal Vectors using Optimized Spherical Coordinates describes such a system for encoding normal vectors while maintaining a minimum level of accuracy, but it could just as well be used for geographical coordinates.
编辑:我发现了另一种看起来更像你想要的方法,因为它更直接地利用了靠近极点的经度所需的较低精度。事实证明,有很多关于存储法向量的研究。使用优化球面坐标编码法线向量描述了这样一种用于编码法向量的系统,同时保持最低精度水平,但它也可以用于地理坐标。
#7
http://www.esri.com/news/arcuser/0400/wdside.html
At the equator, an arc-second of longitude approximately equals an arc-second of latitude, which is 1/60th of a nautical mile (or 101.27 feet or 30.87 meters).
32-bit float contains 23 explicit bits of data.
180 * 3600 requires log2(648000) = 19.305634287546711769425914064259 bits of data. Note that sign bit is stored separately and therefore we need to amount only for 180 degrees.
After subtracting from 23 the bits for log2(648000) we have remaining extra 3.694365712453288230574085935741 bits for sub-second data.
That is 2 ^ 3.694365712453288230574085935741 = 12.945382716049382716049382716053 parts per second.
Therefore a float data type can have 30.87 / 12.945382716049382716049382716053 ~= 2.38 meters precision at equator.
http://www.esri.com/news/arcuser/0400/wdside.html在赤道,经度的弧秒约等于纬度的弧秒,即海里的1/60(或101.27)英尺或30.87米)。 32位浮点包含23个显式位数据。 180 * 3600需要log2(648000)= 19.305634287546711769425914064259位数据。请注意,符号位是单独存储的,因此我们只需要180度的数量。在从23减去log2(648000)的位之后,我们为亚秒数据保留了额外的3.694365712453288230574085935741位。那是2 ^ 3.694365712453288230574085935741 = 12.945382716049382716049382716053每秒零件。因此浮点数据类型在赤道上的精度可以达到30.87 / 12.945382716049382716049382716053~ = 2.38米。
#8
If by "storing" you mean "holding in memory", the real question is: what are you going to do with them?
如果通过“存储”来表示“留在记忆中”,真正的问题是:你打算用它们做什么?
I suspect that before these coordinates do anything interesting, they will have been funnelled as radians through the functions in math.h. Unless you plan on implementing quite a few transcendental functions that operate on Deg/Min/Secs packed into a bit field.
我怀疑在这些坐标做任何有趣的事情之前,它们将通过math.h中的函数作为弧度漏斗。除非你计划实现相当多的超越函数,这些函数在Deg / Min / Secs上运行,并且包含在一个位域中。
So why not keep things simple and just store them in IEEE-754 degrees or radians at the precision of your requirements?
那么为什么不保持简单,只需按照您要求的精度将它们存储在IEEE-754度或弧度中?
#9
A Java program for comuting max rounding error in meters from casting lat/long values into Float/Double:
用于计算最大舍入误差(以米为单位)的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);
}
}
Output:
Float max error (meters): 1.7791213425235692
Double max error (meters): 0.11119508289500799
#10
The following code packs the WGS84 coordinates losslessly coordinates into an unsigned long (i.e. into 8 bytes):
下面的代码将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);
}
}
}
Source: http://www.dupuis.me/node/35
#11
You can use decimal
datatype:
您可以使用decimal数据类型:
CREATE TABLE IF NOT EXISTS `map` (
`latitude` decimal(18,15) DEFAULT NULL,
`longitude` decimal(18,15) DEFAULT NULL
);
#12
Great question!
I know this question is 9 years old now, and I only know a part of the answer you were seeking, but I just came here having a similar question, and many things have changed since that question was asked, such as hardware and GPSes available. I work with this subject frequently in firmware dealing with different kinds of GPSes in different kinds of applications, and have lost count of the hours (and days) I have spent working out "the best design" for different applications that I have worked with or developed.
我知道这个问题现在已经有9年了,我只知道你要找的答案的一部分,但我刚来这里有类似的问题,自从提出这个问题后,很多事情都发生了变化,例如硬件和GPS可用。我经常在不同类型的应用程序中处理不同类型的GPS的固件中使用这个主题,并且已经花费了我为与我合作过的不同应用程序制定“最佳设计”的时间(和天)的数量。发达。
As always, different solutions are going to provide benefits and costs, and ultimately, a "best design" is always going to be a "best fit" of the benefits and costs against system requirements. Here are some things that I have to consider when I ask the same question:
与往常一样,不同的解决方案将提供优势和成本,最终,“最佳设计”始终是“最适合”系统要求的优势和成本。当我提出同样的问题时,我需要考虑以下几点:
CPU Time Cost
CPU时间成本
If CPU does not have a built-in floating-point co-processor (as is the case with many microcontrollers), then dealing with 'float', 'double', and 'long double' can be extremely costly. For example, with one 16-bit microcontroller I work with regularly, a multiplication using 'double' values costs 326 CPU clock cycles, and a division costs 1193 clock cycles. Very expensive!
如果CPU没有内置的浮点协处理器(就像许多微控制器一样),那么处理'float','double'和'long double'可能会非常昂贵。例如,我定期使用一个16位微控制器,使用“双”值的乘法需要326个CPU时钟周期,而一个分区需要1193个时钟周期。非常贵!
Accuracy Trade-Off
At the equator, a 'float' (IEEE-754 32-bit floating point value), needing to represent a signed degree value, assuming 7 "clean" significant decimal digits able to be represented, the change of one least-significant decimal digit (e.g. from 179.9999 to 180.0000) is going to represent a distance of about 11.12 meters. This may or may not meet hard system accuracy requirements. Whereas a 'double' (with 15 "clean" significant decimal digits represented, thus a change from 179.999999999999 to 180.000000000000) represents about 0.00011 mm.
在赤道,“浮动”(IEEE-754 32位浮点值),需要表示有符号度数值,假设7“干净”有效十进制数字能够表示,一个最低有效十进制数字的变化(例如从179.9999到180.0000)将代表大约11.12米的距离。这可能符合或不符合硬系统精度要求。而“双”(表示15“干净”有效小数位,因此从179.999999999999变为180.000000000000)代表约0.00011mm。
Input Accuracy Limitations
输入精度限制
If you're dealing with input from a GPS, how many digits of real accuracy are you getting, and how many do you need to preserve?
如果您正在处理来自GPS的输入,您获得的真实准确度有多少位数,您需要保留多少位数?
Development Time Costs
开发时间成本
An IEEE-754 64-bit double-precision value ('double') and 32-bit single-precision value ('float') are VERY convenient to deal with in the C language since math libraries for both come with virtually every C compiler, and are usually very reliable. If your CPU comes with a hardware floating-point processor, this is an easy choice.
IEEE-754 64位双精度值('double')和32位单精度值('float')在C语言中非常方便,因为几乎每个C编译器都有数学库。 ,通常非常可靠。如果您的CPU配有硬件浮点处理器,这是一个简单的选择。
RAM and Storage Costs
RAM和存储成本
If you have to keep a large number of these values in RAM (or storage e.g. MYSQL), available RAM (and storage space) might have an impact on the workability of the solution.
如果必须在RAM(或存储器,例如MYSQL)中保留大量这些值,则可用的RAM(和存储空间)可能会影响解决方案的可用性。
Available Data vs Required Data
可用数据与所需数据
One example I'm dealing with at this writing (the reason I came here to this question) is that I am dealing with a u-blox M8 GPS which is able to give me binary GPS information (saving the CPU overhead of translating ASCII NMEA sentences). In this binary format (called "UBX Protocol") latitude and longitude are represented as signed 32-bit integers, which representation is able to represent accuracy (at the equator) of down to about 1.11 cm. For example, -105.0269805 degrees longitude is represented as -1050269805 (using all 32 bits) and one LSb change represents about 1.11 cm change in latitude anywhere, and 1.11 cm longitude at the equator (and less at higher latitudes, in proportion to the cosine of the latitude). The application this GPS is in does navigation tasks, which (already existing and well-tested code) requires 'double' data types. Unfortunately, converting this integer to an IEEE-754 64-bit 'double' cannot be easily done just by moving the base-2 bits of the integer into the internal representation bits of the 'double' since the decimal shift to be performed is a base-10 decimal shift. Were it a base-2 decimal shift instead, then the base-2 bits of the integer could be moved into the bit-fields of the 'double' with very little translation required. But alas, this is not the case with the signed integer I have. So it is going to cost me a multiplication on a CPU that doesn't have a hardware floating-point processor: 326 CPU clock cycles.
我在写这篇文章时遇到的一个例子(我来到这个问题的原因)是我正在处理一个u-blox M8 GPS,它能够给我二进制GPS信息(节省转换ASCII NMEA的CPU开销)句子)。在这种二进制格式(称为“UBX协议”)中,纬度和经度表示为带符号的32位整数,该表示能够表示低至约1.11cm的精度(在赤道处)。例如,-105.0269805度经度表示为-1050269805(使用全部32位),一个LSb变化表示任何地方纬度变化约1.11厘米,赤道1.11厘米经度(较低纬度处较少,与余弦成比例)纬度)。 GPS导入的应用程序执行导航任务(已经存在且经过良好测试的代码)需要“双重”数据类型。不幸的是,仅仅通过将整数的基数2位移动到'double'的内部表示位,就不能轻易地将此整数转换为IEEE-754 64位'double',因为要执行的小数移位是基数为10的十进制。如果它是基数为2的十进制移位,那么整数的基数2位可以移动到“双”的位字段中,只需要很少的转换。但是,我所拥有的有符号整数不是这种情况。所以它会让我在没有硬件浮点处理器的CPU上成倍增加:326个CPU时钟周期。
double ldLatitude;
int32_t li32LatFromGps;
ldLatitude = (double)li32LatFromGps * 0.0000001;
Note this multiplication was chosen over this:
注意这个乘法是在这个选择:
ldLatitude = (double)li32LatFromGps / 10000000.0;
because 'double' multiplication is about 3.6X faster than 'double' division on the CPU that I'm dealing with. Such is life in the microcontroller world. :-)
因为'double'乘法比我正在处理的CPU上的'double'除法快约3.6倍。这就是微控制器世界的生命。 :-)
What would have been BRILLIANT (and may be in the future if I can spare the time on weekends) is if the navigation tasks could be done directly with the 32-bit signed integer! Then no conversion would be needed.... But would it cost more to do the navigation tasks with such an integer? CPU costs, probably much more efficient. Development time costs? That's another question, especially with a well-tested system already in place, that uses IEEE-754 64-bit 'double' values! Plus there is already-existing software that provides map data (using 'double' degree values), which software would have to be converted to use the signed integer as well -- not an overnight task!
如果导航任务可以直接使用32位有符号整数完成,那么BRILLIANT(如果我可以在周末节省时间)可能是什么?然后不需要转换....但是使用这样的整数执行导航任务会花费更多吗? CPU成本,可能更高效。开发时间成本?这是另一个问题,特别是对于已经过充分测试的系统,使用IEEE-754 64位“双”值!此外,已有的软件提供地图数据(使用“双度”值),必须将软件转换为使用带符号的整数 - 而不是一夜之间的任务!
One VERY interesting option is to directly (without translation) represent intersections between approximations of "rectangles" (actually trapezoids, which become triangles at the poles) using the raw latitude/longitude integers. At the equator these rectangles would have dimensions of approximately 1.11 cm east-west by 1.11 cm north-south, whereas at a latitude of say London, England, the dimensions would be approximately 0.69 cm east-west by 1.11 cm north-south. That may or may not be easy to deal with, depending on what the application needs.
一个非常有趣的选择是直接(没有平移)表示使用原始纬度/经度整数的“矩形”(实际上是梯形,在极点上变为三角形)的近似值之间的交叉点。在赤道,这些矩形的东西长约1.11厘米,南北长1.11厘米,而在英国伦敦的纬度,尺寸约为东西向0.69厘米,南北长1.11厘米。根据应用程序的需要,这可能会或可能不容易处理。
Anyway, I hope these thoughts and discussion help others who are looking at this topic for "the best design" for their system.
无论如何,我希望这些想法和讨论可以帮助那些正在研究这个主题的人为他们的系统“最好的设计”。
Kind regards, Vic
亲切的问候,维克