Oğuzhan KURNUÇ'un cevabının doğruluğunu kullanma / kanıtlama kodu .
ÖZET:
Küçük boyutta (4B) büyük hassasiyet (~ 1 cm).
[-180, 180] aralıktaki değerler için kesinlik (çok yakın) 7 ondalık basamaktır.
De bu ondalık sağındaki 7 basamak (~ 1 cm) , 9 basamak toplam (ya da 10 haneli "180" bir "1" ilk sayımı kullanılırsa) + -180 yakın için.
Bunu, toplamda sadece ~ 7 basamaklı 4 baytlık bir kayan nokta ile kontrastlayın , bu nedenle ondalıktan sağda ~ 5 basamak + = 180 (~ 1m) yakınında .
Bu yaklaşımı kullanma yöntemleri:
const double Fixed7Mult = 10000000;
public static int DecimalDegreesToFixed7(double degrees)
{
return RoundToInt(degrees * Fixed7Mult);
}
public static double Fixed7ToDecimalDegrees(int fixed7)
{
return fixed7 / (double)Fixed7Mult;
}
Hassasiyet testleri:
/// <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}");
}
Testlerde kullanılan yardımcı yöntemler:
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;
}
}