예제 #1
0
static int euclid(_MIPD_ big x,int num)
{ /* outputs next c.f. quotient from gcd(w5,w6) */
    mr_small sr,m;
#ifdef MR_FP
    mr_small dres;
#endif
    mr_small lr,lq;
    big t;
#ifndef MR_GENERIC_MT
    miracl *mr_mip=get_mip();
#endif
    if (num==0)
    {
        mr_mip->oldn=(-1);
        mr_mip->carryon=FALSE;
        mr_mip->last=FALSE;
        if (compare(mr_mip->w6,mr_mip->w5)>0)
        { /* ensure w5>w6 */
            t=mr_mip->w5,mr_mip->w5=mr_mip->w6,mr_mip->w6=t;
            return (mr_mip->q=0);
        }
    }
    else if (num==mr_mip->oldn || mr_mip->q<0) return mr_mip->q;
    mr_mip->oldn=num;
    if (mr_mip->carryon) goto middle;
start:
    if (size(mr_mip->w6)==0) return (mr_mip->q=(-1));
    mr_mip->ndig=(int)mr_mip->w5->len;
    mr_mip->carryon=TRUE;
    mr_mip->a=1;
    mr_mip->b=0;
    mr_mip->c=0;
    mr_mip->d=1;
    if (mr_mip->ndig==1)
    {
        mr_mip->last=TRUE;
        mr_mip->u=mr_mip->w5->w[0];
        mr_mip->v=mr_mip->w6->w[0];
    }
    else
    {
        m=mr_mip->w5->w[mr_mip->ndig-1]+1;
        if (mr_mip->base==0)
        {
#ifndef MR_NOFULLWIDTH
            if (m==0)
            {
                mr_mip->u=mr_mip->w5->w[mr_mip->ndig-1];
                mr_mip->v=mr_mip->w6->w[mr_mip->ndig-1];
            }
            else
            {
                mr_mip->u=muldvm(mr_mip->w5->w[mr_mip->ndig-1],mr_mip->w5->w[mr_mip->ndig-2],m,&sr);
                mr_mip->v=muldvm(mr_mip->w6->w[mr_mip->ndig-1],mr_mip->w6->w[mr_mip->ndig-2],m,&sr);
            }
#endif
        }
        else
        {
            mr_mip->u=muldiv(mr_mip->w5->w[mr_mip->ndig-1],mr_mip->base,mr_mip->w5->w[mr_mip->ndig-2],m,&sr);
            mr_mip->v=muldiv(mr_mip->w6->w[mr_mip->ndig-1],mr_mip->base,mr_mip->w6->w[mr_mip->ndig-2],m,&sr);
        }
    }
    mr_mip->ku=mr_mip->u;
    mr_mip->kv=mr_mip->v;
middle:
    forever
    { /* work only with most significant piece */
        if (mr_mip->last)
        {
            if (mr_mip->v==0) return (mr_mip->q=(-1));
            lq=MR_DIV(mr_mip->u,mr_mip->v);
        }
        else
        {
            if (((mr_mip->v+mr_mip->c)==0) || ((mr_mip->v+mr_mip->d)==0)) break;
            lq=MR_DIV((mr_mip->u+mr_mip->a),(mr_mip->v+mr_mip->c));
            if (lq!=MR_DIV((mr_mip->u+mr_mip->b),(mr_mip->v+mr_mip->d))) break;
        }
        if (lq>=(mr_small)(MR_TOOBIG/mr_abs(mr_mip->d))) break;

        mr_mip->q=(int)lq;
        mr_mip->r=mr_mip->a-mr_mip->q*mr_mip->c;
        mr_mip->a=mr_mip->c;
        mr_mip->c=mr_mip->r;
        mr_mip->r=mr_mip->b-mr_mip->q*mr_mip->d;
        mr_mip->b=mr_mip->d;
        mr_mip->d=mr_mip->r;
        lr=mr_mip->u-lq*mr_mip->v;
        mr_mip->u=mr_mip->v;
        mr_mip->v=lr;
        return mr_mip->q;
    }
    mr_mip->carryon=FALSE;
    if (mr_mip->b==0)
    { /* update w5 and w6 */
        mr_mip->check=OFF;
        divide(_MIPP_ mr_mip->w5,mr_mip->w6,mr_mip->w7);
        mr_mip->check=ON;
        if (mr_lent(mr_mip->w7)>mr_mip->nib) return (mr_mip->q=(-2));
        t=mr_mip->w5,mr_mip->w5=mr_mip->w6,mr_mip->w6=t;   /* swap(w5,w6) */
        copy(mr_mip->w7,x);
        return (mr_mip->q=size(x));
    }
    else
    {
        mr_mip->check=OFF;
        premult(_MIPP_ mr_mip->w5,mr_mip->c,mr_mip->w7);
        premult(_MIPP_ mr_mip->w5,mr_mip->a,mr_mip->w5);
        premult(_MIPP_ mr_mip->w6,mr_mip->b,mr_mip->w0);
        premult(_MIPP_ mr_mip->w6,mr_mip->d,mr_mip->w6);
        add(_MIPP_ mr_mip->w5,mr_mip->w0,mr_mip->w5);
        add(_MIPP_ mr_mip->w6,mr_mip->w7,mr_mip->w6);
        mr_mip->check=ON;
    }
    goto start;
}
예제 #2
0
int xgcd(_MIPD_ big x,big y,big xd,big yd,big z)
{   /* greatest common divisor by Euclids method  *
     * extended to also calculate xd and yd where *
     *      z = x.xd + y.yd = gcd(x,y)            *
     * if xd, yd not distinct, only xd calculated *
     * z only returned if distinct from xd and yd *
     * xd will always be positive, yd negative    */

    int s,n,iter;
    mr_small r,a,b,c,d;
    mr_small q,m,sr;
#ifdef MR_FP
    mr_small dres;
#endif

#ifdef mr_dltype
    mr_large u,v,lr;
#else
    mr_small u,v,lr;
#endif

    BOOL last,dplus=TRUE;
    big t;
#ifndef MR_GENERIC_MT
    miracl *mr_mip=get_mip();
#endif
    if (mr_mip->ERNUM) return 0;

    MR_IN(30)

    copy(x,mr_mip->w1);
    copy(y,mr_mip->w2);
    s=exsign(mr_mip->w1);
    insign(PLUS,mr_mip->w1);
    insign(PLUS,mr_mip->w2);
    convert(_MIPP_ 1,mr_mip->w3);
    zero(mr_mip->w4);
    last=FALSE;
    a=b=c=d=0;
    iter=0;

    while (size(mr_mip->w2)!=0)
    {
        if (b==0)
        {   /* update mr_mip->w1 and mr_mip->w2 */
            divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w5);
            t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t;    /* swap(mr_mip->w1,mr_mip->w2) */
            multiply(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w0);
            add(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3);
            t=mr_mip->w3,mr_mip->w3=mr_mip->w4,mr_mip->w4=t;    /* swap(xd,yd) */
            iter++;
        }
        else
        {

            /*  printf("a= %d b= %d c= %d  d= %d \n",a,b,c,d);   */

            mr_pmul(_MIPP_ mr_mip->w1,c,mr_mip->w5);   /* c*w1 */
            mr_pmul(_MIPP_ mr_mip->w1,a,mr_mip->w1);   /* a*w1 */
            mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w0);   /* b*w2 */
            mr_pmul(_MIPP_ mr_mip->w2,d,mr_mip->w2);   /* d*w2 */


            if (!dplus)
            {
                mr_psub(_MIPP_ mr_mip->w0,mr_mip->w1,mr_mip->w1); /* b*w2-a*w1 */
                mr_psub(_MIPP_ mr_mip->w5,mr_mip->w2,mr_mip->w2); /* c*w1-d*w2 */
            }
            else
            {
                mr_psub(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1); /* a*w1-b*w2 */
                mr_psub(_MIPP_ mr_mip->w2,mr_mip->w5,mr_mip->w2); /* d*w2-c*w1 */
            }
            mr_pmul(_MIPP_ mr_mip->w3,c,mr_mip->w5);
            mr_pmul(_MIPP_ mr_mip->w3,a,mr_mip->w3);
            mr_pmul(_MIPP_ mr_mip->w4,b,mr_mip->w0);
            mr_pmul(_MIPP_ mr_mip->w4,d,mr_mip->w4);

            if (a==0) copy(mr_mip->w0,mr_mip->w3);
            else      mr_padd(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3);
            mr_padd(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w4);
        }
        if (mr_mip->ERNUM || size(mr_mip->w2)==0) break;


        n=(int)mr_mip->w1->len;
        if (n==1)
        {
            last=TRUE;
            u=mr_mip->w1->w[0];
            v=mr_mip->w2->w[0];
        }
        else
        {
            m=mr_mip->w1->w[n-1]+1;
            if (mr_mip->base==0)
            {
#ifndef MR_NOFULLWIDTH
#ifdef mr_dltype
                /* use double length type if available */
                if (n>2 && m!=0)
                {   /* squeeze out as much significance as possible */
                    MR_TOP(u)=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr);
                    MR_BOT(u)=muldvm(sr,mr_mip->w1->w[n-3],m,&sr);
                    MR_TOP(v)=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr);
                    MR_BOT(v)=muldvm(sr,mr_mip->w2->w[n-3],m,&sr);
                }
                else
                {
                    MR_TOP(u)=mr_mip->w1->w[n-1];
                    MR_BOT(u)=mr_mip->w1->w[n-2];
                    MR_TOP(v)=mr_mip->w2->w[n-1];
                    MR_BOT(v)=mr_mip->w2->w[n-2];
                    if (n==2) last=TRUE;
                }
#else
                if (m==0)
                {
                    u=mr_mip->w1->w[n-1];
                    v=mr_mip->w2->w[n-1];
                }
                else
                {
                    u=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr);
                    v=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr);
                }
#endif
#endif
            }
            else
            {
#ifdef mr_dltype
                if (n>2)
                {   /* squeeze out as much significance as possible */
                    u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr);
                    u=u*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w1->w[n-3],m,&sr);
                    v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr);
                    v=v*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w2->w[n-3],m,&sr);
                }
                else
                {
                    u=(mr_large)mr_mip->base*mr_mip->w1->w[n-1]+mr_mip->w1->w[n-2];
                    v=(mr_large)mr_mip->base*mr_mip->w2->w[n-1]+mr_mip->w2->w[n-2];
                    last=TRUE;
                }
#else
                u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr);
                v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr);
#endif
            }
        }

        dplus=TRUE;
        a=1;
        b=0;
        c=0;
        d=1;

        forever
        {   /* work only with most significant piece */
            if (last)
            {
                if (v==0) break;
                q=qdiv(u,v);
                if (q==0) break;
            }
            else
            {
                if (dplus)
                {
                    if (v-c==0 || v+d==0) break;
                    q=qdiv(u+a,v-c);
                    if (q==0) break;
                    if (q!=qdiv(u-b,v+d)) break;
                }
                else
                {
                    if (v+c==0 || v-d==0) break;
                    q=qdiv(u-a,v+c);
                    if (q==0) break;
                    if (q!=qdiv(u+b,v-d)) break;
                }
            }

            if (q==1)
            {
                if (b+d >= MAXBASE) break;
                r=a+c;
                a=c;
                c=r;
                r=b+d;
                b=d;
                d=r;
                lr=u-v;
                u=v;
                v=lr;
            }
            else
            {
                if (q>=MR_DIV(MAXBASE-b,d)) break;
                r=a+q*c;
                a=c;
                c=r;
                r=b+q*d;
                b=d;
                d=r;
                lr=u-q*v;
                u=v;
                v=lr;
            }
            iter++;
            dplus=!dplus;
        }
        iter%=2;
    }

    if (s==MINUS) iter++;
    if (iter%2==1) subtract(_MIPP_ y,mr_mip->w3,mr_mip->w3);

    if (xd!=yd)
    {
        negify(x,mr_mip->w2);
        mad(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w1,y,mr_mip->w4,mr_mip->w4);
        copy(mr_mip->w4,yd);
    }
    copy(mr_mip->w3,xd);
    if (z!=xd && z!=yd) copy(mr_mip->w1,z);

    MR_OUT
    return (size(mr_mip->w1));
}
예제 #3
0
파일: mrgcd.c 프로젝트: FlexCOS/code
int egcd(_MIPD_ big x,big y,big z)
{ /* greatest common divisor z=gcd(x,y) by Euclids  *
   * method using Lehmers algorithm for big numbers */
    int q,r,a,b,c,d,n;
    mr_small sr,m,sm;
    mr_small u,v,lq,lr;
#ifdef MR_FP
    mr_small dres;
#endif
    big t;
#ifdef MR_OS_THREADS
    miracl *mr_mip=get_mip();
#endif
    if (mr_mip->ERNUM) return 0;

    MR_IN(12)

    copy(x,mr_mip->w1);
    copy(y,mr_mip->w2);
    insign(PLUS,mr_mip->w1);
    insign(PLUS,mr_mip->w2);
    a=b=c=d=0;
    while (size(mr_mip->w2)!=0)
    {
	 /*	printf("a= %d b= %d c= %d d=%d\n",a,b,c,d); */
        if (b==0)
        { /* update w1 and w2 */
            divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w2);
            t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t;   /* swap(w1,w2) */
        }
        else
        {
            premult(_MIPP_ mr_mip->w1,c,z);
            premult(_MIPP_ mr_mip->w1,a,mr_mip->w1);
            premult(_MIPP_ mr_mip->w2,b,mr_mip->w0);
            premult(_MIPP_ mr_mip->w2,d,mr_mip->w2);
            add(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1);
            add(_MIPP_ mr_mip->w2,z,mr_mip->w2);
        }
        if (mr_mip->ERNUM || size(mr_mip->w2)==0) break;
        n=(int)mr_mip->w1->len;
        if (mr_mip->w2->len==1)
        { /* special case if mr_mip->w2 is now small */
            sm=mr_mip->w2->w[0];    
#ifdef MR_FP_ROUNDING
            sr=mr_sdiv(_MIPP_ mr_mip->w1,sm,mr_invert(sm),mr_mip->w1);
#else
            sr=mr_sdiv(_MIPP_ mr_mip->w1,sm,mr_mip->w1);
#endif
            if (sr==0)
            {
                copy(mr_mip->w2,mr_mip->w1);
                break;
            }
            zero(mr_mip->w1);
            mr_mip->w1->len=1;
            mr_mip->w1->w[0]=sr;
            while ((sr=MR_REMAIN(mr_mip->w2->w[0],mr_mip->w1->w[0]))!=0)
                  mr_mip->w2->w[0]=mr_mip->w1->w[0],mr_mip->w1->w[0]=sr;
            break;
        }
        a=1;
        b=0;
        c=0;
        d=1;
        m=mr_mip->w1->w[n-1]+1;
    /*    printf("m= %d\n",m); */
#ifndef MR_SIMPLE_BASE
        if (mr_mip->base==0)
        {
#endif
#ifndef MR_NOFULLWIDTH
            if (m==0)
            {
                u=mr_mip->w1->w[n-1];
                v=mr_mip->w2->w[n-1];
            }
            else
            {
			/*		printf("w1[n-1]= %d w1[n-2]= %d\n", mr_mip->w1->w[n-1],mr_mip->w1->w[n-2]);
					printf("w2[n-1]= %d w2[n-2]= %d\n", mr_mip->w2->w[n-1],mr_mip->w2->w[n-2]);*/
                u=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr);
                v=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr);
            }
#endif
#ifndef MR_SIMPLE_BASE
        }
        else
        {
            u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr);
            v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr);
        }
#endif
     /*   printf("u= %d v= %d\n",u,v);*/

        forever
        { /* work only with most significant piece */
            if (((v+c)==0) || ((v+d)==0)) break;
            lq=MR_DIV((u+a),(v+c));
            if (lq!=MR_DIV((u+b),(v+d))) break;
            if (lq>=(mr_small)(MR_TOOBIG/mr_abs(d))) break;
            q=(int)lq;
            r=a-q*c;
            a=c;
            c=r;
            r=b-q*d;
            b=d;
            d=r;
            lr=u-lq*v;
            u=v;
            v=lr;
        }
    }
    copy(mr_mip->w1,z);
    MR_OUT
    return (size(mr_mip->w1));
}
예제 #4
0
void build(_MIPD_ flash x,int (*gen)(_MIPT_ big,int))
{ /* Build x from its regular c.f. *
   * generated by gen()            */
    mr_small ex1,ex2,ex,st,sr;
    int a,b,c,d,rm,q,n,prc,lw2,lw4,lz;
    BOOL finoff,last;
    big t;
#ifdef MR_OS_THREADS
    miracl *mr_mip=get_mip();
#endif
    if (mr_mip->ERNUM) return;

    MR_IN(48)

    zero(mr_mip->w1);
    convert(_MIPP_ 1,mr_mip->w2);
    convert(_MIPP_ 1,mr_mip->w3);
    zero(mr_mip->w4);
    finoff=FALSE;
    last=FALSE;
    n=0;
    q=(*gen)(_MIPP_ x,n);   /* Note - first quotient may be zero */
    ex=mr_mip->base-1;
    if (mr_mip->nib==mr_mip->workprec) prc=mr_mip->nib;
    else prc=mr_mip->workprec+1;
    while (!mr_mip->ERNUM && q>=0)
    {
        if (q==MR_TOOBIG || n==0 || finoff)
        {
            if (q!=MR_TOOBIG) convert(_MIPP_ q,x);
            else last=FALSE;
            mr_mip->check=OFF;
            multiply(_MIPP_ mr_mip->w2,x,mr_mip->w0);
            subtract(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w7);
            mr_mip->check=ON;
            if ((int)(mr_mip->w7->len&MR_OBITS)>mr_mip->nib) break;
            copy(mr_mip->w7,mr_mip->w1);
            t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t;   /* swap(w1,w2) */
            mr_mip->check=OFF;
            multiply(_MIPP_ mr_mip->w4,x,mr_mip->w0);
            subtract(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w7);
            mr_mip->check=ON;
            if ((int)(mr_mip->w7->len&MR_OBITS)>mr_mip->nib)
            { /* oops! */
                fpack(_MIPP_ mr_mip->w1,mr_mip->w4,x);
                negify(x,x);
                mr_mip->EXACT=FALSE;
                MR_OUT
                return;
            }
            copy(mr_mip->w7,mr_mip->w3);
            t=mr_mip->w3,mr_mip->w3=mr_mip->w4,mr_mip->w4=t;   /* swap(w3,w4) */
            n++;
        }
        lw2=(int)(mr_mip->w2->len&MR_OBITS);
        lw4=(int)(mr_mip->w4->len&MR_OBITS);
        lz=lw2+lw4;
        if (lz > prc) break;  /* too big - exit */
        if (last)
        {
            if (finoff) break;
            finoff=TRUE;
            q=(*gen)(_MIPP_ x,n);
            continue;
        }
        if (lz>=prc-1)
        { /* nearly finished - so be careful not to overshoot */
            if (mr_mip->base==0)
            {
#ifndef MR_NOFULLWIDTH
                st=mr_mip->w2->w[lw2-1]+1;
                if (st==0) ex1=1;
                else ex1=muldvm((mr_small)1,(mr_small)0,st,&sr);
                st=mr_mip->w4->w[lw4-1]+1;
                if (st==0) ex2=1;
                else ex2=muldvm((mr_small)1,(mr_small)0,st,&sr);
#endif
            }
            else
            {
                ex1=mr_mip->base/(mr_mip->w2->w[lw2-1]+1);
                ex2=mr_mip->base/(mr_mip->w4->w[lw4-1]+1);
            }
            if (ex2>ex1) ex=ex1,ex1=ex2,ex2=ex;
            if (lz==prc) ex=ex2;
            else         ex=ex1;
            last=TRUE;
        }
        a=1;
        b=0;
        c=0;
        d=1;
        forever
        {
            q=(*gen)(_MIPP_ x,n);          
            if (q<0 || q>=MR_TOOBIG/mr_abs(d))
            { /* there could be more.... *** V3.21 mod *** */
                last=FALSE;
                break;
            }
            rm=b-q*d;
            b=d;
            d=rm;
            rm=a-q*c;
            a=c;
            c=rm;
            n++;
            if ((mr_small)(mr_abs(c-d))>ex) break;
        }
        premult(_MIPP_ mr_mip->w1,c,mr_mip->w7);
        premult(_MIPP_ mr_mip->w1,a,mr_mip->w1);
        premult(_MIPP_ mr_mip->w2,b,mr_mip->w0);
        premult(_MIPP_ mr_mip->w2,d,mr_mip->w2);
        add(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1);
        add(_MIPP_ mr_mip->w2,mr_mip->w7,mr_mip->w2);
        premult(_MIPP_ mr_mip->w3,c,mr_mip->w7);
        premult(_MIPP_ mr_mip->w3,a,mr_mip->w3);
        premult(_MIPP_ mr_mip->w4,b,mr_mip->w0);
        premult(_MIPP_ mr_mip->w4,d,mr_mip->w4);
        add(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3);
        add(_MIPP_ mr_mip->w4,mr_mip->w7,mr_mip->w4);
    }
예제 #5
0
int xgcd(_MIPD_ big x,big y,big xd,big yd,big z)
{ /* greatest common divisor by Euclids method  *
   * extended to also calculate xd and yd where *
   *      z = x.xd + y.yd = gcd(x,y)            *
   * if xd, yd not distinct, only xd calculated *
   * z only returned if distinct from xd and yd *
   * xd will always be positive, yd negative    */
    int q,r,a,b,c,d,s,n;
    mr_small m,sr;
#ifdef mr_dltype
    mr_large u,v,lq,lr;
#else
    mr_small u,v,lq,lr;
#endif

    BOOL last;
    big t;
#ifndef MR_GENERIC_MT
    miracl *mr_mip=get_mip();
#endif
    if (mr_mip->ERNUM) return 0;

    MR_IN(30)

    copy(x,mr_mip->w1);
    copy(y,mr_mip->w2);
    s=exsign(mr_mip->w1);
    insign(PLUS,mr_mip->w1);
    insign(PLUS,mr_mip->w2);
/*    copy(mr_mip->w1,mr_mip->w3);
    copy(mr_mip->w2,mr_mip->w4);  */
    convert(_MIPP_ 1,mr_mip->w3);
    zero(mr_mip->w4);
    last=FALSE;
    a=b=c=d=0;
    while (size(mr_mip->w2)!=0)
    {
        if (b==0)
        { /* update mr_mip->w1 and mr_mip->w2 */
            divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w5);
            t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t;    /* swap(mr_mip->w1,mr_mip->w2) */
            multiply(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w0);
            subtract(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3);
            t=mr_mip->w3,mr_mip->w3=mr_mip->w4,mr_mip->w4=t;    /* swap(xd,yd) */
        }
        else
        {
            premult(_MIPP_ mr_mip->w1,c,mr_mip->w5);
            premult(_MIPP_ mr_mip->w1,a,mr_mip->w1);
            premult(_MIPP_ mr_mip->w2,b,mr_mip->w0);
            premult(_MIPP_ mr_mip->w2,d,mr_mip->w2);
            add_r(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1);
            add_r(_MIPP_ mr_mip->w2,mr_mip->w5,mr_mip->w2);
            premult(_MIPP_ mr_mip->w3,c,mr_mip->w5);
            premult(_MIPP_ mr_mip->w3,a,mr_mip->w3);
            premult(_MIPP_ mr_mip->w4,b,mr_mip->w0);
            premult(_MIPP_ mr_mip->w4,d,mr_mip->w4);
            add_r(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3);
            add_r(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w4);
        }
        if (mr_mip->ERNUM || size(mr_mip->w2)==0) break;
        n=(int)mr_mip->w1[0];
        a=1;
        b=0;
        c=0;
        d=1;
        if (n==1)
        {
            last=TRUE;
            u=mr_mip->w1[1];
            v=mr_mip->w2[1];
        }
        else
        {
            m=mr_mip->w1[n]+1;
            if (mr_mip->base==0)
            {
#ifdef mr_dltype
 /* use double length type if available */
                if (n>2 && m!=0)
                { /* squeeze out as much significance as possible */
                    MR_TOP(u)=muldvm(mr_mip->w1[n],mr_mip->w1[n-1],m,&sr);
                    MR_BOT(u)=muldvm(sr,mr_mip->w1[n-2],m,&sr);
                    MR_TOP(v)=muldvm(mr_mip->w2[n],mr_mip->w2[n-1],m,&sr);
                    MR_BOT(v)=muldvm(sr,mr_mip->w2[n-2],m,&sr);
                }
                else
                {
                    MR_TOP(u)=mr_mip->w1[n];
                    MR_BOT(u)=mr_mip->w1[n-1];
                    MR_TOP(v)=mr_mip->w2[n];
                    MR_BOT(v)=mr_mip->w2[n-1];
                    if (n==2) last=TRUE;
                }
#else
                if (m==0)
                {
                    u=mr_mip->w1[n];
                    v=mr_mip->w2[n];
                }
                else
                {
                    u=muldvm(mr_mip->w1[n],mr_mip->w1[n-1],m,&sr);
                    v=muldvm(mr_mip->w2[n],mr_mip->w2[n-1],m,&sr);
                }
#endif
            }
            else
            {
#ifdef mr_dltype
 /* use double length type if available */
                if (n>2)
                { /* squeeze out as much significance as possible */
                    u=muldiv(mr_mip->w1[n],mr_mip->base,mr_mip->w1[n-1],m,&sr);
                    u=u*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w1[n-2],m,&sr);
                    v=muldiv(mr_mip->w2[n],mr_mip->base,mr_mip->w2[n-1],m,&sr);
                    v=v*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w2[n-2],m,&sr);
                }
                else
                {
                    u=(mr_large)mr_mip->base*mr_mip->w1[n]+mr_mip->w1[n-1];
                    v=(mr_large)mr_mip->base*mr_mip->w2[n]+mr_mip->w2[n-1];
                    last=TRUE;
                }
#else
                u=muldiv(mr_mip->w1[n],mr_mip->base,mr_mip->w1[n-1],m,&sr);
                v=muldiv(mr_mip->w2[n],mr_mip->base,mr_mip->w2[n-1],m,&sr);
#endif
            }
        }
        forever
        { /* work only with most significant piece */
            if (last)
            {
                if (v==0) break;
                lq=u/v;
            }
            else
            {
                if (((v+c)==0) || ((v+d)==0)) break;
                lq=(u+a)/(v+c);
                if (lq!=(u+b)/(v+d)) break;
            }
#ifdef mr_dltype
            if (lq>=(mr_large)(MR_TOOBIG/abs(d))) break;
#else
            if (lq>=(mr_small)(MR_TOOBIG/abs(d))) break;
#endif
            q=(int)lq;
            r=a-q*c;
            a=c;
            c=r;
            r=b-q*d;
            b=d;
            d=r;
            lr=u-lq*v;
            u=v;
            v=lr;
        }
    }
    if (s==MINUS) negate(mr_mip->w3,mr_mip->w3);
    if (size(mr_mip->w3)<=0) add_r(_MIPP_ mr_mip->w3,y,mr_mip->w3);
    if (xd!=yd)
    {
        negate(x,mr_mip->w2);
        mad(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w1,y,mr_mip->w4,mr_mip->w4);
        copy(mr_mip->w4,yd);
    }
    copy(mr_mip->w3,xd);
    if (z!=xd && z!=yd) copy(mr_mip->w1,z);
    MR_OUT
    return (size(mr_mip->w1));
}