Inputhtml
Outputgit
Sample Inputgithub
95.123 12 0.4321 20 5.1234 15 6.7592 9 98.999 10 1.0100 12
Sample Output算法
548815620517731830194541.899025343415715973535967221869852721 .00000005148554641076956121994511276767154838481760200726351203835429763013462401 43992025569.928573701266488041146654993318703707511666295476720493953024 29448126.764121021618164430206909037173276672 90429072743629540498.107596019456651774561044010001 1.126825030131969720661201
解题思路数组
对于此类高精度计算,必定不能用常规的+、-、*、/运算符运算,因其会致使溢出问题,因此考虑将原数据的每一位分开,而且顺序放入线性表中,模拟竖式的计算过程进行计算。在选择线性表的种类时,根据实际须要选择数组或链表。在C++ STL标准模板库中,以数组实现的线性表的容器是vector,其容量能够随数据大小变化,即在开始时会根据初始数据的大小开辟一个比数据的长度稍大的空间,好比初始数组中只有一个数,可是容器会先开辟8个数据的容量。若后续对容器进行数据量的增长,会填满这8个空位,那么容器会自动判断是否有空位,容量不够的话,会从新开辟一块更大容量的空间,而且将原数组中的内容拷贝到新的空间。这就致使,在此问题中若用数组实现线性表时,会浪费更多的程序运行时间,因此此处选择链表形式的线性表,在STL中,使用线性表须要添加头文件:函数
#include <list>
将题目中输入的s转存到list当中,在转存时,为了方便操做,将高位与低位倒置放在链表中(由于模拟竖式运算时,须要从低位向高位计算)。而且同时记录原始数据中小数点的位置。spa
list<int> origin, res(1, 1); //origin为转换为链表以后存储底数的变量 int dot_pos = 0, res_dot = 0; //dot_pos为原底数小数点位置, res_dot记录结果的小数点位置 for (int i = s.size() - 1; i >= 0; --i) { if (s[i] == '.') dot_pos = s.size() - i - 1; //记录是否在原底数中有小数点的存在,记录逆序小数点位置 else origin.push_back(s[i]-'0'); //转化char为int类型 }
接下来运用快速幂计算的算法思路来求解s的n次幂。普通的幂计算是用递归(递推)方式求解,计算n次幂须要n次递归计算,时间复杂度为O(n)。而快速幂算法的简单思路为:若计算s^n,将n表示为二进制形式,如5可表示为101,即1+4,则,s^5=s^(1+4)=s^1*s^4=1*s^1*s^4。根据以上所述,依次计算s^1, s^2, s^4, ...,将s^1与s^4累乘到1上,便可获得结果。时间复杂度为O(logn)。详细代码以下:.net
/*使用快速幂运算求高精度幂*/ while (n > 0) { if (n & 1) { multiple(res, origin); res_dot += dot_pos; //更新结果的小数点位置 } multiple(origin, origin); if (dot_pos > 0) dot_pos <<= 1; n >>= 1; }
其中,multiple计算两个存储在链表中的两个数的乘积,结果经过第一个参数的引用返回。multiple函数的定义以下:指针
/*计算存储在两个链表中的两个数的乘积,结果经过Num1的引用返回*/ void multiple(list<int>& num1, list<int> num2) { //模拟乘法竖式进行计算,规定num2为乘数,num1为被乘数 list<int> temp, origin_num1(num1); //temp存储乘数与被乘数其中一位的临时结果,origin_num1为num1的拷贝,以防后续将num1清空致使原数据丢失 int key_index = 0; //记录两位数相乘时被乘数的左移位数 num1.erase(num1.begin(), num1.end()); for (auto key : origin_num1) { temp.erase(temp.begin(), temp.end()); for (int i = 0; i < key_index; ++i) temp.push_back(0); multiple_one(num2, key, temp); add(num1, temp); ++key_index; } }
注意,由于传入的两个数num1与num2多是同一个变量,因此此处实现时,为了函数体中可以保留num2原参数值,没有传入引用。传入引用时,C++编译器直接对实参进行操做,相似指针,而不加&符号时,C++在初始化函数后,拷贝一份实参的实体,并对这个新的实体进行操做,关于C++引用的详细内容,可参考这里。code
上述代码中的multiple_one与add函数分别计算一位数与多位数相乘以及两个多位数相加,实现思想与multiple函数相同,即模拟竖式计算。其函数原型以下:
/*计算一个一位整数与存储在链表L-H中的数的乘积,结果存储在result的引用返回*/ void multiple_one(list<int>& num, int one, list<int>& result); //模拟竖式计算多位乘以一位/*计算存储在链表L-H中的两个数的和,结果存储在num1*/ void add(list<int>& num1, list<int>& num2); //模拟竖式计算两个数相加
完成快速幂计算后,程序的主体已基本完成,最后的步骤就是根据题目要求格式化输出,即去掉前导与末尾的0。此处实现格式化时得出最后结果,对结果进行操做。也能够直接对原数据进行去零操做。对于程序运行时间来讲,后者效果更好。
源代码