一。高精度乘法(敲了好久。。头秃)
//str1,str2是存数字的字符串,返回最后的位数,c存储结果 int highmult( char str1[], char str2[], int c[] ) { int len1 = strlen(str1), len2 = strlen(str2); int a[len1 + 1] = {0}, b[len2 + 1] = {0}; int i, j; memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); memset(c, 0, sizeof(c));
/*
*用这个函数写1000阶乘时这句话没用了,
*不知道为啥,可把我无奈坏了,找了半天错,
*好像memset对int数组不好用,有时候出问题
*/
//把字符变成数字,方便运算 for( i = len1 - 1, j = 0; i >= 0; i--) a[j++] = str1[i] - '0'; for( i = len2 - 1, j = 0; i >= 0; i--) b[j++] = str2[i] - '0'; for( i = 0; i < len1; i++)//i, j是权重,i+j就是c[]里面的权重 for( j = 0; j < len2; j++) { c[i + j] += a[i] * b[j]; printf("%d\n", c[i + j]); if( c[i + j] >= 10 )//因为9 + 9 * 9 < 100,所以只进一位 { int k = c[i + j]; c[i + j + 1] += k / 10; c[i + j] = k % 10; } }
//找位数。。。这个大概可以在前面的代码里优化,,懒,, for( i = len1 + len2 + 2; (c[i] == 0) && (i >= 0); i-- ) ; return i + 1; }
二。高精度加法
这个是我还不知道高精度是啥东西时百度的算法,记不得找的哪儿的了,一直存着,稍微改了点,,,原创看见了误喷一定加上链接。
恩!原创棒棒的!
//加起来存进c
int highadd( char num1[], char num2[], int c[] ) { int lena = strlen(num1), lenb = strlen(num2), lenc, i, x;//x 是进位用的 int a[100], b[100]; memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); memset(c, 0, sizeof(c));
//存数字 for( i = 0; i < lena; i++) a[lena - i - 1] = num1[i] - '0'; for( i = 0; i < lenb; i++) b[lenb - i - 1] = num2[i] - '0'; lenc = 0; x = 0; while( lenc <= lena || lenc <= lenb ) { c[lenc] = a[lenc] + b[lenc] + x; x = c[lenc] / 10; c[lenc] %= 10; lenc++; } c[lenc] = x; if( c[lenc] == 0 ) lenc--; return lenc; }
三。高精度减法
//贼他妈难写,
int highsub( char a[], char b[], int c[] )
{ for(int i = 0; i < MAXLEN; ++i) c[i] = 0; int la = strlen(a), lb = strlen(b); int sign(0), m(0); int com = compare(a, b);
//记录符号 if( com > 0 ) { sign = 1; m = la; } else if( com < 0) { sign = -1; m = lb; } else return 1;//一位以便于输出0 if(sign == 1) { int sub = la - lb; for(int i = 0; i < sub; ++i)//先把前面的权重高的解决了 c[i] = a[i] - '0'; for(int i = sub; i < m; ++i)//和我写的乘法一样,算一次就处理一次进位 { if( a[i] > b[i - sub]) c[i] = a[i] - b[i - sub]; else if( a[i] == b[i - sub] ) ; else//小于时向上一位要一个,后面再集中处理如果上一位也是零的情况 { --c[i - 1]; c[i] = (a[i] - '0') + 10 - (b[i - sub] - '0'); } } } else//一样的 { int sub = lb - la; for(int i = 0; i < sub; ++i) c[i] = b[i] - '0'; for(int i = sub; i < m; ++i) { if( b[i] > a[i - sub]) c[i] = b[i] - a[i - sub]; else if( a[i - sub] == b[i]) ; else { --c[i - 1]; c[i] = (b[i] - '0') + 10 - (a[i - sub] - '0'); } } } for(int i = m - 1; i >= 0; --i)//处理退位时产生的负数问题 if( c[i] < 0 ) { --c[i - 1]; c[i] += 10; } if(c[0] == 0)//处理a, b中前几位相同以至于c前几位是0的问题 for(int i = 1; i < MAXLEN; ++i) if( c[i] != 0 ) { for(int j = i; j < m; ++j) c[j - i] = c[j]; m -= i; break; } c[0] *= sign; return m; }
四。高精度除法
这个代码对于大数不能算位数相差超过六位的,太慢了,因为是用减法实现的,循环减,减了几次答案就是几
以后灵光一闪优化了(偷偷百度一下)再修改吧
(最难写的高精度。。)
//要存小数点就用字符数组c了,n是确定小数点后几位,默认c里面都是0,懒得加memset
int highdiv( char a[], char b[], char c[], int n ) { int d[MAXLEN]; int j(0), k(0); int zs;//记录小数点位置,便于小数部分运算
//代码核心,把除降解为减 while( compare( a, b ) >= 0 ) { int len = highsub(a, b, d); memset(a, 0, sizeof(0)); for(int i = 0; i < len; ++i) a[i] = d[i] + '0'; a[len] = '\0'; ++c[j]; if(c[j] >= 10)//烦人的进位问题 { for(int i = j; i > 0; --i) if( c[i] >= 10 ) { ++c[i - 1]; c[i] %= 10; } if(c[0] >= 10)//进到头了就把c整体往后挪一位 { for(int i = j; i >= 0; --i) c[i + 1] = c[i]; c[0] = 1; c[1] = 0; ++j; } } } zs = j + 2;//实际上是指向了小数点后一位
//把减的比b小的a膨胀开来,添加n + 1个0,模拟手算的加0过程 for(int i = strlen(a); i < MAXLEN && k <= n; ++i, ++k) { a[i] = '0'; if( k == n ) a[i + 1] = '\0'; } j += 2;//j指向第一个小数位,再来一波和上面差不多的操作 while( compare( a, b ) >= 0 ) { int len = highsub(a, b, d); memset(a, 0, sizeof(0)); for(int i = 0; i < len; ++i) a[i] = d[i] + '0'; a[len] = '\0'; ++c[j]; if(c[j] >= 10) { for(int i = j; i > zs; --i) if( c[i] >= 10 ) { ++c[i - 1]; c[i] %= 10; } if(c[zs] >= 10) { for(int i = j; i >= zs; --i) c[i + 1] = c[i]; c[zs] = 1; c[zs + 1] = 0; ++j; } } } k = j; if( c[k] >= 5 )//四舍五入,循环是怕一入就出现了10 do { ++c[k - 1]; c[k] = 0; } while( c[--k] >= 10 ); j = zs + n; for(int i = 0; i <= j; ++i)//数字变字符,便于小数点打印 c[i] += '0'; c[zs - 1] = '.'; c[j] = '\0'; return j + 1; }
最后把compare也贴出来吧,不复杂
int compare(char a[], char b[]) { int la = strlen(a), lb = strlen(b); if( la > lb ) return 1; else if( la < lb ) return -1; else for(int i = 0; i < la; ++i) if( a[i] > b[i] ) return 1; else if( a[i] < b[i] ) return -1; return 0; }
还是初学者,自己敲可能有bug,也应该还可以优化,比如处理进位写成函数什么的。
要是以后变大佬了就回来优化一波算法。