【无限长度】【绝对精度】的大数运算方法
来源:互联网 发布:数据挖掘岗很难进吗 编辑:程序博客网 时间:2024/05/22 00:39
说到加减乘除,那应该是计算机的基本运算了,计算机之所以叫“计算机”就是因为拥有这些运算能力。但是当任何小的问题扩大化,都会成为一个大问题。因为计算机硬件的天然计算能力是限定位数的。例如32位CPU的运算能力就是2的32次方以内,64位CPU就是2的64次方以内。这在大多数的时候都是够用了,但在许多特殊情况下,却是不够用的。比如计算:107 的 50 次方;金融领域计算某个公式推演到20年后的情况,简化一点比如 1.102 的 20 次方,要求精确值,比如气象运算,医学模拟。在一些领域中2的64次是绝对不够用的!
那么如何解决这个问题呢?答案是:【软件模拟CPU的硬件运算】
这里我给出【大正整数】的【加法】和【乘法】,浮点数的加减乘除可以以此类推,后续也可能补充这部分的代码。
1.这里是大正整数【加法】的运算函数,在注释部分有详细的工作机制说明
string add(string &a,string &b){/**********************************//* 采取模拟CPU运算器的方法 *//* 1.字符ASCII码可以进行加减乘除 *//* 例如:'0'+'1'= 48 + 49 =97 *//* '6'+'1'-'0'='7' *//* 所以:要进行两个字符的加法 *//* 可采用a+b-48 *//* 或者用a+b-'0' *//* *//* 2.每次运算后考虑采用一个carry *//* 记录进位,所以每次加法应该加 *//* 前次运算的进位,所以运算为: *//* a + b + carry - '0' *//* *//* 3.要计算两个字符串代表的数值的 *//* 加和,那么应该采用逆序运算: *//* 比如:求"133"、"123"的和 *//* 运算次序应该是 *//* 3+3->3+2->1+1 *//* 这种求和顺序导致逆序记录更加 *//* 方便,即先记录成"652" *//* 最后所有运算结束的时候再逆序 *//* 得到"256" *//* *//* 4.运算的时候应当考虑字符串长度 *//* 不等的情况,如"12""3456" *//* 应先运算可运算的等长部分,即 *//* "12""56" *//* 最后将"34"与进位加和的结果添 *//* 加到最终结果的前面 *//**********************************/int a_len = a.length();int b_len = b.length();/*存放最终结果*/string result;/*存放临时进位、临时结果*/int carry = 0;char consq = 0;int i,j; /*i,j在循环退出后,仍然需要用到,故在循环外声明*/for(i=a_len-1,j=b_len-1; i>=0&&j>=0; --i,--j) /*循环能直接相加的部分*/{consq = a.at(i) + b.at(j) - 48 + carry;carry = 0;if( consq > '9'){carry = 1;consq = consq - 10;}result.push_back(consq);}if(i>=0)/*如果a仍然有没加完的部分*/{ while(i>=0){consq = a.at(i) + carry;carry = 0;if( consq > '9'){carry = 1;consq = consq - 10;}result.push_back(consq);--i;}}else if( j>=0 )/*如果b仍然有没加完的部分*/{while(j>=0){consq = b.at(j) + carry;carry = 0;if( consq > '9'){carry = 1;consq = consq - 10;}result.push_back(consq);--j;}}if(carry ==1) /*处理最后的进位*/{result.push_back('1');}/*翻转*/std::reverse(result.begin(),result.end());return result;};
string multiply(const string& a, const string& b){/**********************************//* 采取模拟CPU运算器的方法 *//* 1.字符ASCII码可以进行加减乘除 *//* 例如:('2'-'0')*('5'-'0')=10 *//* *//* 所以:要进行两个字符的乘法 *//* 可采用(a-'0')*(b-'0') *//* *//* 2.每次运算后考虑采用一个carry *//* 记录进位,所以每次加法应该加 *//* 前次运算的进位,所以运算为: *//* (a-'0')*(b-'0') + carry *//* *//* 3.要计算两个字符串代表的数值的 *//* 乘积,那么应该采用逆序记录, *//* 最后所有运算结束的时候再逆序 *//* *//* 4.乘积运算要考虑移位操作,但其 *//* 实可以用i、j循环变量确定当前 *//* 与上次循环结果的偏移量,其实 *//* 就是正序时就是i+j,但现在采用*//* 逆序记录,那么就是 *//* str_a.length -1 -i + *//* str_b.length -1 -j ; *//**********************************/int a_len = a.length();int b_len = b.length();/*最终结果*/string result;/*设置初始结果,"0000...000",与b的位数相同*/result.assign(b_len,'0');/*临时结果、临时进位*/int consq = 0;int carry = 0;for(int i=a_len-1; i>=0; --i){/* a中某一位数乘以b中每个数*/for(int j=b_len-1; j>=0; --j){ /*结果由三部分构成*/ consq = (a.at(i)-'0') * ( b.at(j)-'0') /*1. a*b的临时结果*/ + (result.at(a_len-i+b_len-j-2)-'0') /*2. 最终结果中这个位置的值*/+ carry ; /*3. 前面运算的进位*/carry = 0;if( consq >9 ){int temp = consq/10;carry = temp;consq = consq - carry*10;}result.at(a_len-i+b_len-j-2) = (consq+'0');} /*处理最后的进位*/result.push_back(carry+'0'); /*可能是0-9,0是有意义的,可以保证for循环中consq运算时*/carry = 0; /*result.at(i+j)总是能够取到值的*/ /*carry使用后清零*/}/*处理最终结果*/if( result.at(a_len+b_len-1) == '0'){result.pop_back();}/*翻转得到最终结果*/reverse(result.begin(),result.end());return result;};
- 【无限长度】【绝对精度】的大数运算方法
- python实现无限精度除法运算
- 对大数精度的处理(3)_大数乘大数
- 大数运算的算法
- 大数的运算
- 大数间的运算
- 大数的加减运算
- 大数的运算思想
- 大数的运算
- 项目:大数的运算
- 精简的大数运算
- BigDecimal带精度的运算
- BigDecimal带精度的运算
- 算数混合运算的精度
- 一种求大数运算的方法,如5000!
- java中大数运算Biginteger类的方法调用
- 对大数精度的处理(1)_大数阶乘
- 对大数精度的处理(2)_大数乘小数
- 带头结点和不带头结点的单链表的尾插法以及各种操作
- RPM 软件包的管理与安装
- 成员函数指针与高性能的C++委托
- Union和Union All的区别
- 快译实现报表模板打印
- 【无限长度】【绝对精度】的大数运算方法
- MVC 分页
- 想成为嵌入式程序员应知道的16个基本问题
- Sybase创建数据库
- luene
- 解决Windows7 x64中PLSQL出现中文乱码问题
- Hosted Network Assistant (承载网络助手)!
- VC中 十六进制字符串转换为十进制数字
- Andrioid SystemProperties和Settings.System介绍,不同应用间传递信息