static guint
ght_gnc_numeric_hash(gconstpointer v1)
{
    gnc_numeric n1 = *(gnc_numeric *)v1;
    gdouble d1 = gnc_numeric_to_double(n1);
    return g_str_hash(&d1);
}
Example #2
0
static void
check_double (void)
{
    double flo;
    gnc_numeric val = gnc_numeric_create (0, 1);

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (112346, 100000),
                    double_to_gnc_numeric(1.1234567890123,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(6) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s double 6 figs");

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (112346, 10000000),
                    double_to_gnc_numeric(0.011234567890123,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(6) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s double 6 figs");

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (112346, 100),
                    double_to_gnc_numeric(1123.4567890123,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(6) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s double 6 figs");
    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (112346, 10000000000LL),
                    double_to_gnc_numeric(1.1234567890123e-5,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(6) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s double 6 figs");

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (961600000, 10000000),
                    double_to_gnc_numeric(96.16,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(9) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s GncNumeric from 96.16");

    check_unary_op (gnc_numeric_eq,
                    gnc_numeric_create (9616000000, 1),
                    double_to_gnc_numeric(9616000000.0,
                                          GNC_DENOM_AUTO,
                                          GNC_HOW_DENOM_SIGFIGS(9) |
                                          GNC_HOW_RND_ROUND),
                    val, "expected %s = %s GncNumeric from 9616000000.0");

    flo = gnc_numeric_to_double(gnc_numeric_create(7, 16));
    do_test ((0.4375 == flo), "float pt conversion");
}
Example #3
0
static void
convert_query_term_to_sql( const GncSqlBackend* be, const gchar* fieldName, QofQueryTerm* pTerm, GString* sql )
{
    QofQueryPredData* pPredData;
    gboolean isInverted;

    g_return_if_fail( pTerm != NULL );
    g_return_if_fail( sql != NULL );

    pPredData = qof_query_term_get_pred_data( pTerm );
    isInverted = qof_query_term_is_inverted( pTerm );

    if ( g_strcmp0( pPredData->type_name, QOF_TYPE_GUID ) == 0 )
    {
        query_guid_t guid_data = (query_guid_t)pPredData;
        GList* guid_entry;

        g_string_append( sql, "(" );
        g_string_append( sql, fieldName );

        switch ( guid_data->options )
        {
        case QOF_GUID_MATCH_ANY:
            if ( isInverted ) g_string_append( sql, " NOT IN (" );
            else g_string_append( sql, " IN (" );
            break;

        case QOF_GUID_MATCH_NONE:
            if ( isInverted ) g_string_append( sql, " IN (" );
            else g_string_append( sql, " NOT IN (" );
            break;

        default:
            PERR( "Unexpected GncGUID match type: %d\n", guid_data->options );
        }

        for ( guid_entry = guid_data->guids; guid_entry != NULL; guid_entry = guid_entry->next )
        {
            gchar guid_buf[GUID_ENCODING_LENGTH+1];

            if ( guid_entry != guid_data->guids ) g_string_append( sql, "," );
            (void)guid_to_string_buff( guid_entry->data, guid_buf );
            g_string_append_printf( sql, "'%s'", guid_buf );
        }
        g_string_append( sql, "))" );

    }
    else if ( g_strcmp0( pPredData->type_name, QOF_TYPE_CHAR ) == 0 )
    {
        query_char_t char_data = (query_char_t)pPredData;
        int i;

        if ( isInverted )
        {
            g_string_append( sql, "NOT(" );
        }
        if ( char_data->options == QOF_CHAR_MATCH_NONE )
        {
            g_string_append( sql, "NOT " );
        }
        g_string_append( sql, "(" );
        for ( i = 0; char_data->char_list[i] != '\0'; i++ )
        {
            if ( i != 0 )
            {
                g_string_append( sql, " OR " );
            }
            g_string_append( sql, fieldName );
            g_string_append( sql, " = '" );
            g_string_append_c( sql, char_data->char_list[i] );
            g_string_append( sql, "'" );
        }
        g_string_append( sql, ") " );
        if ( isInverted )
        {
            g_string_append( sql, ") " );
        }

    }
    else if ( g_strcmp0( pPredData->type_name, QOF_TYPE_STRING ) == 0 )
    {
        query_string_t string_data = (query_string_t)pPredData;
        sqlEscape* escape = sqlEscape_new();

        if ( isInverted )
        {
            g_string_append( sql, "NOT(" );
        }
        if ( pPredData->how == QOF_COMPARE_NEQ )
        {
            g_string_append( sql, "NOT(" );
        }
        g_string_append( sql, fieldName );
        if ( string_data->is_regex || string_data->options == QOF_STRING_MATCH_CASEINSENSITIVE )
        {
            PWARN( "String is_regex || option = QOF_STRING_MATCH_INSENSITIVE\n" );
        }
//			g_string_append( sql, " ~" );
//		} else {
        g_string_append( sql, " =" );
//		}
//		if( string_data->options == QOF_STRING_MATCH_CASEINSENSITIVE ) {
//			g_string_append( sql, "*" );
//		}
        g_string_append( sql, "'" );
        g_string_append( sql, sqlEscapeString( escape, string_data->matchstring ) );
        g_string_append( sql, "'" );
        if ( pPredData->how == QOF_COMPARE_NEQ )
        {
            g_string_append( sql, ")" );
        }
        if ( isInverted )
        {
            g_string_append( sql, ")" );
        }
        sqlEscape_destroy( escape );

    }
    else
    {
        g_string_append( sql, "(" );
        g_string_append( sql, fieldName );
        convert_query_comparison_to_sql( pPredData, isInverted, sql );

        if ( strcmp( pPredData->type_name, QOF_TYPE_NUMERIC ) == 0 )
        {
            query_numeric_t pData = (query_numeric_t)pPredData;
            double d = gnc_numeric_to_double( pData->amount );

            g_string_append_printf( sql, "%f", d );

        }
        else if ( g_strcmp0( pPredData->type_name, QOF_TYPE_DATE ) == 0 )
        {
            query_date_t date_data = (query_date_t)pPredData;
            gchar* datebuf;

            datebuf = gnc_sql_convert_timespec_to_string( be, date_data->date );
            g_string_append_printf( sql, "'%s'", datebuf );

        }
        else if ( strcmp( pPredData->type_name, QOF_TYPE_INT32 ) == 0 )
        {
            query_int32_t pData = (query_int32_t)pPredData;

            g_string_append_printf( sql, "%d", pData->val );

        }
        else if ( strcmp( pPredData->type_name, QOF_TYPE_INT64 ) == 0 )
        {
            query_int64_t pData = (query_int64_t)pPredData;

            g_string_append_printf( sql, "%" G_GINT64_FORMAT, pData->val );

        }
        else if ( strcmp( pPredData->type_name, QOF_TYPE_DOUBLE ) == 0 )
        {
            query_double_t pData = (query_double_t)pPredData;

            g_string_append_printf( sql, "%f", pData->val );

        }
        else if ( strcmp( pPredData->type_name, QOF_TYPE_BOOLEAN ) == 0 )
        {
            query_boolean_t pData = (query_boolean_t)pPredData;

            g_string_append_printf( sql, "%d", pData->val );

        }
        else
        {
            PERR( "Unknown query predicate type: %s\n", pPredData->type_name );
        }

        g_string_append( sql, ")" );
    }
}
Example #4
0
gnc_numeric
gnc_numeric_convert(gnc_numeric in, gint64 denom, gint how)
{
    gnc_numeric out;
    gnc_numeric temp;
    gint64      temp_bc;
    gint64      temp_a;
    gint64      remainder;
    gint64      sign;
    gint        denom_neg = 0;
    double      ratio, logratio;
    double      sigfigs;
    qofint128 nume, newm;

    temp.num   = 0;
    temp.denom = 0;

    if (gnc_numeric_check(in))
    {
        return gnc_numeric_error(GNC_ERROR_ARG);
    }

    if (denom == GNC_DENOM_AUTO)
    {
        switch (how & GNC_NUMERIC_DENOM_MASK)
        {
        default:
        case GNC_HOW_DENOM_LCD:   /* LCD is meaningless with AUTO in here */
        case GNC_HOW_DENOM_EXACT:
            return in;
            break;

        case GNC_HOW_DENOM_REDUCE:
            /* reduce the input to a relatively-prime fraction */
            return gnc_numeric_reduce(in);
            break;

        case GNC_HOW_DENOM_FIXED:
            if (in.denom != denom)
            {
                return gnc_numeric_error(GNC_ERROR_DENOM_DIFF);
            }
            else
            {
                return in;
            }
            break;

        case GNC_HOW_DENOM_SIGFIG:
            ratio    = fabs(gnc_numeric_to_double(in));
            if (ratio < 10e-20)
            {
                logratio = 0;
            }
            else
            {
                logratio = log10(ratio);
                logratio = ((logratio > 0.0) ?
                            (floor(logratio) + 1.0) : (ceil(logratio)));
            }
            sigfigs  = GNC_HOW_GET_SIGFIGS(how);

            if (fabs(sigfigs - logratio) > 18)
                return gnc_numeric_error(GNC_ERROR_OVERFLOW);

            if (sigfigs - logratio >= 0)
            {
                denom    = (gint64)(pow(10, sigfigs - logratio));
            }
            else
            {
                denom    = -((gint64)(pow(10, logratio - sigfigs)));
            }

            how = how & ~GNC_HOW_DENOM_SIGFIG & ~GNC_NUMERIC_SIGFIGS_MASK;
            break;

        }
    }

    /* Make sure we need to do the work */
    if (in.denom == denom)
    {
        return in;
    }
    if (in.num == 0)
    {
        out.num = 0;
        out.denom = denom;
        return out;
    }

    /* If the denominator of the input value is negative, get rid of that. */
    if (in.denom < 0)
    {
        in.num = in.num * (- in.denom);  /* BUG: overflow not handled.  */
        in.denom = 1;
    }

    sign = (in.num < 0) ? -1 : 1;

    /* If the denominator is less than zero, we are to interpret it as
     * the reciprocal of its magnitude. */
    if (denom < 0)
    {

        /* XXX FIXME: use 128-bit math here ... */
        denom     = - denom;
        denom_neg = 1;
        temp_a    = (in.num < 0) ? -in.num : in.num;
        temp_bc   = in.denom * denom;  /* BUG: overflow not handled.  */
        remainder = temp_a % temp_bc;
        out.num   = temp_a / temp_bc;
        out.denom = - denom;
    }
    else
    {
        /* Do all the modulo and int division on positive values to make
         * things a little clearer. Reduce the fraction denom/in.denom to
         * help with range errors */
        temp.num   = denom;
        temp.denom = in.denom;
        temp       = gnc_numeric_reduce(temp);

        /* Symbolically, do the following:
         * out.num   = in.num * temp.num;
         * remainder = out.num % temp.denom;
         * out.num   = out.num / temp.denom;
         * out.denom = denom;
         */
        nume = mult128 (in.num, temp.num);
        newm = div128 (nume, temp.denom);
        remainder = rem128 (nume, temp.denom);

        if (newm.isbig)
        {
            return gnc_numeric_error(GNC_ERROR_OVERFLOW);
        }

        out.num = newm.lo;
        out.denom = denom;
    }

    if (remainder)
    {
        switch (how & GNC_NUMERIC_RND_MASK)
        {
        case GNC_HOW_RND_FLOOR:
            if (sign < 0)
            {
                out.num = out.num + 1;
            }
            break;

        case GNC_HOW_RND_CEIL:
            if (sign > 0)
            {
                out.num = out.num + 1;
            }
            break;

        case GNC_HOW_RND_TRUNC:
            break;

        case GNC_HOW_RND_PROMOTE:
            out.num = out.num + 1;
            break;

        case GNC_HOW_RND_ROUND_HALF_DOWN:
            if (denom_neg)
            {
                if ((2 * remainder) > in.denom * denom)
                {
                    out.num = out.num + 1;
                }
            }
            else if ((2 * remainder) > temp.denom)
            {
                out.num = out.num + 1;
            }
            /* check that 2*remainder didn't over-flow */
            else if (((2 * remainder) < remainder) &&
                     (remainder > (temp.denom / 2)))
            {
                out.num = out.num + 1;
            }
            break;

        case GNC_HOW_RND_ROUND_HALF_UP:
            if (denom_neg)
            {
                if ((2 * remainder) >= in.denom * denom)
                {
                    out.num = out.num + 1;
                }
            }
            else if ((2 * remainder ) >= temp.denom)
            {
                out.num = out.num + 1;
            }
            /* check that 2*remainder didn't over-flow */
            else if (((2 * remainder) < remainder) &&
                     (remainder >= (temp.denom / 2)))
            {
                out.num = out.num + 1;
            }
            break;

        case GNC_HOW_RND_ROUND:
            if (denom_neg)
            {
                if ((2 * remainder) > in.denom * denom)
                {
                    out.num = out.num + 1;
                }
                else if ((2 * remainder) == in.denom * denom)
                {
                    if (out.num % 2)
                    {
                        out.num = out.num + 1;
                    }
                }
            }
            else
            {
                if ((2 * remainder ) > temp.denom)
                {
                    out.num = out.num + 1;
                }
                /* check that 2*remainder didn't over-flow */
                else if (((2 * remainder) < remainder) &&
                         (remainder > (temp.denom / 2)))
                {
                    out.num = out.num + 1;
                }
                else if ((2 * remainder) == temp.denom)
                {
                    if (out.num % 2)
                    {
                        out.num = out.num + 1;
                    }
                }
                /* check that 2*remainder didn't over-flow */
                else if (((2 * remainder) < remainder) &&
                         (remainder ==  (temp.denom / 2)))
                {
                    if (out.num % 2)
                    {
                        out.num = out.num + 1;
                    }
                }
            }
            break;

        case GNC_HOW_RND_NEVER:
            return gnc_numeric_error(GNC_ERROR_REMAINDER);
            break;
        }
    }

    out.num = (sign > 0) ? out.num : (-out.num);

    return out;
}
static void
_var_numeric_to_string(gnc_numeric *value, GString **str)
{
    *str = g_string_sized_new(5);
    g_string_printf(*str, "%0.2f", gnc_numeric_to_double(*value));
}
static void
check_reciprocal(void)
{
    gnc_numeric a, b, ans, val;
    double flo;

    val = gnc_numeric_create(-60, 20);
    check_unary_op (gnc_numeric_eq, gnc_numeric_create (-3, -1),
                    gnc_numeric_convert(val, GNC_DENOM_RECIPROCAL(1),
                                        GNC_HOW_RND_NEVER),
                    val, "expected %s got %s = (%s as RECIP(1))");

    a = gnc_numeric_create(200, 100);
    b = gnc_numeric_create(300, 100);

    /* 2 + 3 = 5 */
    ans = gnc_numeric_add(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
    check_binary_op (gnc_numeric_create(5, -1),
                     ans, a, b, "expected %s got %s = %s + %s for reciprocal");

    /* 2 + 3 = 5 */
    a = gnc_numeric_create(2, -1);
    b = gnc_numeric_create(300, 100);
    ans = gnc_numeric_add(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
    check_binary_op (gnc_numeric_create(5, -1),
                     ans, a, b, "expected %s got %s = %s + %s for reciprocal");

    /* check gnc_numeric_to_double */
    flo = gnc_numeric_to_double(gnc_numeric_create(5, -1));
    do_test ((5.0 == flo), "reciprocal conversion");

    /* check gnc_numeric_compare */
    a = gnc_numeric_create(2, 1);
    b = gnc_numeric_create(2, -1);
    do_test((0 == gnc_numeric_compare(a, b)), " 2 == 2 ");
    a = gnc_numeric_create(2, 1);
    b = gnc_numeric_create(3, -1);
    do_test((-1 == gnc_numeric_compare(a, b)), " 2 < 3 ");
    a = gnc_numeric_create(-2, 1);
    b = gnc_numeric_create(2, -1);
    do_test((-1 == gnc_numeric_compare(a, b)), " -2 < 2 ");
    a = gnc_numeric_create(2, -1);
    b = gnc_numeric_create(3, -1);
    do_test((-1 == gnc_numeric_compare(a, b)), " 2 < 3 ");

    /* check for equality */
    a = gnc_numeric_create(2, 1);
    b = gnc_numeric_create(2, -1);
    do_test(gnc_numeric_equal(a, b), " 2 == 2 ");

    /* check gnc_numeric_mul */
    a = gnc_numeric_create(2, 1);
    b = gnc_numeric_create(3, -1);
    ans = gnc_numeric_mul(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
    check_binary_op (gnc_numeric_create(6, -1),
                     ans, a, b, "expected %s got %s = %s * %s for reciprocal");

    /* check gnc_numeric_div */
    /* -60 / 20 = -3 */
    a = gnc_numeric_create(-60, 1);
    b = gnc_numeric_create(2, -10);
    ans = gnc_numeric_div(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
    check_binary_op (gnc_numeric_create(-3, -1),
                     ans, a, b, "expected %s got %s = %s / %s for reciprocal");

    /* 60 / 20 = 3 */
    a = gnc_numeric_create(60, 1);
    b = gnc_numeric_create(2, -10);
    ans = gnc_numeric_div(a, b, GNC_DENOM_RECIPROCAL(1), GNC_HOW_RND_NEVER);
    check_binary_op (gnc_numeric_create(3, -1),
                     ans, a, b, "expected %s got %s = %s / %s for reciprocal");


}
Example #7
0
static
void*
func_op(const char *fname, int argc, void **argv)
{
    SCM scmFn, scmArgs, scmTmp;
    int i;
    var_store *vs;
    gchar *str;
    gnc_numeric n, *result;
    GString *realFnName;

    realFnName = g_string_sized_new( strlen(fname) + 5 );
    g_string_printf( realFnName, "gnc:%s", fname );
    scmFn = scm_internal_catch(SCM_BOOL_T,
                               (scm_t_catch_body)scm_c_eval_string, realFnName->str,
                               scm_handle_by_message_noexit, NULL);
    g_string_free( realFnName, TRUE );
    if (!scm_is_procedure(scmFn))
    {
        /* FIXME: handle errors correctly. */
        printf( "gnc:\"%s\" is not a scm procedure\n", fname );
        return NULL;
    }
    scmArgs = scm_listify( SCM_UNDEFINED );
    for ( i = 0; i < argc; i++ )
    {
        /* cons together back-to-front. */
        vs = (var_store*)argv[argc - i - 1];
        switch ( vs->type )
        {
        case VST_NUMERIC:
            n = *(gnc_numeric*)(vs->value);
            scmTmp = scm_make_real( gnc_numeric_to_double( n ) );
            break;
        case VST_STRING:
            str = (char*)(vs->value);
            scmTmp = scm_mem2string( str, strlen(str) );
            break;
        default:
            /* FIXME: error */
            printf( "argument %d not a numeric or string [type = %d]\n",
                    i, vs->type );
            return NULL;
            break; /* notreached */
        }
        scmArgs = scm_cons( scmTmp, scmArgs );
    }

    //scmTmp = scm_apply(scmFn, scmArgs , SCM_EOL);
    scmTmp = gfec_apply(scmFn, scmArgs, _exception_handler);
    if (_function_evaluation_error_msg != NULL)
    {
        PERR("function eval error: [%s]\n", _function_evaluation_error_msg);
        _function_evaluation_error_msg = NULL;
        return NULL;
    }

    result = g_new0( gnc_numeric, 1 );
    *result = double_to_gnc_numeric( scm_num2dbl(scmTmp, G_STRFUNC),
                                     GNC_DENOM_AUTO,
                                     GNC_HOW_DENOM_SIGFIGS(6) | GNC_HOW_RND_ROUND );
    /* FIXME: cleanup scmArgs = scm_list, cons'ed cells? */
    return (void*)result;
}