Code zur Verwendung / zum Nachweis der Genauigkeit der Antwort von Oğuzhan KURNUÇ .
ZUSAMMENFASSUNG:
Große Präzision (~ 1 cm) bei kleiner Größe (4B).
Die Genauigkeit beträgt (sehr nahe an) 7 Dezimalstellen für Werte über dem Bereich [-180, 180].
Das sind 7 Stellen rechts von der Dezimalstelle (~ 1 cm) , also insgesamt 9 Stellen (oder 10 Stellen, wenn die anfängliche "1" von "180" gezählt wird) in der Nähe von + -180.
Vergleichen Sie dies mit einem 4-Byte-Float , der insgesamt nur ~ 7 Stellen hat, also ~ 5 Stellen rechts von der Dezimalstelle in der Nähe von + = 180 (~ 1 m) .
Methoden zur Verwendung dieses Ansatzes:
const double Fixed7Mult = 10000000;
public static int DecimalDegreesToFixed7(double degrees)
{
return RoundToInt(degrees * Fixed7Mult);
}
public static double Fixed7ToDecimalDegrees(int fixed7)
{
return fixed7 / (double)Fixed7Mult;
}
Präzisionstests:
/// <summary>
/// This test barely fails in 7th digit to right of decimal point (0.0000001 as delta).
/// Passes with 0.0000002 as delta.
/// </summary>
internal static void TEST2A_LatLongPrecision()
{
//VERY_SLOW_TEST Test2A_ForRange(-180, 360, 0.0000001);
//FAILS Test2A_ForRange(-180, 0.1, 0.0000001);
Test2A_ForRange(-180, 0.1, 0.0000002);
Test2A_ForRange(0, 0.1, 0.0000002);
Test2A_ForRange(179.9, 0.1, 0.0000002);
}
/// <summary>
/// Test for the smallest difference. A: 9.9999994E-08.
/// </summary>
internal static void TEST2B_LatLongPrecision()
{
double minDelta = double.MaxValue;
double vAtMinDelta = 0;
//VERY_SLOW_TEST Test2B_ForRange(-180, 360, ref minDelta, ref vAtMinDelta);
Test2B_ForRange(-180, 0.1, ref minDelta, ref vAtMinDelta);
Test2B_ForRange(0, 0.1, ref minDelta, ref vAtMinDelta);
Test2B_ForRange(179.9, 0.1, ref minDelta, ref vAtMinDelta);
// Fails. Smallest delta is 9.9999994E-08; due to slight rounding error in 7th decimal digit.
//if (minDelta < 0.0000001)
// throw new InvalidProgramException($"Fixed7 has less than 7 decimal digits near {vAtMinDelta}");
// Passes.
if (minDelta < 0.000000099)
throw new InvalidProgramException($"Fixed7 has less than 7 decimal digits near {vAtMinDelta}");
}
Hilfsmethoden für Tests:
private static void Test2A_ForRange(double minV, double range, double deltaV)
{
double prevV = 0;
int prevFixed7 = 0;
bool firstTime = true;
double maxV = minV + range;
for (double v = minV; v <= maxV; v += deltaV) {
int fixed7 = DecimalDegreesToFixed7(v);
if (firstTime)
firstTime = false;
else {
// Check for failure to distinguish two values that differ only in 7th decimal digit.
// Fails.
if (fixed7 == prevFixed7)
throw new InvalidProgramException($"Fixed7 doesn't distinguish between {prevV} and {v}");
}
prevV = v;
prevFixed7 = fixed7;
}
}
private static void Test2B_ForRange(double minV, double range, ref double minDelta, ref double vAtMinDelta)
{
int minFixed7 = DecimalDegreesToFixed7(minV);
int maxFixed7 = DecimalDegreesToFixed7(minV + range);
bool firstTime = true;
double prevV = 0; // Initial value is ignored.
for (int fixed7 = minFixed7; fixed7 < maxFixed7; fixed7++) {
double v = Fixed7ToDecimalDegrees(fixed7);
if (firstTime)
firstTime = false;
else {
double delta = Math.Abs(v - prevV);
if (delta < minDelta) {
minDelta = delta;
vAtMinDelta = v;
}
}
prevV = v;
}
}