前几天在网上看到这样一个题目 “两个数相乘,小数点后的位数没有限制,写一个高效算法“,在网上搜集到一些想法,感觉”先做大数乘法,然后再给结果加小数点“这种方法更好一些,用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;
}