/* fraction.c */
/* Copyright 1992 by P.J. LaBrocca */

#include <stdio.h>
#include "mixed.h"

mixed_t *mix_init( mixed_t *m, Integer w, Integer n, Integer d )
{
    m->sign  = POSITIVE;
    m->whole = w;
    if( w < 0 ) {
        m->sign  = NEGATIVE;
        m->whole *= -1;
    }
    m->num   = n;
    m->den   = d;
    m->factors[ NUMER ][ 0 ] = 1;
    m->factors[ DENOM ][ 0 ] = 1;
    return m;
}

mixed_t *mix_clear( mixed_t *m )
{
    m->whole = 0;
    m->num   = 0;
    m->den   = 1;
    m->factors[ NUMER ][ 0 ] = 1;
    m->factors[ DENOM ][ 0 ] = 1;
    m->sign  = POSITIVE;
    return m;
}

mixed_t *mix_factor( mixed_t *m )
{
    Integer n;
    int i;
    Integer *pi;
    Integer *pp;

    for( i = 0; i < 2; ++i) {
        pp = Primes;       /* point to global array of primes */
        (i != 0) ? (n = m->den) : (n = m->num);
        pi = &m->factors[i][0];

        while(n > 1) {
            if( !(n % *pp) ) {   /* if there is no remainder */
                n = (Integer) (n / *pp);  /* factor the prime out of number */
                *pi = *pp;         /* save the prime */
                ++pi;
                continue;         /* try the prime again */
            }
            ++pp;               /* next prime */
        }
        *pi = 1;
        pp = Primes;
    }
    return m;
}

mixed_t *mix_reduce( mixed_t *m )
{
    Integer tnum = 1, tden = 1;
    Integer *top = &m->factors[NUMER][0];
    Integer *bot = &m->factors[DENOM][0];

    if( m->num == 0) {
        return m;
    }
    if( m->den == 1 ) {
        m->whole += m->num;
        m->num = 0;
        return m;
    }
    mix_factor( m );  /* got to factor to reduce */
                     /*accumulators for reduced numerator & denominator*/
    while(*top != 1 && *bot != 1) {    /* neither factor is sentinel */
            if(*top == *bot) {    /* if the current factors are equal..*/
                    ++top;        /* ..cancel them & continue */
                    ++bot;
                    continue;
            }               /* otherwise accumulate the smaller*/
            (*top < *bot) ? (tnum *= *top++) : (tden *= *bot++);

    }
    while(*top != 1)              /* any remaining factors are */
            tnum *= *top++;      /* multiplied in */
    while(*bot != 1)
            tden *= *bot++;
    if(tnum == tden) {    /*ie, n/d == 1*/
        ++m->whole;          /*add 1 to whole*/
        m->num = 0;
        m->den = 1;
    }
    else if(tnum > tden) {              /*improper fraction*/
        m->whole += (Integer) (tnum / tden);
        m->num = tnum % tden;
        m->den = tden;
    }
    else {                              /*proper fraction*/
        m->num = tnum;
        m->den = tden;
    }
    if(m->num == 0) {          /* keep zero-valued fractions*/
        m->den = 1;            /* in consistent state*/
        if(m->whole == 0)
            mix_clear( m );
    }
    return m;
}

void mix_make_improper( mixed_t *m )  /* converts invoking instance*/
{                                   /* into an improper fraction*/
    m->num += m->whole * m->den;             /* if possible*/
    m->whole = 0;
}

/* If sizeof( Integer ) changes
   change %ld
*/
void mix_print( mixed_t *m )
{
    printf("\t");
    if( m->sign == -1 )
        printf("-");
    if( m->whole != 0 )
        printf("%ld", m->whole);
    if( m->num != 0 )
        printf(" %ld|%ld",m->num, m->den);
    if( (m->whole == 0) && (m->num == 0) )
        printf("0");
    printf("\n");
}

