前几天在网上看到这样一个题目 “两个数相乘,小数点后的位数没有限制,写一个高效算法“,在网上搜集到一些想法,感觉”先做大数乘法,然后再给结果加小数点“这种方法更好一些,用c语言实现了,分享给大家。如果大家有更好的方法,欢迎一起交流。
#include<stdio.h> #include<string.h> void longmulti(const char *a, const char *b, char *c); void decimalmulti(char *a, char *b, char *c); int main(void) { char c[1024]; decimalmulti("3.1415926", "3.14", c); printf("3.1415926 * 3.14 = %s\n\n", c); return 0; } void longmulti(const char *a, const char *b, char *c) { int i, j, k, n, carry; int len_a, len_b; i = j = k = 0; //如果a,b中有一个是0,则整个运算的结果为0 if(!strcmp(a, "0") || !strcmp(b, "0")) { c[0] = '0'; c[1] = '\0'; return; } //判断运算结果的正负号 if(a[0] == '-') { i = 1; k = !k; } if(b[0] == '-') { j = 1; k = !k; } //如果出现了符号,先将符号过滤掉 if(i || j) { if(k) c[0] = '-'; longmulti(a+i, b+j, c+k); return; } len_a = strlen(a); len_b = strlen(b); memset(c, '0', len_a + len_b); c[len_a + len_b] = '\0'; //各位数的运算 #define I(a) (a - '0') for(i = len_a - 1; i >= 0; i--) { for(j = len_b - 1, k = i+j+1, carry = 0; j >= 0; j--, k--) { n = I(a[i]) * I(b[j]) + I(c[k]) + carry; c[k] = (n % 10) + '0'; carry = n / 10; } c[k] += carry; } #undef I if(c[0] == '0') memmove(c, c+1, len_a + len_b); } void decimalmulti(char *a, char *b, char *c) { /* len_a记录字符串a的长度 len_b记录字符串b的长度 len_c记录字符串c的长度 dot_a记录小数点在字符串a中的位置,从1开始计数,即数组下标加1。 dot_b记录小数点在字符串b中的位置。 index记录相乘后的结果中应该有几位小数 */ int len_a, len_b, len_c, i, j, k, dot_a, dot_b, index; len_a = strlen(a); len_b = strlen(b); dot_a = len_a;//小数点的位置为字符串的长度,表示不存在小数点 dot_b = len_b; //将字符串a中的小数点去掉,并记录小数点的位置 for(i = 0, k = 0; i < len_a; i++) { if(a[i] == '.') dot_a = i + 1;//在数组中的索引+1,为了方便后面计算 else a[k++] = a[i]; } a[k] = '\0'; //将字符串b中的小数点去掉,并记录小数点的位置 for(i = 0, k = 0; i < len_b; i++) { if(b[i] == '.') dot_b = i + 1; else b[k++] = b[i]; } b[k] = '\0'; //计算相乘后的结果总共有多少位小数 index = (len_a - dot_a) + (len_b - dot_b); //大整数乘法 longmulti(a, b, c); len_c = strlen(c); //为计算后的结果添加小数点 if(index > 0) { for(i = len_c; i >= len_c - index; i--) c[i + 1] = c[i]; c[len_c - index] = '.'; } //过滤左边的0 len_c = strlen(c); for(i = 0, j = 0; i < len_c; i++) { if(c[i+1] == '.' || c[i] != '0') break; j++; } if(j) memmove(c, c+j, len_c - j + 1); //过滤右边的0 len_c = strlen(c); for(i = len_c - 1; i >= 0; i--) if(c[i] == '0') c[i] = '\0'; else if(c[i] == '.') { c[i] = '\0'; break; } else break; }