[C] float/double zerlegen

beuteltier

Grünschnabel
Hallo,
ich steh' jetzt schon eine Weile auf dem Schlauch und hoffe, Ihr könnt mir helfen...
Ich soll eine Funktion schreiben, die floats in Strings (char*) übersetzt, ähnlich sprintf(), aber:
das Ergebnis muss immer der "Canonical Representation" eines floats (wahlweise auch double) aus XML Schema entsprechen
(http://www.w3.org/TR/xmlschema-2/#float-canonical-representation).
Ich hab' ewig Google gefüttert, implementierungen von sprintf, vsnprintf und Konsorten sowie die manpages von diversen Funktionen aus <math.h> (frexp, modf, etc.) studiert doch ich komm' einfach nicht darauf wie ich anfangen soll!
Z.B. habe ich keine Ahnung wie ich das "single digit which is non-zero to the left of the decimal point" errechnen soll -

hat jemand eine Idee, einen kleinen Denkanstoß für mich?
Dank im Vorraus!
 
Hallo,

mit dem Format "%E" bei "sprintf" bekommst du schon eine ganz brauchbare Vorlage. So wie ich das sehe brauchst du aus dem erhaltenen String nur noch (wenn vorhanden) die nachfolgenden Nullen bei der Mantisse und ein positives Vorzeichen sowie die führenenden Nullen beim Exponenten herauswerfen.

Gruß
MCoder
 
Hallo
Kann man für VLC ein PlugIn Schreiben?
Wenn ja, in c/c++?
Habt ihr erfahrungen damit?

Mfg, SuperWaaaaaaaaadl123
 
mit dem Format "%E" bei "sprintf" bekommst du schon eine ganz brauchbare Vorlage.
Daran hab' ich auch schon gedacht. Allerdings ist fraglich ob mein Prof. akzeptiert dass ich einem simplen Wrapper für snprintf() schreibe; zumal der Aufruf zum Ermitteln der benötigten Anzahl von Zeichen (mittels NULL/0 Kombination) entweder einen zu hohen Wert zurückgeben könnte (für Nullen etc.) oder aber die Implementation verlangt selbst für diesen Aufruf einen weiteren, funktions-internen Buffer zu deklarieren als auch 2(!) Aufrufe von (snprintf(), dann sprintf()) vorzunehmen.

Dennoch, wenn ich nicht auf etwas besseres komme wird das wohl die Lösung sein die ich einreiche...
 
Daran hab' ich auch schon gedacht. Allerdings ist fraglich ob mein Prof. akzeptiert dass ich einem simplen Wrapper für snprintf() schreibe
Welches Ziel wird denn mit der Übung verfolgt bzw. was ist das Thema der Vorlesung?

Wenn du dadurch das IEEE 754 Gleitkommaformat besser verstehen sollst, vermute ich mal das eine Lösung mit sprintf nicht akzeptabel ist.

Gruß
 
Sorry, aber ich blick's einfach nicht. Nach dem meine snprintf() Lösung ja schon funktioniert (siehe unten), sollte es doch nicht soo schwer sein das ganze selbst auf die Beine zu stellen.
Doch schaffe ich es nicht einmal die auf http://de.wikipedia.org/wiki/IEEE_754 beschriebenen Berechnungen nach C zu übersetzen!
Und wenn ich versuche den GNU Quellcode von vasnprintf zu verstehen, finde ich einfach nicht die Teile die für float/double interessant sind, bzw. es scheint als würde sich die Funktion immer wieder selbst aufrufen...

Das hab' ich bisher (die kläglichen IEEE754 Versuche erspar' ich Euch mal):
Code:
#define SERIALIZE_FLOAT_SNPRINTF

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>

#ifdef SERIALIZE_FLOAT_SNPRINTF
# include <stdio.h>
#else
# include <float.h>
#endif

static size_t
serialize_float(float, char*, size_t);

int
main(const int argc, const char *const *argv)
{
    int argn;
    float value;
    char buffer[100], *end;
    for(argn = 1; argc != argn; ++argn) {
        errno = 0;
        value = strtof(argv[argn], &end);
        if(0 == errno) {
            while(isspace(*end)) ++end;
            if('\0' == *end)
              {
                assert( serialize_float(value, buffer, 100) <=
                    serialize_float(value, NULL, 0) );
                puts(buffer);
                continue;
              }
            errno = EINVAL;
        }
        fprintf( stderr, "failed to parse \"%s\": %s\n", argv[argn],
            strerror(errno) );
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}


static size_t
serialize_float(float value, char *buffer, size_t size)
{
    size_t length;
#ifdef SERIALIZE_FLOAT_SNPRINTF
    unsigned offset;
#else
# error "Kein Plan!"
#endif
#   define SERIALIZE_FLOAT_SPECIAL(CONDITION, STRING, LENGTH) \
    do { \
        if((CONDITION)) { \
            if(0 != size) { \
                assert(LENGTH + 1 <= size); \
                memcpy(buffer, STRING, LENGTH + 1); \
            } \
            return LENGTH; \
        } \
    } while(0)
    SERIALIZE_FLOAT_SPECIAL(isnan(value), "NaN", 3);
    SERIALIZE_FLOAT_SPECIAL(0.F == value || -0.F == value, "0.0E0", 5);
    if(isinf(value)) {
        SERIALIZE_FLOAT_SPECIAL(0.F > value, "-INF", 4);
        SERIALIZE_FLOAT_SPECIAL(1.F, "INF", 3);
    }
#   undef SERIALIZE_FLOAT_SPECIAL
#ifdef SERIALIZE_FLOAT_SNPRINTF
    if(0 == size) {
        return snprintf(NULL, 0, "%E", value);
    }
    assert(NULL != buffer);
    assert(size >= (length = snprintf(buffer, size, "%E", value)));
    /* if('+' == *buffer) {
        memmove(buffer, &buffer[1], length);
        --length;
    } */
    for(offset = 0, buffer += 3;;) {
        if('0' == buffer[offset]) {
            ++offset;
        } else if('E' != buffer[offset]) {
            buffer += offset + 1;
            offset = 0;
        } else {
            if(0 != offset) {
                memmove( buffer, &buffer[offset],
                    strlen(&buffer[offset]) + 1 );
                length -= offset;
            }
            break;
        }
    }
    if(0 != (offset = strspn(++buffer, "+0"))) {
        if('\0' == buffer[offset]) --offset;
        memmove( buffer, &buffer[offset], strlen(&buffer[offset]) + 1);
    }
#else
    if(signbit(value)) {
        value = -value;
        length = 4; /* -x.x */
        if(0 != size) {
            *buffer++ = '-';
        }
    } else {
        length = 3; /* 0.x */
    }
    /* ? */
    buffer[length] = '\0';
#endif
    return length;
}
 
Zurück