2010-11-13 4 views
1

J'ai un programme pour calculer un produit pondéré (j'ai adapté d'un autre programme que j'ai trouvé). Mais je ne peux pas comprendre comment initialiser la total_data partie de la struct product_state à un pour que je ne finis pas toujours avec un produit de zéro. En ce moment, il conserve la valeur zéro par défaut de sorte que toutes les valeurs que je transmets depuis SQLite soient supprimées. J'ai pris du C++ à l'université, mais jamais profondément dans les structures, et en revenir à cela est en dehors de ma timonerie. Merci!Initialiser les valeurs dans la fonction struct in C utilisée comme un agrégateur SQLite

/* product.c */ 

#include "sqlite3ext.h" 
SQLITE_EXTENSION_INIT1; 

#include <stdlib.h> 

typedef struct product_state_s { 
    double total_data; /* sum of (data * weight) values */ 
    double total_wt; /* sum of weight values */ 
} product_state; 

static void product_step(sqlite3_context *ctx, int num_values, sqlite3_value **values) 
{ 
    double   row_wt = 1.0; 
    int   type; 
    product_state *st = (product_state*)sqlite3_aggregate_context(ctx, 
               sizeof(product_state)); 
    if (st == NULL) { 
     sqlite3_result_error_nomem(ctx); 
     return; 
    } 

    /* Extract weight, if we have a weight and it looks like a number */ 
    if (num_values == 2) { 
     type = sqlite3_value_numeric_type(values[1]); 
     if ((type == SQLITE_FLOAT)||(type == SQLITE_INTEGER)) { 
      row_wt = sqlite3_value_double(values[1]); 
     } 
    } 

    /* Extract data, if we were given something that looks like a number. */ 
    type = sqlite3_value_numeric_type(values[0]); 
    if ((type == SQLITE_FLOAT)||(type == SQLITE_INTEGER)) { 
     st->total_data *= row_wt * sqlite3_value_double(values[0]); 
     st->total_wt += row_wt; 
    } 
} 

static void product_final(sqlite3_context *ctx) 
{ 
    double   result = 0.0; 
    product_state *st = (product_state*)sqlite3_aggregate_context(ctx, 
               sizeof(product_state)); 
    if (st == NULL) { 
     sqlite3_result_error_nomem(ctx); 
     return; 
    } 

    if (st->total_wt != 0.0) { 
     result = st->total_data/st->total_wt; 
    } 
    sqlite3_result_double(ctx, result); 
} 

int product_init(sqlite3 *db, char **error, const sqlite3_api_routines *api) 
{ 
    SQLITE_EXTENSION_INIT2(api); 

    sqlite3_create_function(db, "product", 1, SQLITE_UTF8, 
      NULL, NULL, product_step, product_final); 
    sqlite3_create_function(db, "product", 2, SQLITE_UTF8, 
      NULL, NULL, product_step, product_final); 

    return SQLITE_OK; 
} 

Répondre

1

En product_step, après votre test st == NULL, essayez d'ajouter ceci:

if (0.0 == st->total_data) st->total_data = 1.0; 

En général, vous devriez être très prudent de comparer une valeur à virgule flottante pour l'égalité. Les mathématiques à virgule flottante sont limitées dans leur précision. Cependant, une comparaison simple devrait fonctionner ici, à condition qu'aucune des valeurs de la ligne ne soit nulle: la première fois, le tampon retourné par sqlite3_aggregate_context a été mis à zéro par sqlite, donc la valeur doit être égale à 0.0.

Si une valeur de ligne étant zéro est possible (et il est probable), vous devez ajouter état à la struct de dire si l'initialisation a été fait:

typedef struct product_state_s { 
    double total_data; /* sum of (data * weight) values */ 
    double total_wt; /* sum of weight values */ 
    bool  did_init; 
} product_state; 

et, plus tard, au lieu de vérifier si st->total_data est zéro, à la place:

if (!did_init) { 
    st->total_data = 1.0; 
    st->did_init = true; 
} 
Questions connexes