代码之家  ›  专栏  ›  技术社区  ›  Richard Herron

初始化C函数中用作sqlite聚合器的结构中的值

  •  1
  • Richard Herron  · 技术社区  · 14 年前

    我有一个计算加权积的程序(我改编自我发现的另一个程序)。但我不知道如何初始化 total_data 部分 product_state 构造为1,这样我就不会总是以零的乘积结束。现在,它将保留默认的零值,以便我从sqlite传入的所有值都归零。

    我在大学里学过一些C++,但从来没有深入到结构上去,回到这一步就在我的驾驶室之外。谢谢!

    /* 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;
    }
    
    1 回复  |  直到 14 年前
        1
  •  1
  •   Jeremy W. Sherman    14 年前

    product_step ,测试后 st == NULL ,尝试添加:

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

    一般来说,您应该非常谨慎地比较浮点值是否相等。浮点数学的精度有限。但是,如果行中的值都不是零,那么在这里直接比较应该可以很好地工作:第一次通过时,缓冲区返回 sqlite3_aggregate_context 已被sqlite归零,因此该值应比较等于 0.0 .

    如果行值可能为零(也可能为零),则应向结构添加状态,以指示是否已完成初始化:

    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;
    

    稍后,而不是测试 st->total_data 而是为零:

    if (!did_init) {
        st->total_data = 1.0;
        st->did_init = true;
    }
    
    推荐文章