大数相乘
首先说一下乘法计算的算法:同样是模拟人工计算时的方法。
从低位向高位乘,在竖式计算中,我们是将乘数第一位与被乘数的每一位相乘,记录结果之后,用第二位相乘,记录结果并且左移一位,以此类推,直到计算完最后一位,再将各项结果相加,得出最后结果。
例如:
int a=97
int b=23
23为乘数,97是被乘数:
为了程序程序计算方便,开辟一个数组,数组的最大长度为:
数组长度 = a的位数 + b的位数 + 1
计算过程为:
arr[i+j] += a[i]a[j]
其中i,j都是从右边向左开始计数的
第一趟的情况:
第二趟的情况:
从右向左考虑进位:
如果arr[i]>=10,通过整除10将第i位的进位加到i+1位上,余数部分作为第i位的值,
arr[i+1] += arr[i]/10;
arr[i] %= 10;
用c++代码实现如下:
//大数相乘,对于正数
string bigMul(string&a, string&b)
{
string res = "";
std::vector<int>c(a.size() + b.size() + 1); //输出结果最大为size()+b.size()+1,其中加1考虑的是进位
//考虑逐个位相乘,c[i+j]+=a[i]*a[j]
//用a的每一位分别乘以b的每一位上
//从右边开始遍历
for (int i = 0; i <a.size(); i++){
for (int j = 0; j<b.size(); j++){
int ai = a[a.size() - 1 - i] - '0'; //从最后一位开始表示最低位置
int bj = b[b.size() - 1 - j] - '0';
c[i + j] = c[i + j] + ai*bj; //注意在原始的基础上累加ai*bj;
}
}
//考虑进位,c中的数据是低位在前高位在后
for (int i = 0; i<c.size(); i++){
if (c[i] >= 10) {
c[i + 1] += c[i] / 10;
c[i] %= 10;
}
}
//最后一位表示最高位,c=a*b 中c的高位可能没有进位,需要去掉这些0之后再输出
for (int i = c.size() - 1; i >= 0; i--) {
if (c[i] == 0)c.pop_back();
else break;
}
//反向输出
for (int i = c.size() - 1; i >= 0; i--) {
// cout << c[i];
res += c[i] + '0'; //转化为字符
}
//cout << endl;
return res;}
基于大数相乘,可以解决牛客网上大数浮点指数运算那道题
题目
给定两个数R和n,输出R的n次方,其中0.0<R<99.999, 0<n<=25
输入
95.123 12 0.1 1
输出
548815620517731830194541.899025343415715973535967221869852721 0.1
思路是:
先将表示浮点数的字符串去掉小数点变成整数,并记录小数点的位数,然后用前面的整数的大数乘法计算,最后加上小数点
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
//大数相乘,对于正数
string bigMul(string&a, string&b)
{
string res = "";
std::vector<int>c(a.size() + b.size() + 1); //输出结果最大为a.size()+b.size()+1,其中加1考虑的是进位
//考虑逐个位相乘,c[i+j]+=a[i]*a[j]
//用a的每一位分别乘以b的每一位上
//从右边开始遍历
for (int i =0; i <a.size(); i++){
for (int j = 0;j<b.size(); j++){
int ai = a[a.size()-1-i] - '0'; //从最后一位开始表示最低位置
int bj = b[b.size()-1-j] - '0';
c[i + j ] = c[i + j ] +ai*bj; //注意在原始的基础上累加ai*bj;
}
}
//考虑进位,c中的数据是低位在前高位在后
for (int i = 0; i<c.size(); i++){
if (c[i] >= 10)
{
c[i+1] += c[i] / 10;
c[i] %= 10;
}
}
//最后一位表示最高位,c=a*b 中c的高位可能没有进位,需要去掉这些0之后再输出
for (int i = c.size() - 1; i >= 0; i--)
{
if (c[i] == 0)c.pop_back();
else break;
}
//反向输出
for (int i = c.size()-1;i>=0; i--) {
// cout << c[i];
res += c[i] + '0'; //转化为字符
}
//cout << endl;
return res;
}
//浮点数相乘,转化为正式后再相乘
string bigMulFloat(string&a, string&b)
{
string a_int = "";
string b_int = "";
size_t pos1 = a.find('.');
size_t pos2 = b.find('.');
int a_post_len = 0; //小数部分的长度
int b_post_len = 0;
if (pos1 != a.npos){ //如果能找到小数点
a_int += a.substr(0, pos1); //整数
a_post_len = a.size() - pos1 - 1;
a_int += a.substr(pos1 + 1, a_post_len); //小数部分
}
else{
a_int =a; //整数
}
if (pos2 != b.npos) { //如果能找到小数点
b_int += b.substr(0, pos2); //整数
b_post_len = b.size() - pos2 - 1;
b_int += b.substr(pos2 + 1, b_post_len); //小数部分
}
else{
b_int=b;
}
int len = a_post_len + b_post_len; //a,b小数部分的长度
string c = bigMul(a_int, b_int);
//c中小数部分个数为len_end个,正数部分长度为c.size()-len
string res;
//将小数点加入
if (len >= c.size()) { //如果全是小数,则前缀加一个0,最后表示成0.xxx
res += "0.";
for (int i = 0; i < len - c.size(); i++)
res += '0';
res += c;
}
else{
res += c.substr(0, c.size() - len); //整数
res += '.';
res += c.substr(c.size() - len, len);
}
//处理小数点后面的0
int cnt = 0;
for (cnt = 0; cnt < len; cnt++) {
if (res[res.size() - 1] == '0')
res.pop_back();
else
break;
}
//如果小数点后面都是0,则小数点也不要
if (cnt == len)
res.pop_back();
return res;
}
int main(){
string a;
int r;
vector<string> v_a;
vector<int>v_r;
while(cin>>a>>r){
v_a.push_back(a);
v_r.push_back(r);
}
int n=0;
for( n=0;n<v_a.size()-1;n++){
string res="1";
for(int i=0;i<r;i++)
{
res= bigMulFloat(res,v_a[n]) ;
}
cout<< res<<" ";
}
//最后一个输出没有空格
string res="1";
for(int i=0;i<r;i++)
{
res= bigMulFloat(res,v_a[n]) ;
}
cout<< res;
return 0;
}