正文

高精度计算2007-04-11 14:56:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/goal00001111/24795.html

分享到:

      前几天写的高精度的基本运算,包括整数和浮点数加减乘除,乘方和整数的阶乘.乘法和除法,以及乘方和阶乘都是以加法为基础,调用了加法的函数.写得很简陋,但是功能还可以,希望各位网友试用,如找到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); }}

阅读(4441) | 评论(3)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册