📄 mrarth0.c
字号:
/*
* MIRACL arithmetic routines 0 - Add and subtract routines
* mrarth0.c
*
* Copyright (c) 1988-1995 Shamus Software Ltd.
*/
#include "miracl.h"
void mr_padd(_MIPD_ big x,big y,big z)
{ /* add two big numbers, z=x+y where *
* x and y are positive */
int lx,ly,lz,la,i;
mr_small carry,psum;
mr_small *gx,*gy,*gz;
#ifdef MR_OS_THREADS
miracl *mr_mip=get_mip();
#endif
lx = (int)x->len;
ly = (int)y->len;
if (ly>lx)
{
lz=ly;
la=lx;
if (x!=z) copy(y,z);
else la=ly;
}
else
{
lz=lx;
la=ly;
if (y!=z) copy(x,z);
else la=lx;
}
carry=0;
z->len=lz;
gx=x->w; gy=y->w; gz=z->w;
if (lz<mr_mip->nib || !mr_mip->check) z->len++;
if (mr_mip->base==0)
{
for (i=0;i<la;i++)
{ /* add by columns to length of the smaller number */
psum=gx[i]+gy[i]+carry;
if (psum>gx[i]) carry=0;
else if (psum<gx[i]) carry=1;
gz[i]=psum;
}
for (;i<lz && carry>0;i++ )
{ /* add by columns to the length of larger number (if there is a carry) */
psum=gx[i]+gy[i]+carry;
if (psum>gx[i]) carry=0;
else if (psum<gx[i]) carry=1;
gz[i]=psum;
}
if (carry)
{ /* carry left over - possible overflow */
if (mr_mip->check && i>=mr_mip->nib)
{
mr_berror(_MIPP_ MR_ERR_OVERFLOW);
return;
}
gz[i]=carry;
}
}
else
{
for (i=0;i<la;i++)
{ /* add by columns */
psum=gx[i]+gy[i]+carry;
carry=0;
if (psum>=mr_mip->base)
{ /* set carry */
carry=1;
psum-=mr_mip->base;
}
gz[i]=psum;
}
for (;i<lz && carry>0;i++)
{
psum=gx[i]+gy[i]+carry;
carry=0;
if (psum>=mr_mip->base)
{ /* set carry */
carry=1;
psum-=mr_mip->base;
}
gz[i]=psum;
}
if (carry)
{ /* carry left over - possible overflow */
if (mr_mip->check && i>=mr_mip->nib)
{
mr_berror(_MIPP_ MR_ERR_OVERFLOW);
return;
}
gz[i]=carry;
}
}
if (gz[z->len-1]==0) z->len--;
}
void mr_psub(_MIPD_ big x,big y,big z)
{ /* subtract two big numbers z=x-y *
* where x and y are positive and x>y */
int lx,ly,i;
mr_small borrow,pdiff;
mr_small *gx,*gy,*gz;
#ifdef MR_OS_THREADS
miracl *mr_mip=get_mip();
#endif
lx = (int)x->len;
ly = (int)y->len;
if (ly>lx)
{
mr_berror(_MIPP_ MR_ERR_NEG_RESULT);
return;
}
if (y!=z) copy(x,z);
else ly=lx;
z->len=lx;
gx=x->w; gy=y->w; gz=z->w;
borrow=0;
if (mr_mip->base==0) for (i=0;i<ly || borrow>0;i++)
{ /* subtract by columns */
if (i>lx)
{
mr_berror(_MIPP_ MR_ERR_NEG_RESULT);
return;
}
pdiff=gx[i]-gy[i]-borrow;
if (pdiff<gx[i]) borrow=0;
else if (pdiff>gx[i]) borrow=1;
gz[i]=pdiff;
}
else for (i=0;i<ly || borrow>0;i++)
{ /* subtract by columns */
if (i>lx)
{
mr_berror(_MIPP_ MR_ERR_NEG_RESULT);
return;
}
pdiff=gy[i]+borrow;
borrow=0;
if (gx[i]>=pdiff) pdiff=gx[i]-pdiff;
else
{ /* set borrow */
pdiff=mr_mip->base+gx[i]-pdiff;
borrow=1;
}
gz[i]=pdiff;
}
mr_lzero(z);
}
static void mr_select(_MIPD_ big x,int d,big y,big z)
{ /* perform required add or subtract operation */
int sx,sy,sz,jf,xgty;
#ifdef MR_FLASH
if (mr_notint(x) || mr_notint(y))
{
mr_berror(_MIPP_ MR_ERR_INT_OP);
return;
}
#endif
sx=exsign(x);
sy=exsign(y);
x->len&=MR_OBITS; /* force operands to be positive */
y->len&=MR_OBITS;
xgty=compare(x,y);
jf=(1+sx)+(1+d*sy)/2;
switch (jf)
{ /* branch according to signs of operands */
case 0:
if (xgty>=0)
mr_padd(_MIPP_ x,y,z);
else
mr_padd(_MIPP_ y,x,z);
sz=MINUS;
break;
case 1:
if (xgty<=0)
{
mr_psub(_MIPP_ y,x,z);
sz=PLUS;
}
else
{
mr_psub(_MIPP_ x,y,z);
sz=MINUS;
}
break;
case 2:
if (xgty>=0)
{
mr_psub(_MIPP_ x,y,z);
sz=PLUS;
}
else
{
mr_psub(_MIPP_ y,x,z);
sz=MINUS;
}
break;
case 3:
if (xgty>=0)
mr_padd(_MIPP_ x,y,z);
else
mr_padd(_MIPP_ y,x,z);
sz=PLUS;
break;
}
if (sz<0) z->len^=MR_MSBIT; /* set sign of result */
if (x!=z && sx<0) x->len^=MR_MSBIT; /* restore signs to operands */
if (y!=z && y!=x && sy<0) y->len^=MR_MSBIT;
}
void add(_MIPD_ big x,big y,big z)
{ /* add two signed big numbers together z=x+y */
#ifdef MR_OS_THREADS
miracl *mr_mip=get_mip();
#endif
if (mr_mip->ERNUM) return;
MR_IN(27)
mr_select(_MIPP_ x,PLUS,y,z);
MR_OUT
}
void subtract(_MIPD_ big x,big y,big z)
{ /* subtract two big signed numbers z=x-y */
#ifdef MR_OS_THREADS
miracl *mr_mip=get_mip();
#endif
if (mr_mip->ERNUM) return;
MR_IN(28)
mr_select(_MIPP_ x,MINUS,y,z);
MR_OUT
}
void incr(_MIPD_ big x,int n,big z)
{ /* add int to big number: z=x+n */
#ifdef MR_OS_THREADS
miracl *mr_mip=get_mip();
#endif
if (mr_mip->ERNUM) return;
MR_IN(7)
convert(_MIPP_ n,mr_mip->w0);
mr_select(_MIPP_ x,PLUS,mr_mip->w0,z);
MR_OUT
}
void decr(_MIPD_ big x,int n,big z)
{ /* subtract int from big number: z=x-n */
#ifdef MR_OS_THREADS
miracl *mr_mip=get_mip();
#endif
if (mr_mip->ERNUM) return;
MR_IN(8)
convert(_MIPP_ n,mr_mip->w0);
mr_select(_MIPP_ x,MINUS,mr_mip->w0,z);
MR_OUT
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -