您的位置:首页 > 其它

高精度加减乘除

2017-11-29 23:44 197 查看
一。高精度乘法(敲了好久。。头秃)
//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;}elsereturn 1;//一位以便于输出0if(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 )//四舍五入,循环是怕一入就出现了10do{++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;elsefor(int i = 0; i < la; ++i)if( a[i] > b[i] )return 1;else if( a[i] < b[i] )return -1;return 0;}
还是初学者,自己敲可能有bug,也应该还可以优化,比如处理进位写成函数什么的。要是以后变大佬了就回来优化一波算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: