Using mpq_t for aggregating currencies with wildly varying ranges

David Gillies daggillies at gmail.com
Wed Apr 16 19:20:45 UTC 2014


Oh lord, it's just a test harness, but if you want...

//
// de-canonicalize a pair of numbers i.e. treat them as numerator
// and denominator of a rational, assuming rational is terminating.
// Then rational a/b can be written as c/10^d
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <gmp.h>

int main(int argc,char *argv[])
{
    mpz_t                a,b,c,t,five;
    mp_bitcnt_t        m,n;
    char                *ab,*tb;
    size_t            as;

    if(argc<3)
        {
        printf("bad args\n");
        exit(EINVAL);
        }

    mpz_inits(t,c,NULL); // temporaries
    mpz_init_set_ui(five,5UL); // needed for mpz_remove, grr

    mpz_init_set_str(a,argv[1],10); // numerator
    mpz_init_set_str(b,argv[2],10); // denominator
    gmp_printf("a: %Zd\n",a);
    gmp_printf("b: %Zd\n",b);

    m=mpz_scan1(b,0); // power of 2 in den
    n=mpz_remove(c,b,five); // power of 5
    printf("m: %d\n",m);
    printf("n: %d\n",n);

    if(m>n)
        mpz_ui_pow_ui(t,5UL,m-n); // t = 5^(m-n)
    else
        mpz_setbit(t,n-m); // t = 2^(n-m)

    gmp_printf("t: %Zd\n",t);
    mpz_mul(a,a,t); // multiply numerator by t
    gmp_printf("num (decanonicalised): %Zd\n",a);
    // check denominator
    mpz_ui_pow_ui(c,5,n);
    mpz_mul_2exp(c,c,m);
    if(mpz_cmp(b,c))
        {
        printf("Bad denominator\n");
        exit(-1);
        }

    as=mpz_sizeinbase(a,10);
    if((ab=malloc(as+2))==NULL)
        {
        perror("bad alloc (ab)");
        exit(errno);
        }
    if((tb=malloc(as+2))==NULL)
        {
        perror("bad alloc (tb)");
        exit(errno);
        }
    as=gmp_sprintf(ab,"%Zd",a);

    m=(m>n ? m : n);
    if(m>0)
        {
        strncpy(tb,ab,as-m);
        tb[as-m]=0;
        printf("\n=====> %s.%s\n",tb,ab+as-m);
        }
    else
        printf("\n=====> %s\n",ab);

    free(ab);
    free(tb);

    return 0;
}


Pretty ugly, I'm afraid, but it's proof of concept.


On Wed, Apr 16, 2014 at 12:33 PM, Donovan Hide <donovanhide at gmail.com>wrote:

> Thanks Phil and David for the pointers! Much appreciated. I've found that
> the simplifying of the rationals hasn't occurred when I've switched over to
> using the C interface from the C++ interface. Not sure if a canonicalise
> was hidden away somewhere in the C++ wrapper output handling...
>
> David, any chance of seeing your code? I'm just working on the decimal
> place shifting in the string output. My C is very rusty :-)
>
>



-- 
David Gillies
San Jose
Costa Rica


More information about the gmp-discuss mailing list