Frage

Ich mag die erste Doppel von 0d nach oben kennen, die von einigem Delta durch die lange von dem „gleichen Wert“ abweicht, sagt 1e-8. Ich versagen, obwohl hier. Ich versuche, dies in C zu tun, obwohl ich in der Regel verwalteten Sprachen verwenden, nur für den Fall. Bitte helfen.


#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;
         }
    }
}

Ich vermute, dass das Problem, dass di ist Güsse i deshalb verdoppeln und d == i und dann ist der Unterschied immer 0. Wie sonst kann ich das richtig erkennen - ich würde Spaß C Gießen über den Vergleich Saiten bevorzugen , die für immer dauern würde.

ANTWORT : ist genau so, wie wir erwartet hatten. 2 ^ 53 + 1 = 9007199254740993 ist der erste Punkt des Unterschiedes nach Standard C / UNIX / POSIX-Tool. Dank viel zu pax für sein Programm. Und ich denke, Mathematik gewinnt wieder.

War es hilfreich?

Lösung

Doubles in IEE754 haben eine Genauigkeit von 52 Bits, das heißt, sie Nummern speichern können genau bis zu (mindestens) 2 51 .

Wenn Ihr sehnt sich 32-Bit sind, werden sie nur die (positive) haben Bereich 0 bis 2 31 so nicht gibt es 32-Bit lang, die nicht genau als doppelt dargestellt werden kann. Für einen 64-Bit lang, es wird (in etwa) 2 52 , damit ich um dort beginnen würde, nicht bei Null.

Sie können das folgende Programm verwenden, um festzustellen, wo die Fehler auftreten starten. Eine frühere Version hatte ich auf die Tatsache verlassen, dass die letzte Ziffer in einer Zahl, die kontinuierlich die Sequenz verdoppelt folgt {2,4,8,6}. Allerdings entschied ich mich schließlich ein bekanntes vertrauenswürdiges Werkzeug (bc) zu verwenden, um die gesamte Anzahl Prüfung, nicht nur die letzte Ziffer.

Beachten Sie, dass diese können durch die Aktionen der sprintf() betroffen sein und nicht als die reale Genauigkeit verdoppelt (ich glaube nicht persönlich, da es bis zu 2 keine Probleme mit bestimmten Zahlen hatte < sup> 143 ).

Dies ist das Programm:

#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++;
    }
}

Das hält zu gehen, bis:

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

das ist, wo ich es erwartet auszufallen.

Als beiseite, habe ich ursprünglich Zahlen der Form 2 n , aber das hat mich bis zu:

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]

mit der Größe eines Doppel ist 8 Bytes (mit sizeof geprüft). Es stellte sich heraus, diese Zahlen der binären Form "1000..." waren, die für weit mehr mit Doppel dargestellt werden kann. Das ist, wenn ich in Switched 2 n -1 ein besseres Bitmuster zu erhalten. Nur Bits

Andere Tipps

Die erste lang ‚falsch‘ sein, wenn zu einem Doppel gegossen wird von 1e-8 nicht ausgeschaltet wird, wird es ab Solange von 1 sein als die doppelten lange in seinen Signifikanden passen, wird es genau darstellen .

ich vergessen, wie viele Bits ein Doppel für Präzision hat vs Offset, aber das würde man die maximale Größe sagen, es darstellen könnte. Die erste lange falsch sein sollte, die binäre Form 10000 ..., so dass Sie es viel schneller durch beginnend mit 1 und Linksverschiebung finden.

Wikipedia sagt 52 Bits in der Mantisse, nicht die implizite Ausgangs 1. Zählen, dass die erste lange bedeuten sollte auf einen anderen Wert zu gießenden 2 ^ 53.

Obwohl ich zögerlich bin Fortran 95 und Nachfolger in dieser Diskussion zu erwähnen, ich erwähnen, dass Fortran seit 1990 Standard eine SPACING intrinsische Funktion angeboten hat, die Ihnen sagt, was der Unterschied zwischen darstellbare REALs sind über einen gegebenen REAL. Sie könnten eine binäre Suche auf dies tun, zu stoppen, wenn SPACING (X)> DELTA. Für Compiler, die die gleiche Floating-Point-Modell als die, die Sie interessieren sich für (wahrscheinlich zu sein, der IEEE754-Standard) verwenden, sollten Sie die gleichen Ergebnisse erhalten.

Aus der Hand, dachte ich, dass verdoppelt alle ganzen Zahlen darstellen könnte (innerhalb ihrer Grenzen) genau.

Wenn das nicht der Fall ist, dann wirst du sowohl mich als auch d, um etwas mit mehr Präzision als jeder von ihnen werfen wollen. Vielleicht eine lange doppelte funktioniert.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top