前几天写的高精度的基本运算,包括整数和浮点数加减乘除,乘方和整数的阶乘.乘法和除法,以及乘方和阶乘都是以加法为基础,调用了加法的函数.写得很简陋,但是功能还可以,希望各位网友试用,如找到BUG请留言,谢谢!/*用数组存储数字,可以超越数据类型的限制,实现超长整型,高精度基本运算 */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 200
int Compare(const char *a, const char *b);
void IntAddition(char *augend, char *addend, char *sum);
void IntSubtration(char *minuend, char *subtrahend, char *difference);
void IntMultiplication(char *multiplicand, char *multiplier, char *product);
void IntDivision(char *dividend, char *divisor, char *quotient, char *remainder);
int Radix(char *toStr, char *fromStr);
void FloatAddition(char *augend, char *addend, char *sum);
void FloatSubtration(char *minuend, char *subtrahend, char *difference);
void FloatMultiplication(char *multiplicand, char *multiplier, char *product);
void FloatDivision(char *dividend, char *divisor, char *quotient, int precision);
void Insert(char s[], int left, int right);
int IsCycle(char a[][MAX], int label);
void Factorial(char *base, char *result);
void IntPower(char *base, char *exponential, char *power);
void FloatPower(char *base, char *exponential, char *power);
int main(void)
{
char a[MAX] = {0};
char b[MAX] = {0};
char c[3*MAX] = {0};
char d[MAX] = {0};
puts("请输入第一个数:");
gets(a);
puts("请输入第二个数:");
gets(b);
IntAddition(a, b, c);
puts("两者之和:");
puts(c);
IntSubtration(a, b, c);
puts("两者之差:");
puts(c);
IntMultiplication(a, b, c);
puts("两者之积:");
puts(c);
IntDivision(a, b, c, d);
puts("两者之商:");
puts(c);
puts("余数:");
puts(d);
FloatAddition(a, b, c);
puts("两者之和:");
puts(c);
FloatSubtration(a, b, c);
puts("两者之差:");
puts(c);
FloatMultiplication(a, b, c);
puts("两者之积:");
puts(c);
FloatDivision(a, b, c, MAX);
puts("两者之商:");
puts(c);
IntPower(a, b, c);
puts("两者之乘方:");
puts(c);
FloatPower(a, b, c);
puts("两者之乘方:");
puts(c);
Factorial(a, c);
puts("a的阶乘:");
puts(c);
system("pause");
return 0;
}
/*
函数功能:利用字符串实现超长整型,高精度加法运算
输入变量:char *augend,存储了被加数的字符串
char *addend,存储了加数的字符串
char *sum,用来存储两数之和的字符串
输出变量:char *sum,用来存储两数之和的字符串
返回值: 无
*/
void IntAddition(char *augend, char *addend, char *sum)
{
int cAug[MAX] = {0};//用来存储被加数的整型数组
int cAdd[MAX] = {0};//用来存储加数的整型数组
int cSum[MAX] = {0};//用来存储两数之和的整型数组
int lenAug = strlen(augend), lenAdd = strlen(addend);//被加数和加数字符串的长度
int lenMin = lenAug < lenAdd ? lenAug : lenAdd;//两个加数的长度中的较小值
int i;
//逆序复制加数和被加数到整型数组(因为加法运算是从低位开始)
for (i=0; i<lenAug; i++)
cAug[i] = augend[lenAug-1-i] - '0';
for (i=0; i<lenAdd; i++)
cAdd[i] = addend[lenAdd-1-i] - '0';
int carry = 0;//进位
int s = 0; //两数之和
for (i=0; i<lenMin; i++)//加法运算过程
{
s = cAug[i] + cAdd[i] + carry;//两个加数和进位之和作为当前位的和
cSum[i] = s % 10;//存储当前位
carry = s / 10;//获取进位
}
//处理加数或被加数超出长度lenMin的部分
while (i < lenAug)
{
s = cAug[i] + carry;
cSum[i] = s % 10;
carry = s / 10;
i++;
}
while (i < lenAdd)
{
s = cAdd[i] + carry;
cSum[i] = s % 10;
carry = s / 10;
i++;
}
if (carry > 0)//处理最后一个进位
cSum[i++] = carry;
int j;
for (j=0; j<i; j++)//逆序存储两数之和到字符串sum
sum[j] = cSum[i-1-j] + '0';
sum[i] = '\0';
}
//比较两个用字符串存储的超长正整数的大小,若a>b,返回1;a==b,返回0;a<b,返回-1
int Compare(const char *a, const char *b)
{
int lenA = strlen(a);
int lenB = strlen(b);
if (lenA != lenB)
return lenA > lenB ? 1 : -1;
else
return strcmp(a, b);
}
/*
函数功能:利用字符串实现超长整型,高精度减法运算
输入变量:char *minuend,存储了被减数的字符串
char *subtrahend,存储了减数的字符串
char *difference,用来存储两数之差的字符串
输出变量:char *difference,用来存储两数之差的字符串
返回值: 无
*/
void IntSubtration(char *minuend, char *subtrahend, char *difference)
{
if (strcmp(minuend, subtrahend) == 0)//如果两数相等,返回"0"
{
strcpy(difference, "0");
return;
}
int cM[MAX] = {0};//用来存储被减数的整型数组
int cS[MAX] = {0};//用来存储减数的整型数组
int cD[MAX] = {0};//用来存储两数之差的整型数组
int lenM = strlen(minuend), lenS = strlen(subtrahend);//被减数和减数字符串的长度
int lenMin = lenM < lenS ? lenM : lenS;//两个减数的长度中的较小值
int flag;//记录结果是整数还是负数
int i;
//逆序复制减数和被减数到整型数组(因为减法运算是从低位开始),保证cM大于cS
if (Compare(minuend, subtrahend) > 0)
{
flag = 0;//被减数大于减数,结果为正数
for (i=0; i<lenM; i++)
cM[i] = minuend[lenM-1-i] - '0';
for (i=0; i<lenS; i++)
cS[i] = subtrahend[lenS-1-i] - '0';
}
else
{
flag = 1;//被减数小于减数,结果为负数,此时要用subtrahend - minuend
for (i=0; i<lenM; i++)
cS[i] = minuend[lenM-1-i] - '0';
for (i=0; i<lenS; i++)
cM[i] = subtrahend[lenS-1-i] - '0';
}
for (i=0; i<lenMin; i++)//减法运算过程
{
if (cM[i] >= cS[i])//被减数大于减数,直接相减
cD[i] = cM[i] - cS[i];
else //否则要向前借位
{
cD[i] = cM[i] + 10 - cS[i];
--cM[i+1];
}
}
//处理减数或被减数超出长度lenMin的部分
int len = lenM > lenS ? lenM : lenS;
while (i < len)
{
if (cM[i] >= 0)
cD[i] = cM[i];
else
{
cD[i] = cM[i] + 10;
--cM[i+1];
}
i++;
}
while (cD[i-1] == 0)
i--;
int j = 0;
if (flag == 1)//如果被减数小于减数,返回一个负数
difference[j++] = '-';
int k;
for (k=i-1; k>=0; k--,j++)//逆序存储两数之差到字符串sum
difference[j] = cD[k] + '0';
difference[j] = '\0';
}
/*
函数功能:利用字符串实现超长整型,高精度乘法运算
输入变量:char *minuend,存储了被乘数的字符串
char *subtrahend,存储了乘数的字符串
char *difference,用来存储两数之乘积的字符串
输出变量:char *difference,用来存储两数之乘积的字符串
返回值: 无
*/
void IntMultiplication(char *multiplicand, char *multiplier, char *product)
{
int cD[MAX] = {0};//用来存储被乘数的整型数组
int cR[MAX] = {0};//用来存储乘数的整型数组
int cP[MAX] = {0};//用来存储两数之乘积的整型数组
char tcP[MAX] = "";//用来存储两数之乘积的整型数组
int lenD = strlen(multiplicand), lenR = strlen(multiplier);//被乘数和乘数字符串的长度
int i, j, k;
//逆序复制乘数和被乘数到整型数组(因为乘法运算是从低位开始)
for (i=0; i<lenD; i++)
cD[i] = multiplicand[lenD-1-i] - '0';
for (i=0; i<lenR; i++)
cR[i] = multiplier[lenR-1-i] - '0';
int carry;//进位
int mul = 0; //两数之乘积
strcpy(product, "0"); //先使product的值为0
for (i=0; i<lenR; i++)//乘法运算过程
{
carry = 0;//进位
for (j=0; j<lenD; j++)//乘数的每一位都和被乘数进行乘法运算
{
mul = cD[j] * cR[i] + carry;//两个乘数之积与进位相加作为当前位乘积
cP[j] = mul % 10;//存储当前位
carry = mul / 10;//获取进位
}
if (carry > 0)//获取最后一个进位
cP[j++] = carry;
while (cP[j-1] == 0)//去掉多余的0
--j;
//逆序复制当前位的乘积tP到字符串tcP
for (k=0; k<j; k++)
tcP[k] = cP[j-1-k] + '0';
for (j=0; j<i; j++)//注意各位数得到的结果应相应左移
tcP[k++] = '0';
tcP[k] = '\0';
IntAddition(product, tcP, product);//对字符串进行加法运算
}
}
/*
函数功能:利用字符串实现超长整型,高精度除法运算
输入变量:char *dividend,存储了被除数的字符串
char *divisor,存储了除数的字符串
char *quotient,用来存储两数相除之商的字符串
char *remainder,用来存储两数相除之余数的字符串
输出变量:char *quotient,用来存储两数相除之商的字符串
char *remainder,用来存储两数相除之余数的字符串
返回值: 无
*/
void IntDivision(char *dividend, char *divisor, char *quotient, char *remainder)
{
if (Compare(dividend, divisor) == 0)//被除数等于除数
{
strcpy(quotient, "1");
strcpy(remainder, "0");
return ;
}
if (strcmp(divisor, "0") == 0 || Compare(dividend, divisor) < 0)//被除数小于除数
{
strcpy(quotient, "0");
strcpy(remainder, dividend);
return ;
}
char buf[2] = "0";//临时数组依次存储被除数的每一位数
int i, s, k;
strcpy(remainder, ""); //先使product的值为空
for (i=0,k=0; dividend[i]!='\0'; i++)
{
s = 0;
buf[0] = dividend[i];
strcat(remainder, buf);//接上被除数的一位数,改变当前余数
while (Compare(remainder, divisor) >= 0)//连减试商
{
s++;
IntSubtration(remainder, divisor, remainder);
}
quotient[k++] = s + '0';//记录每一位得到的商值
if (strcmp(remainder, "0") == 0)
strcpy(remainder, ""); //使product的值为空,去掉多余的0
}
quotient[k] = '\0';
//去掉多余的0
int j;
for (i=0; quotient[i]=='0'; i++)
;
for (j=i; j<=k; j++)
quotient[j-i] = quotient[j];
}
/*
函数功能:去掉原字符串的小数点,把浮点数转化成整数后存储到新的字符串
输入变量:char *toStr,存储了转化后的整数的字符串
char *fromStr,存储了原浮点数的字符串
输出变量:char *toStr,存储了转化后的整数的字符串
返回值: 原浮点数小数部分的长度
*/
int Radix(char *toStr, char *fromStr)
{
int i = 0, j = 0;
int len;
while (fromStr[i] != '.' && fromStr[i] != '\0')
{
toStr[j++] = fromStr[i++];
}
len = i++;//跳过小数点,并记录该位置
while (fromStr[i] != '\0')
{
toStr[j++] = fromStr[i++];
}
return i - len - 1;//记录小数点后的数字个数
}
/*
函数功能:利用字符串实现超长浮点型,高精度加法运算
输入变量:char *augend,存储了被加数的字符串
char *addend,存储了加数的字符串
char *sum,用来存储两数之和的字符串
输出变量:char *sum,用来存储两数之和的字符串
返回值: 无
*/
void FloatAddition(char *augend, char *addend, char *sum)
{
char cAug[MAX] = {0};//用来存储被加数的字符串
char cAdd[MAX] = {0};//用来存储加数的字符串
char cSum[MAX] = {0};//用来存储两数之和的字符串
int lenAug, lenAdd, lenSum;//分别存储三个数的小数点后的数字个数
int i, topAug, topAdd;
//去掉小数点,把浮点数转化成整数后存储到新的字符串
lenAug = Radix(cAug, augend);
lenAdd = Radix(cAdd, addend);
topAug = strlen(cAug);
topAdd = strlen(cAdd);
//在小数部分较短的字符串后补零,使得两个数的小数部分长度相等
if (lenAug > lenAdd)
{
lenSum = lenAug;
for (i=lenAug-lenAdd; i>0; i--)
cAdd[topAdd++] = '0';
}
else
{
lenSum = lenAdd;
for (i=lenAdd-lenAug; i>0; i--)
cAug[topAug++] = '0';
}
cAdd[topAdd++] = '\0';
cAug[topAug++] = '\0';
//执行整数加法运算
IntAddition(cAdd, cAug, cSum);
i = strlen(cSum) - 1;
while (lenSum > 0 && cSum[i] == '0')//去掉小数部分多余的零
{
i--;
lenSum--;
}
cSum[i+2] = '\0';
while (lenSum > 0)//在适当位置插入'.’
{
cSum[i+1] = cSum[i];
i--;
lenSum--;
}
cSum[i+1] = '.';
strcpy(sum, cSum);
}
/*
函数功能:利用字符串实现超长浮点型,高精度减法运算
输入变量:char *minuend,存储了被减数的字符串
char *subtrahend,存储了减数的字符串
char *difference,用来存储两数之差的字符串
输出变量:char *difference,用来存储两数之差的字符串
返回值: 无
*/
void FloatSubtration(char *minuend, char *subtrahend, char *difference)
{
if (strcmp(minuend, subtrahend) == 0)//如果两数相等,返回"0"
{
strcpy(difference, "0");
return;
}
char cM[MAX] = {0};//用来存储被减数的字符串
char cS[MAX] = {0};//用来存储减数的字符串
char cD[MAX] = {0};//用来存储两数之差的字符串
int lenM, lenS, lenD;//分别存储三个数的小数点后的数字个数
int i, topM, topS;
//去掉小数点,把浮点数转化成整数后存储到新的字符串
lenM = Radix(cM, minuend);
lenS = Radix(cS, subtrahend);
topM = strlen(cM);
topS = strlen(cS);
//在小数部分较短的字符串后补零,使得两个数的小数部分长度相等
if (lenM > lenS)
{
lenD = lenM;
for (i=lenM-lenS; i>0; i--)
cS[topS++] = '0';
}
else
{
lenD = lenS;
for (i=lenS-lenM; i>0; i--)
cM[topM++] = '0';
}
cM[topM++] = '\0';
cS[topS++] = '\0';
//执行整数减法运算
IntSubtration(cM, cS, cD);
i = strlen(cD) - 1;
while (lenD > 0 && cD[i] == '0')//去掉小数部分多余的零
{
i--;
lenD--;
}
cD[i+2] = '\0';
while (lenD > 0)//在适当位置插入'.’
{
cD[i+1] = cD[i];
i--;
lenD--;
}
cD[i+1] = '.';
if (i == -1)//结果为0的情况
{
cD[0] = '0';
cD[1] = '.';
cD[2] = '\0';
}
strcpy(difference, cD);
}
/*
函数功能:利用字符串实现超长浮点型,高精度乘法运算
输入变量:char *minuend,存储了被乘数的字符串
char *subtrahend,存储了乘数的字符串
char *difference,用来存储两数之乘积的字符串
输出变量:char *difference,用来存储两数之乘积的字符串
返回值: 无
*/
void FloatMultiplication(char *multiplicand, char *multiplier, char *product)
{
char cD[MAX] = {0};//用来存储被乘数的字符串
char cR[MAX] = {0};//用来存储乘数的字符串
char cP[2*MAX] = {0};//用来存储两数之乘积的字符串
int lenD, lenR, lenP;//分别存储三个数的小数点后的数字个数
//去掉小数点,把浮点数转化成整数后存储到新的字符串
lenD = Radix(cD, multiplicand);
lenR = Radix(cR, multiplier);
lenP = lenD + lenR;
IntMultiplication(cD, cR, cP);
int i = strlen(cP) - 1;
while (lenP > 0 && cP[i] == '0')//去掉小数部分多余的零
{
i--;
lenP--;
}
cP[i+2] = '\0';
while (lenP > 0 && i >= 0)//在适当位置插入'.’
{
cP[i+1] = cP[i];
i--;
lenP--;
}
cP[i+1] = '.';
if (i == -1)//如果小数点在第一位,在前面添0
{
for (i=strlen(cP); i>0; --i)
cP[i+1+lenP] = cP[i];
for (i=0; i<lenP; ++i)
cP[i+2] = '0';
cP[1] = '.';
cP[0] = '0';
}
strcpy(product, cP);
}
/*
函数功能:利用字符串实现超长浮点型,高精度除法运算
输入变量:char *dividend,存储了被除数的字符串
char *divisor,存储了除数的字符串
char *quotient,用来存储两数相除之商的字符串
int precision,用来存储小数部分的精度
输出变量:char *quotient,用来存储两数相除之商的字符串
返回值: 无
*/
void FloatDivision(char *dividend, char *divisor, char *quotient, int precision)
{
if (Compare(dividend, divisor) == 0)//被除数等于除数
{
strcpy(quotient, "1.");
return ;
}
if (strcmp(divisor, "0.")==0 || strcmp(divisor, "0")==0)//被除数小于除数
{
strcpy(quotient, "0.");
return ;
}
char cD[MAX] = {0};//用来存储被除数的字符串
char cR[MAX] = {0};//用来存储除数的字符串
char cQ[MAX] = {0};//用来存储两数之商的字符串
char cY[MAX] = {0};//用来存储两数之当前余数的字符串
char tcY[MAX][MAX] = {0};//用来存储两数之所有余数的字符串
int lenD, lenR, lenQ;//分别存储三个数的小数点后的数字个数
int i, j, t, s, left;
//去掉小数点,把浮点数转化成整数后存储到新的字符串
lenD = Radix(cD, dividend);
lenR = Radix(cR, divisor);
//如果被除数的小数部分长,则求出多出的小数长度,以便插入小数点,否则补0
if (lenD > lenR)
lenQ = lenD - lenR;
else
{
lenQ = 0;
i = strlen(cD);
for (j=0; j<lenR-lenD; j++)
cD[i++] = '0';
cD[i] = '\0';
}
IntDivision(cD, cR, cQ, cY);//得到整数部分的商
t = j = strlen(cQ);
//插入小数点
for (i=0; i<lenQ; ++i,--t)
{
if (t > 0)
cQ[t] = cQ[t-1];
else
{
t = 1;
cQ[t] = '0';
}
}
cQ[t] = '.';
if (t == 0)//如果小数点在第一位,在前面添0
{
for (i=j++; i>=0; --i)
cQ[i+1] = cQ[i];
cQ[0] = '0';
}
++j;
//处理小数部分
i = t = 0;
while (i < precision && strcmp(cY, "0")!=0)
{
strcpy(tcY[t++], cY);//存储所有的余数(小数部分)
left = IsCycle(tcY, t-1);//判断是否出现循环节
if (left != t-1) //如果找到相等的余数,就结束循环
{
Insert(cQ, j-(t-1-left), j);//在字符数组s中适当位置插入符号'('
if (cQ[j-1] == '(' && cQ[j] == '0')//去除多余的循环节,即特殊处理可以除尽的情况
cQ[--j] = '\0';
else//否则用“()”把循环节括起来
{
cQ[j+1] = ')';
cQ[j+2] = '\0';
}
break;
}
//否则继续计算小数部分
strcat(cY, "0");
s = 0;
if (Compare(cY, cR) < 0)
cQ[j++] = '0';
else
{
while (Compare(cY, cR) >= 0)
{
++s;
IntSubtration(cY, cR, cY);
}
cQ[j++] = s + '0';
}
++i;
}
if (i == precision)
cQ[j] = '\0';
strcpy(quotient, cQ);
}
/*函数介绍:在字符数组s中适当位置插入符号'('
char s[]: 字符数组,用来存储给定分数的小数形式
int left:数组a中需要插入符号'('的位置
int right:数组a中当前最右边的数字之后的下标
*/
void Insert(char s[], int left, int right)
{
int i;
for (i=right; i>left; i--) //把数组元素后移,为插入符号'('腾出位置
{
s[i] = s[i-1];
}
s[left] = '(';//插入符号'('
}
/*函数介绍:判断当前余数是否与前面的某个余数相同,若相同,返回该余数的位置下标
char a[][MAX]: 字符数组,存储了当前余数
int label:当前余数的下标
*/
int IsCycle(char a[][MAX], int label)
{
int i;
for (i=0; i<label; i++)
{
if (strcmp(a[i], a[label]) == 0) //如果数组中有与当前余数相同的余数,返回该余数的位置下标
return i;
}
return label; //否则返回当前余数的位置下标
}
/*
函数功能:利用字符串实现超长整型,高精度乘方运算
输入变量:char *base,存储了底数的字符串
char *exponential,存储了指数的字符串
char *power,用来存储两数相除之乘方的字符串
输出变量:char *power,用来存储两数相除之乘方的字符串
返回值: 无
*/
void IntPower(char *base, char *exponential, char *power)
{
if (strcmp(exponential, "0") == 0)//如果指数为0,返回1
{
strcpy(power, "1");
return ;
}
if (strcmp(exponential, "1") == 0)//如果指数为1,返回底数
{
strcpy(power, base);
return ;
}
char cRem[MAX] = {0};//用来存储余数的整型数组
char cExp[MAX] = {0};//用来存储指数的整型数组
char cPow[4*MAX] = {0};//用来存储两数之乘方的整型数组
IntDivision(exponential, "2", cExp, cRem);//将指数整除2
IntPower(base, cExp, cPow);//递归计算乘方,注意此时指数为原来的一半
IntMultiplication(cPow, cPow, power);//将递归得到的乘方结果相乘
if (strcmp(cRem, "1") == 0)//如果指数是奇数,乘方结果再乘以底数
IntMultiplication(power, base, power);
}
/*
函数功能:利用字符串实现超长浮点型,高精度乘方运算,注意指数为整数
输入变量:char *base,存储了底数的字符串
char *exponential,存储了指数的字符串
char *power,用来存储两数相除之乘方的字符串
输出变量:char *power,用来存储两数相除之乘方的字符串
返回值: 无
*/
void FloatPower(char *base, char *exponential, char *power)
{
if (strcmp(exponential, "0") == 0)//如果指数为0,返回1
{
strcpy(power, "1");
return ;
}
if (strcmp(exponential, "1") == 0)//如果指数为1,返回底数
{
strcpy(power, base);
return ;
}
char cRem[MAX] = {0};//用来存储余数的整型数组
char cExp[MAX] = {0};//用来存储指数的整型数组
char cPow[4*MAX] = {0};//用来存储两数之乘方的整型数组
IntDivision(exponential, "2", cExp, cRem);//将指数整除2
FloatPower(base, cExp, cPow);//递归计算乘方,注意此时指数为原来的一半
FloatMultiplication(cPow, cPow, power);//将递归得到的乘方结果相乘
if (strcmp(cRem, "1") == 0)//如果指数是奇数,乘方结果再乘以底数
FloatMultiplication(power, base, power);
}
/*
函数功能:利用字符串实现超长整型,高精度除法阶乘运算
输入变量:char *base,存储了被求阶乘的数的字符串
char *result,存储了阶乘结果的字符串
输出变量:char *result,存储了阶乘结果的字符串
返回值: 无
*/
void Factorial(char *base, char *result)
{
char cBase[MAX] = {0};//用来存储被求阶乘的数的整型数组
strcpy(cBase, base);
strcpy(result, "1");
while (strcmp(cBase, "1") > 0)
{
IntMultiplication(cBase, result, result);//按照阶乘的定义计算
IntSubtration(cBase, "1", cBase);
}
}
评论