📄 lmul.c
字号:
/*
* Module: lmul.c
* Modified by: X.C.Zheng WeiHua
* Modified on: Date: 03-8-11 14:02
* Copyright(c) WeiHua Tech Ltd.
*/
#include "ecrsys.h"
#include "sysdata.h"
#include "data.h"
#include "ftype.h"
#include "mathes.h"
#include "stdlib.h"
#include "string.h"
/*
* Get a long value which is based on 10 for given input
*/
dword getLong(BYTE cnt)
{
BYTE i;
dword lltmp = 1L;
if(cnt==0)
return(1L);
for (i = 0; i < cnt; i++)
lltmp *= 10;
return(lltmp);
}
/* llx * lly -> llx */
/* return : NOTOK: Overflow, OK: normal */
byte DL_Mul(DoubleLong *llx, long lly, BYTE dots)
{
BYTE i;
BYTE sign;
word op[8] = {0, 0, 0, 0, 0, 0, 0, 0};
word *ip;
dword *lltmp, lm1, lm2;
dword dltmp;
if(lly == MIN_SIGNED_LONG)
{
/* Remain */
}
if(lly == 0) /* The result is 0 */
{
DL_Clr(llx);
return (OK);
}
else if(lly < 0)
{
lly = -lly;
sign = NEGATIVE;
}
else
sign = POSITIVE;
ip = (word *)llx;
for (i = 0; i < 4; i++)
{
lltmp = (dword *)&op[i];
lm1 = ((dword)ip[i]) & 0x0000FFFF;
lm2 = lly & 0x0000FFFF;
dltmp = lm1 * lm2 + (*lltmp);
if((*lltmp) > dltmp) /* When overflow, the next second cell add one */
op[i+2] ++;
*lltmp = dltmp;
lltmp = (dword *)&op[i+1];
lm2 = (lly >> 16) & 0x0000FFFF;
dltmp = lm1 * lm2 + (*lltmp);
if((*lltmp) > dltmp) /* When overflow, the next second cell add one */
op[i+3] ++;
*lltmp = dltmp;
}
lltmp = (dword *)&op[0];
llx->lowlong = *lltmp;
lltmp = (dword *)&op[2];
llx->highlong = *lltmp;
llx->dots += dots;
if(llx->sign==sign)
llx->sign=POSITIVE;
else
llx->sign=NEGATIVE;
lltmp = (dword *)&op[4];
if((*lltmp) != 0) /* This case only occur in the calculation mode,
indicate the result is too big.
When this case occur, adjust it to the right format */
{
if(DL_Mul_Adj(llx,(*lltmp)) == NG)
return (NOTOK);
}
return (OK);
}
/* llx / lly -> llx */
/* if flag == 0, do not adujst it */
/* sysdots: decimal position */
byte DL_Div(DoubleLong *llx, long lly, BYTE dots, BYTE flag, BYTE sysdots)
{
byte i,j;
BYTE sign;
dword ltmp1;
dword ltmp2;
dword ltmp3;
ltmp1 = 0L;
if(lly == MIN_SIGNED_LONG)
{
/* Remain */
}
if(lly == 0)
return (NOTOK);
else if(lly < 0)
{
lly=-lly;
sign=NEGATIVE;
}
else
sign=POSITIVE;
if(flag)
{
if((llx->dots - dots < sysdots+1 )||(llx->dots<dots))
{
if(DL_Mul(llx, getLong(sysdots + 1 - llx->dots + dots),0) == NOTOK)
return (NOTOK);
llx->dots += sysdots + 1 - llx->dots + dots;
}
}
else
{
if(llx->dots < dots)
if(DL_Mul(llx, getLong(dots - llx->dots), dots - llx->dots) == NOTOK)
return (NOTOK);
}
for(i = 0; i < 64; i++)
{
ltmp2 = 0L;
if(llx->lowlong & 0x80000000) ltmp2 = 1L;
llx->lowlong <<= 1;
lD1:
ltmp3 = 0L;
if(llx->highlong & 0x80000000)
ltmp3 = 1L;
llx->highlong <<= 1;
llx->highlong += ltmp2;
lD3:
ltmp1 <<= 1;
ltmp1 += ltmp3;
if (ltmp1 >= lly)
{
ltmp1 -= lly;
llx->lowlong += 1L;
}
}/* end for */
llx->dots -= dots;
if(llx->sign==sign)
llx->sign=POSITIVE;
else
llx->sign=NEGATIVE;
return (OK);
}
/* Translate Double long interger to long interger */
long DL2L(DoubleLong *dl, BYTE dots, BYTE round)
{
dword dltmp;
DoubleLong ll;
ll.highlong= dl->highlong ;
ll.lowlong=dl->lowlong ;
ll.dots=dl->dots ;
while((ll.dots<dots+1))
{
DL_Mul(&ll, 10, 0);
ll.dots++;
}
while((ll.dots>dots+1))
{
DL_Div(&ll, 10, 0, 0,sysflag->sysdots);
ll.dots--;
}
if(round==0) /** round==0 **/
dltmp=5;
else if(round==2) /** round off==2 **/
dltmp=0;
else if(round==1) /** round up==1 **/
dltmp=9;
else
return -1L;
dltmp = dltmp + ll.lowlong;
if(ll.lowlong>dltmp)
ll.highlong++;
ll.lowlong = dltmp;
DL_Div(&ll,10,0, 0, sysflag->sysdots);
ll.dots--;
dl->highlong = ll.highlong ;
dl->lowlong = ll.lowlong ;
dl->dots = ll.dots ;
if ((ll.highlong != 0 )|| (ll.lowlong&0x80000000))
/* overflow occurs */
return(-1L);
/* if(ll.sign==NEGATIVE)
return(-ll.lowlong);
else*/
return(ll.lowlong);
}
/* Translate long interger to double long interger */
void L2DL(long l, DoubleLong *ll, BYTE dots)
{
if(l == MIN_SIGNED_LONG)
{
ll->highlong = 1;
ll->lowlong = 0;
ll->dots = dots;
ll->sign = NEGATIVE;
return;
}
ll->highlong = 0L;
if(l<0)
{
ll->lowlong = (-1)*l;
ll->sign=NEGATIVE;
}
else
{
ll->lowlong = l;
ll->sign = POSITIVE;
}
ll->dots = dots;
}
/* llx(signed) + lly(signed) -> llx(signed) */
/* return: NOTOK: the result has overflow, OK: normal */
byte DL_Add(DoubleLong *llx, long lly, BYTE dots)
{
DoubleLong ll;
if(lly == MIN_SIGNED_LONG)
{
/* Remain */
}
L2DL(lly,&ll,dots); /* Adjust it to the double long */
if(DL_Add2(llx, ll) == NOTOK)
return (NOTOK);
return (OK);
}
/* llx(signed) + lly(signed) -> llx(signed) */
/* return: NOTOK: the result has overflow, OK: normal */
byte DL_Add2(DoubleLong *llx, DoubleLong ll)
{
dword dltmp;
DL_Add_Adj(llx, &ll); /* Adjust to the same dots */
if(llx->sign == ll.sign) /* The same sign */
{
dltmp = llx->lowlong + ll.lowlong;
if(ll.lowlong > dltmp) /* Carry */
{
if(llx->highlong == 0xFFFFFFFF)
return (NOTOK); /* Overflow */
else
ll.highlong ++;
}
llx->lowlong = dltmp;
dltmp = llx->highlong + ll.highlong;
if(ll.highlong > dltmp)
return (NOTOK); /* Overflow */
llx->highlong = dltmp;
}
else /* The different sign */
{
dltmp = llx->lowlong - ll.lowlong;
if(llx->lowlong < dltmp) /* Borrow */
{
if(llx->highlong == 0)
{
llx->sign = (llx->sign == POSITIVE)?NEGATIVE:POSITIVE; /* Reverse the sign */
llx->highlong = 0xFFFFFFFF;
}
else
llx->highlong --;
}
llx->lowlong = dltmp;
dltmp = llx->highlong - ll.highlong;
if(llx->highlong < dltmp) /* Borrow */
llx->sign = (llx->sign == POSITIVE)?NEGATIVE:POSITIVE; /* Reverse the sign */
llx->highlong = dltmp;
if(llx->sign == ll.sign) /* When the sign is changed, adjust to the right format */
{
llx->highlong ^= 0xFFFFFFFF;
llx->lowlong ^= 0xFFFFFFFF;
DL_Add(llx, (llx->sign == POSITIVE)?1:-1, llx->dots);
}
}
if((llx->highlong == 0) && (llx->lowlong == 0))
{
// llx->dots = 0; /* Can't clear the dots, for the function DL_Exact_Div must remain the dots */
llx->sign = POSITIVE;
}
return (OK);
}
/* llx <- lly */
void DL_Eva(DoubleLong *llx, DoubleLong *lly)
{
llx->lowlong = lly->lowlong;
llx->highlong = lly->highlong;
llx->dots = lly->dots;
llx->sign = lly->sign;
}
/* Adjust the too big data
The adjust expressions:
primal_data = highdata*2^64 + highlong|lowlong;
divisor = 10^(length(highdata)); // also can larger than it.
adjust_data = primal_data / divisor;(Contain dots)
= (highdata*2^64 + highlong|lowlong)/divisor;
= (highlong|lowlong)/divisor + (highdata*2^64)/divisor; // may be smaller than the formar expressions, but can ignore
= (highlong|lowlong)/divisor + highdata*(2^64)/divisor;
--------------
|___________________ new_data
new_data = highdata*(0x10000000000000000/divisor + 0x10000000000000000%divisor/divisor);
--------------------------- ---------------------------
| |_________________residue;
|__________________________________________________quotient;
quotient = 0x10000000000000000/divisor;
= 0xFFFFFFFFFFFFFFFF/divisor;
residue = 0x10000000000000000 - quotient*divisor;
= 0xFFFFFFFFFFFFFFFF - quotient*divisor + 1;
= 0xFFFFFFFF - (quotient*divisor).lowlong + 1;((quotieng*divisor).highlong = 0xFFFFFFFF)
adjust_data = (highlong|lowlong)/divisor + highdata*quotient + highdata*residue/divisor;
*/
byte DL_Mul_Adj(DoubleLong *ll, dword highdata)
{
BYTE i;
dword tmp;
dword divisor;
dword residue;
dword dltmp;
DoubleLong dl;
tmp = highdata; /* Get this data */
for(i = 0; tmp != 0; i ++) /* Get this datas length */
tmp /= 10;
if(ll->dots < i)
return (NG);
divisor = getLong(i); /* Get the divisor */
dl.lowlong = 0xFFFFFFFF;
dl.highlong = 0xFFFFFFFF;
dl.sign = POSITIVE;
dl.dots = 0;
DL_Div(&dl, divisor, 0, 0, 0); /* Get the quotient */
DL_Mul(&dl, highdata, i);
DL_Div(ll, divisor, i, 0, 0);
dltmp = ll->lowlong + dl.lowlong;
if(ll->lowlong > dltmp)
ll->highlong ++;
ll->lowlong = dltmp;
ll->highlong += dl.highlong;
dl.lowlong = 0xFFFFFFFF;
dl.highlong = 0xFFFFFFFF;
dl.sign = POSITIVE;
dl.dots = 0;
DL_Div(&dl, divisor, 0, 0, 0);
DL_Mul(&dl,divisor, 0);
residue = 0xFFFFFFFF - dl.lowlong + 1; /* Get the residue */
L2DL(residue, &dl, 0);
DL_Mul(&dl, highdata, 0);
DL_Div(&dl, divisor, 0, 0, 0);
dltmp = ll->lowlong + dl.lowlong;
if(ll->lowlong > dltmp)
ll->highlong ++;
ll->lowlong = dltmp;
ll->highlong += dl.highlong;
return (OK);
}
void DL_Clr(DoubleLong *ll)
{
ll->highlong = 0;
ll->lowlong = 0;
ll->dots = 0;
ll->sign = POSITIVE;
}
/* llx / lly -> llx, used for the exact result */
byte DL_Exact_Div(DoubleLong *llx, long lly, BYTE dots)
{
byte sign1, sign2; /* Store the sign of the llx and lly */
DoubleLong dl,dl1;
long residue;
long quotient;
long divisor;
if(llx->dots < dots)
{
if(DL_Mul(llx, getLong(dots), 0) == NOTOK)
return (NOTOK);
dots = 0;
}
sign1 = llx->sign;
llx->sign = POSITIVE;
if(lly > 0)
sign2 = POSITIVE;
else
sign2 = NEGATIVE;
lly = labs(lly);
DL_Eva(&dl, llx);
if(DL_Div(&dl, lly, dots, 0, 0) == NOTOK)
return (NOTOK);
DL_Mul(&dl, lly, dots);
residue = llx->lowlong - dl.lowlong;
DL_Div(llx, lly, dots, 0, 0);
divisor = lly;
while(residue != 0)
{
if((llx->highlong > (0xFFFFFFFF/0x64)) || (llx->dots > 10)) /* The result is enough */
break;
L2DL(residue, &dl, 0);
DL_Mul(&dl, 10, 0);
DL_Eva(&dl1,&dl);
DL_Div(&dl, divisor, 0, 0, 0);
quotient = dl.lowlong; /* Get the quotient */
DL_Mul(llx, 10, 1);
DL_Add(llx, quotient, llx->dots); /* Add the quotient to the result */
DL_Mul(&dl, divisor, 0);
residue = dl1.lowlong - dl.lowlong; /* Get the new residue */
}
llx->sign = (sign1^sign2)?NEGATIVE:POSITIVE;
return (OK);
}
/* Adjust the two data llx and lly the same dots */
void DL_Add_Adj(DoubleLong *llx, DoubleLong *lly)
{
if(llx->dots < lly->dots)
{
while((llx->highlong < 0xFFFFFFFF/0x0A) && (llx->dots < lly->dots))
DL_Mul(llx, 10, 1);
if(llx->dots < lly->dots)
{
while(llx->dots < lly->dots)
DL_Div(lly, 10, 1, 0, 0);
}
}
else if(llx->dots > lly->dots)
{
while((lly->highlong < 0xFFFFFFFF/0x0A) && (lly->dots < llx->dots))
DL_Mul(lly, 10, 1);
if(lly->dots < llx->dots)
{
while(lly->dots < llx->dots)
DL_Div(llx, 10, 1, 0, 0);
}
}
}
#define MAX_BUF_LEN2 23
/* Transform the DoubleLong format to the ASCII format */
void DLong2Asc(DoubleLong *ll, char *obj_str, byte Adj_Len)
{
char posi;
char tmp_str[MAX_BUF_LEN2];
byte i, j;
byte cntr;
byte dots;
DoubleLong ll_tmp;
DoubleLong ll_tmp1;
j = 0;
dots = ll->dots;
posi = MAX_BUF_LEN2 - 1;
cntr = dots;
DL_Eva(&ll_tmp, ll);
ll_tmp.sign = POSITIVE;
while((ll_tmp.highlong != 0) || (ll_tmp.lowlong != 0))
{
DL_Eva(&ll_tmp1, &ll_tmp); /* ll_tmp%10 -->> i */
DL_Div(&ll_tmp1, 10, 0, 0, 0);
DL_Mul(&ll_tmp1, 10, 0);
ll_tmp1.sign = NEGATIVE;
DL_Add2(&ll_tmp1, ll_tmp);
i = ll_tmp1.lowlong;
tmp_str[posi --] = i + '0';
cntr --;
if(cntr == 0)
tmp_str[posi --] = '.';
DL_Div(&ll_tmp, 10, 0, 0, 0);
j ++;
}
if(j <= dots)
{
while(cntr)
{
tmp_str[posi --] = '0';
cntr --;
}
if(j < dots)
tmp_str[posi --] = '.';
tmp_str[posi --] = '0';
}
if(dots != 0)
cntr = 1;
else
cntr = 0;
if((MAX_BUF_LEN2 - 1 - posi) < (Adj_Len + cntr))
{
j = (Adj_Len + cntr) - (MAX_BUF_LEN2 - 1 - posi);
for(i = 0; i < j; i ++)
{
tmp_str[posi --] = '0';
}
}
if(ll->sign == NEGATIVE)
tmp_str[posi --] = '-';
posi ++;
memcpy(obj_str, tmp_str+posi, MAX_BUF_LEN2-posi);
obj_str[MAX_BUF_LEN2-posi] = 0;
}
#undef MAX_BUF_LEN2 /* Release the define */
/*----------------------------------------------------------------------*
* Transform the double long format to the bcd format
*
* bcdstr: Compressed BCD code, the high cell store the sign.
* Max_Len: The max length of the bcdstr, 4 bits equal 1 lenth;
*
* Note: Take no account of the decimal dots.
*----------------------------------------------------------------------*/
void DLong2Bcd(DoubleLong *ll, byte *bcdstr, byte Max_Len)
{
byte i;
byte posi;
DoubleLong ll_tmp;
DoubleLong ll_tmp1;
if(Max_Len == 0)
return;
posi = 0;
DL_Eva(&ll_tmp, ll);
ll_tmp.sign = POSITIVE;
while(Max_Len > 1)
{
DL_Eva(&ll_tmp1, &ll_tmp); /* ll_tmp%10 -->> i */
DL_Div(&ll_tmp1, 10, 0, 0, 0);
DL_Mul(&ll_tmp1, 10, 0);
ll_tmp1.sign = NEGATIVE;
DL_Add2(&ll_tmp1, ll_tmp);
i = ll_tmp1.lowlong;
Store_CBCD_Cell(i, bcdstr, posi);
posi ++;
if(posi == Max_Len - 1)
break;
DL_Div(&ll_tmp, 10, 0, 0, 0);
}
if(ll->sign == NEGATIVE)
i = 1;
else // ll->sign == POSITIVE
i = 0;
Store_CBCD_Cell(i, bcdstr, posi);
posi ++;
}
/*----------------------------------------------------------------------*
* Transform the bcd format to the double long format
*
* bcdstr: Compressed BCD code, the high cell is the sign.
* Max_Len: The max length of the bcdstr, 4 bits equal 1 length;
* sign_flag: 1: Store the sign
* 0: Not store the sign
*
* Note: Take no account of the decimal dots.
*----------------------------------------------------------------------*/
void Bcd2DLong(byte *bcdstr, DoubleLong *ll, byte Max_Len)
{
/* Reserved */
}
/* Rev 1.0 30 Dec. 1996. LHM.
* mathmatic function and tax computation
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -