Question

Je veux savoir le premier double de haut 0d qui dévie la longue de la « même valeur » par certains delta, par exemple 1E-8. Je ne ici cependant. Je suis en train de le faire en C, bien que je l'habitude d'utiliser des langues gérées, juste au cas où. S'il vous plaît aider.


#include <stdio.h>
#include <limits.h>
#define DELTA 1e-8

int main() {
    double d = 0; // checked, the literal is fine
    long i;
    for (i = 0L; i < LONG_MAX; i++) {
         d=i; // gcc does the cast right, i checked
         if (d-i > DELTA || d-i < -DELTA) {
              printf("%f", d);
              break;
         }
    }
}

Je suppose que la question est que di i moulages de doubler et donc d == i et la différence est toujours 0. Comment puis-je détecter ce bien - je préfère coulée amusant C sur les chaînes comparant , qui prendrait une éternité.

Réponse : est exactement comme nous l'espérions. 2 ^ 53 + 1 = 9007199254740993 est le premier point de différence selon les outils standard C / UNIX / POSIX. Merci beaucoup à pax pour son programme. Et je suppose que les mathématiques gagne encore.

Était-ce utile?

La solution

Doubles en IEE754 ont une précision de 52 bits ce qui signifie qu'ils peuvent enregistrer des numéros exactement à (au moins) 2 51 .

Si vos positions longues sont 32 bits, ils ne le sont (positif) compris entre 0 et 2 31 donc il n'y a pas un long double 32 bits qui ne peut pas être représenté exactement. Pour un 64 peu long, il sera (environ) 2 52 donc je commencerais autour de là-bas, pas à zéro.

Vous pouvez utiliser le programme suivant pour détecter où les échecs commencent à se produire. Une version antérieure j'avais compté sur le fait que le dernier chiffre dans un nombre qui double en continu suit la séquence {2,4,8,6}. Cependant, j'ai choisi finalement d'utiliser un outil de confiance (bc) connu pour vérifier le nombre entier, pas seulement le dernier chiffre.

Gardez à l'esprit que ce peut être affectés par les actions de sprintf() plutôt que la précision réelle des doubles (je ne pense pas personnellement car il avait aucun problème avec certains numéros jusqu'à 2 < sup> 143 ).

Voici le programme:

#include <stdio.h>
#include <string.h>

int main() {
    FILE *fin;
    double d = 1.0; // 2^n-1 to avoid exact powers of 2.
    int i = 1;
    char ds[1000];
    char tst[1000];

    // Loop forever, rely on break to finish.
    while (1) {
        // Get C version of the double.
        sprintf (ds, "%.0f", d);

        // Get bc version of the double.
        sprintf (tst, "echo '2^%d - 1' | bc >tmpfile", i);
        system(tst);
        fin = fopen ("tmpfile", "r");
        fgets (tst, sizeof (tst), fin);
        fclose (fin);
        tst[strlen (tst) - 1] = '\0';

        // Check them.
        if (strcmp (ds, tst) != 0) {
            printf( "2^%d - 1 <-- bc failure\n", i);
            printf( "   got       [%s]\n", ds);
            printf( "   expected  [%s]\n", tst);
            break;
        }

        // Output for status then move to next.
        printf( "2^%d - 1 = %s\n", i, ds);
        d = (d + 1) * 2 - 1;  // Again, 2^n - 1.
        i++;
    }
}

Cela permet d'aller jusqu'à:

2^51 - 1 = 2251799813685247
2^52 - 1 = 4503599627370495
2^53 - 1 = 9007199254740991
2^54 - 1 <-- bc failure
   got       [18014398509481984]
   expected  [18014398509481983]

qui est sur le point où je m'y attendais à l'échec.

En aparté, je l'origine utilisé nombres de la forme 2 n , mais cela m'a fait jusqu'à:

2^136 = 87112285931760246646623899502532662132736
2^137 = 174224571863520493293247799005065324265472
2^138 = 348449143727040986586495598010130648530944
2^139 = 696898287454081973172991196020261297061888
2^140 = 1393796574908163946345982392040522594123776
2^141 = 2787593149816327892691964784081045188247552
2^142 = 5575186299632655785383929568162090376495104
2^143 <-- bc failure
   got       [11150372599265311570767859136324180752990210]
   expected  [11150372599265311570767859136324180752990208]

avec la taille d'un double étant de 8 octets (vérifié avec sizeof). Il est apparu ces chiffres étaient de la forme binaire "1000..." qui peut être représenté pour beaucoup plus longtemps avec des doubles. C'est quand je suis passé à l'aide de 2 n -1 pour obtenir un meilleur profil binaire. Tous les bits à

Autres conseils

La première longue pour être « mauvais » quand il est lancé à une double ne sera pas hors de 1E-8, il sera hors de 1. Tant que le double peut adapter long dans son significand, il le représentera avec précision .

J'oublie combien de bits double précision a pour vs offset, mais cela vous dire la taille maximale qu'il pourrait représenter. La première longue à tort devrait avoir la forme binaire 10000 ..., de sorte que vous pouvez trouver beaucoup plus rapide en commençant à 1 et à gauche décalage.

Wikipedia dit 52 bits dans le significand, sans compter le départ implicite 1. Cela devrait signifier le premier temps d'être jeté à une valeur différente est 2 ^ 53.

Bien que je suis hésité à parler Fortran 95 et successeurs dans cette discussion, je mentionne que la norme Fortran depuis 1990 a offert une ESPACEMENT fonction intrinsèque qui vous indique ce que la différence entre représentables sont sur REAL un réel donné. Vous pouvez faire une recherche binaire sur ce point, l'arrêt lorsque ESPACEMENT (X)> DELTA. Pour les compilateurs qui utilisent le même modèle de virgule flottante que celui que vous êtes intéressé (susceptible d'être la norme IEEE754), vous devriez obtenir les mêmes résultats.

Off main, je pensais que doubles pourraient représenter tous les entiers (dans leurs limites) exactement.

Si ce n'est pas le cas, alors vous allez vouloir jeter i et d à quelque chose avec plus de précision que l'un d'eux. Peut-être un long double fonctionnera.

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