Quelle est la plus rapide bibliothèque de classe C ++ ou C pour convertir la latitude et la longitude de degrés décimaux à chaîne et à l'arrière

StackOverflow https://stackoverflow.com/questions/4018775

Question

Je cherche le meilleur C ou C ++ code pour le codage et la latitude décimale de décodage et les valeurs de longitude de / doubler / char. Je préfère le converti de code de double en char [] et vice versa plutôt que c ++ chaînes.

Si vous avez un extrait de code qui serait génial aussi.

Pour clarifier: Je dois convertir une chaîne degrés / minutes / secondes pour doubler et revenir à la chaîne. J'ai 300 millions de disques, si la vitesse est une grande préoccupation.

Voir: http://en.wikipedia.org/wiki/Geographic_coordinate_conversion

Était-ce utile?

La solution

Travailler avec l'OP (amanda) par courrier électronique, nous avons développé une fonction rapide basée sur une grande instruction switch cas.

amanda rapports qui est exécute quelque part autour de 15x plus rapide que le code qu'ils utilisaient.
Compte tenu de cette est géré plus de 300 millions de disques, qui devrait être un gain de temps assez important.

Je trouve que le problème est très intéressant.

Voici le code:

/* WARNING:  These values are very important, as used under the "default" case. */
#define INT_PART 3
#define DEC_PART 2

double Str2LatLong(char* coord)
//double LLStr::Str2LL(char* coord)
{
    int sign = +1;
    double val;

    int i = 0;  /* an index into coord, the text-input string, indicating the character currently being parsed */

    int p[9] = {0,0,1,  /* degrees */
                0,0,1,  /* minutes */
                0,0,1   /* seconds */
               };
    int* ptr = p;   /* p starts at Degrees. 
                       It will advance to the Decimal part when a decimal-point is encountered,
                       and advance to minutes & seconds when a separator is encountered */
    int  flag = INT_PART; /* Flips back and forth from INT_PART and DEC_PART */

    while(1)
    {
        switch (coord[i])
        {
            /* Any digit contributes to either degrees,minutes, or seconds */
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                *ptr = 10* (*ptr) + (coord[i] - '0');
                if (flag == DEC_PART)  /* it'd be nice if I could find a clever way to avoid this test */
                {
                    ptr[1] *= 10;
                }
                break;

            case '.':     /* A decimal point implies ptr is on an integer-part; advance to decimal part */
                flag = DEC_PART; /* after encountering a decimal point, we are now processing the Decimal Part */
                ptr++;  /* ptr[0] is now the Decimal piece; ptr[1] is the Denominator piece (powers of 10) */
                break;

            /* A Null terminator triggers return (no break necessary) */
            case '\0':
                val = p[0]*3600 + p[3]*60 + p[6];             /* All Integer math */
                if (p[1]) val += ((double)p[1]/p[2]) * 3600;  /* Floating-point operations only if needed */
                if (p[4]) val += ((double)p[4]/p[5]) *   60;  /* (ditto) */
                if (p[7]) val += ((double)p[7]/p[8]);         /* (ditto) */
                return sign * val / 3600.0;                 /* Only one floating-point division! */

            case 'W':
            case 'S':
                sign = -1;
                break;

            /* Any other symbol is a separator, and moves ptr from degrees to minutes, or minutes to seconds */
            default:
                /* Note, by setting DEC_PART=2 and INT_PART=3, I avoid an if-test. (testing and branching is slow) */
                ptr += flag;
                flag = INT_PART; /* reset to Integer part, we're now starting a new "piece" (degrees, min, or sec). */
        }
        i++;
    }

    return -1.0;  /* Should never reach here! */
}

Autres conseils

Voici le code que j'ai développé:

double Str2LatLong(char* coord)
{
    // char* testInput = "47,26'14\"";

    int i = 0;
    int parts[3] = {0};  // parts[0] is degrees, parts[1] is minutes, parts[2] is seconds
    int* pCurr = parts;

    do
    {
        if (coord[i] == '\0')
        {
            break;
        }
        if (!isdigit(coord[i]))
        {
            *pCurr++; // skip from parts[0] ==> [1], or [1] ==> [2]
            continue;
        }
        *pCurr = 10* (*pCurr) + coord[i] - '0';
        ++i;
    } while (1);

    return parts[0] + ((double)parts[1])/60.0 + ((double)parts[2])/3600.0;
}

Parce qu'il est écrit pour la vitesse, il n'y a pas de validation d'entrée.
Vous devez fournir une bonne entrée, ou il gâchera mal.

je gardais tout entier aux mathématiques, et de la mémoire séquentielle comme je pouvais.
Il ne vérifie pas délimiteurs « appropriés ». Au contraire, quand quelque chose est pas un chiffre, il suppose que la transition est de degrés en minutes ou en secondes minutes.

Il est seulement à la dernière ligne qu'il convertit en double avec des opérations en virgule flottante très simple.

Je suppose que vous aurez envie de le modifier pour gérer les valeurs positives / négatives et du Nord / Sud, Est / Ouest, indicateurs et décimales après les secondes. Mais je pense que ce code est une bonne base pour une routine de conversion très rapide.

J'espère que cela va tester très vite. S'il vous plaît laissez-moi savoir comment ça se passe.

C ++ chaînes et des flux sont très une bonne idée, mais si vous absolument ne peut pas les utiliser, le code suivant peut être utile. La première fonction écrit les deux doubles dans une existant string C. La deuxième fonction lit deux doubles sur une existant string C et retourne eux par pointeur:

void CoordinatesToString(double lat, double long, char *buffer, size_t len) {
    assert(buffer != NULL);
    assert(len > 0);

    snprintf(buffer, len, "%f, %f", lat, long);
    buffer[len - 1] = 0; /* ensure null terminated */
}

int StringToCoordinates(const char *string, double *outLatitude, double *outLongitude) {
    assert(string != NULL);
    assert(outLatitude != NULL);
    assert(outLongitude != NULL);

    return (2 == sscanf(string, "%f, %f", outLatitude, outLongitude));
}

Utilisation:

char buffer[128];
CoordinatesToString(90.0, -33.0, buffer, 128);

double lat, lng;
if (StringToCoordinates(buffer, &lat, &lng)) {
    printf("lat: %f long %f\n", lat, lng);
}

MAIS. chaînes C ++ sont conçus pour ce type d'utilisation. Ils ne souffrent pas de problèmes de débordement potentiels inhérents aux réseaux de char, et vous ne devez pas gérer manuellement leur mémoire - ils sont redimensionnés pour adapter leur contenu au besoin. Y at-il une raison pourquoi vous voulez éviter std::string quand vous dites que vous êtes par ailleurs d'accord avec une solution C ++?

Voici une autre variante.

La logique est la même, mais il utilise une instruction switch cas pour une meilleure organisation, moins pause / continue, et les un retour plus rapide.

Vous devez également être en mesure d'améliorer celui-ci avec

case 'N':
case 'S':
case 'E':
case 'W': 

au besoin.

double Str2LatLong(char* coord)
{
    // char* testInput = "47,26'14\"";

    int i = 0;
    int parts[3] = {0};
    int* pCurr = parts;

    while(1)
    {
        switch (coord[i])
        {
            /* Any digit contributes to either degrees,minutes, or seconds (as *pCurr) */
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                *pCurr = 10* (*pCurr) + coord[i] - '0';
                break;

            /* A Null terminator triggers return (no break necessary) */
            case '\0':
                return parts[0] + ((double)parts[1])/60.0 + ((double)parts[2])/3600.0;

            /* Any other symbol moves pCurr from degrees to minutes, or minutes to seconds */
            default:
                *pCurr++;
        }
        i++;
    }

    return -1.0;  /* Should never reach this point! */
}

Le plus dur va représenter toutes les variations de format avec une grammaire simple. Une fois que vous faites, vous pouvez utiliser un outil générateur de lexer pour cracher un DFA hautement optimisé qui sera concurrentiel avec le meilleur code à l'écoute à la main.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top