[c++]大数运算1---利用C++ string实现任意长度正小数、整数之间的加减法
本文为大大维原创,最早于博客园发表,转载请注明出处!!!
一、概述
C/C++中的int类型能表示的范围是-2E31-2E31–1。unsigned类型能表示的范围是0-2E32–1,即 0-4294967295。所以,int和unsigned类型变量,都不能保存超过10位的整数。有时我们需要参与运算的数,可能会远远不止10 位,例如,可能需要保留小数点后面100位(比如求π的值),那么,即便使用能表示很大数值范围的double变量,但是由于double变量只有64位,所以还是不可能达到精确到小数点后面100位这样的精度。double变量的精度也不足以表示一个100位的整数。一般我们称这种基本数据类型无法表示的整数为大数。如何表示和存放大数呢?在c语言下,我们可以用数组存放和表示大整数,一个数组元素,存放大数中的一位。而在c++中,使用标准库的string类型,使得大数问题的计算更加实用(没有最大值的限制),更加灵活(输入更加简洁方便),更加简单(可以方便的处理小数之间的运算)。
二、算法原理简单描述:
看如下大整数的加法运算:

answer每一位都是num1、num2和carry的和,因此,我们在输入加数和被加数的string之后,可以将内容进行一次反转,这样,answer[i]=num1[i]+num2[i]+carry[i-1]。反转的一个重要的原因是可以方便的将向前的进位和运算变为向后的进位运算,有利于充分发挥string的特点。在这里,我们可以使用<algorithm>头文件下的reverse()函数方便的实现string的内容反转。当运算完毕后,反转回来即可。
当加入小数点后,我们就需要考虑一些额外的问题--小数点的位置问题,笔者在此采用了如下的策略:将输入内容格式检查之后(使用了cctpe头文件),将一个数分为小数部分和整数部分,然后先运算小数部分,将得到的carry最后和整数部分一起运算,最后将两部分的和拼接在一起。
对于大数的减法问题,基本上是大数加法的一个逆运算过程,笔者不在细讲,看源代码就可以很容易的理解。
三、程序代码:
/*
大数的运算1--加法:
利用C++ string实现任意长度正小数、整数之间的加减法
作者:大大维
2017/5/5
*/
#include<iostream>
#include<string>
#include<cctype>
#include<algorithm>
using namespace std;
string sum(string,string,string,string);
string sub(string,string,string,string);
int main()
{
string num1,num2;
cout<<"Input num1 , num2:"<<endl;
cin>>num1>>num2;
string num11,num12,num21,num22;
//输入检查
//是否是小数的标志
bool num1Flag=false,num2Flag=false;
for(auto c:num1)
{
//由数字或者数字加一个.组成
if(!isdigit(c)||num1.empty())
{
if(c=='.'&&!num1Flag)
{
num1Flag=true;
}
else
{
cout<<"num1: Please input correct form!!!"<<endl;
return ;
}
}
}
for(auto c:num2)
{
if(!isdigit(c)||num2.empty())
{
if(c=='.'&&!num2Flag)
{
num2Flag=true;
}
else
{
cout<<"num2: Please input correct form!!!"<<endl;
return ;
}
}
} //字符串分割{整数部分和小数部分)
if(num1Flag)//如果是小数
{
int i=;
while(i!=num1.size()&&num1[i]!='.')
{
num11+=num1[i];
++i;
}
while(++i!=num1.size())
{
num12+=num1[i];
}
//用于.XXX或XXX.型输入的控制
if(num11.empty())
num11+='';
if(num12.empty())
num12+='';
}
else//如果是整数
{
num11=num1;
num12+='';
}
if(num2Flag)//如果是小数
{
int i=;
while(i!=num2.size()&&num2[i]!='.')
{
num21+=num2[i];
++i;
}
while(++i!=num2.size())
{
num22+=num2[i];
}
//用于.XXX或XXX.型输入的控制
if(num21.empty())
num21+='';
if(num22.empty())
num22+='';
}
else//如果是整数str
{
num21=num2;
num22+='';
} cout<<"The Sum result = "<<sum(num11,num12,num21,num22)<<endl;
cout<<"The Sub result = "<<sub(num11,num12,num21,num22)<<endl;
} //加法 较长的整数部分 较长的小数部分 较短的整数部分 较短的小数部分
string sum(string strLong1,string strLong2,string strShort1,string strShort2)
{
//小数部分计算
if(strLong2.size()<strShort2.size())
{
string strTemp=strLong2;
strLong2=strShort2;
strShort2=strTemp;
}
//补0
for(int i=strShort2.size(); i<strLong2.size(); ++i)
strShort2+='';
//反转字符串
reverse(strLong2.begin(),strLong2.end());
reverse(strShort2.begin(),strShort2.end());
//小数部分进行加法计算
string strRes2(strLong2.size(),'');
int carry=;//进位
for(int i=; i!=strLong2.size(); ++i)
{
int a=strShort2[i]-'',b=strLong2[i]-'';
a=a+b+carry;
carry=a/;
strRes2[i]=(a%)+'';
}
//反转回来
reverse(strRes2.begin(),strRes2.end()); //整数部分计算
if(strLong1.size()<strShort1.size())
{
string strTemp=strLong1;
strLong1=strShort1;
strShort1=strTemp;
}
//反转字符串
reverse(strLong1.begin(),strLong1.end());
reverse(strShort1.begin(),strShort1.end()); string strRes1(strLong1.size(),'');
for(int i=; i!=strShort1.size(); ++i)
{
int a=strShort1[i]-'',b=strLong1[i]-'';
a=a+b+carry;
carry=a/;
strRes1[i]=(a%)+'';
}
for(int i=strShort1.size(); i!=strLong1.size(); ++i)
{
int b=strLong1[i]-'';
b+=carry;
carry=b/;
strRes1[i]=b%+'';
}
if(carry)
{
strRes1+=(carry+'');
}
//反转回来
reverse(strRes1.begin(),strRes1.end()); //合并整数部分和小数部分
string strRes=strRes1+'.'+strRes2;
return strRes;
} //减法 被减数的整数部分 被减数的小数部分 减数的整数部分 减数的小数部分
string sub(string strBjs1,string strBjs2,string strJs1,string strJs2)
{
//小数部分进行减法计算
int cntTemp=strBjs2.size()-strJs2.size();
//补0
if(cntTemp<=)
{
for(int i=cntTemp;i!=;++i)
{
strBjs2+='';
}
}
else
{
for(int i=cntTemp;i!=;--i)
{
strJs2+='';
}
} //反转字符串
reverse(strBjs2.begin(),strBjs2.end());
reverse(strJs2.begin(),strJs2.end());
string strRes2(strBjs2.size(),'');
int carry=;//进位
for(int i=; i!=strBjs2.size(); ++i)
{
int a=strBjs2[i]-'',b=strJs2[i]-'';
a=a-b-carry;
if(a>=)
{
carry=;
strRes2[i]=a+'';
}
else
{
carry=;
strRes2[i]=a++'';
}
}
//反转回来
reverse(strRes2.begin(),strRes2.end()); //整数部分进行减法计算
//反转字符串
reverse(strBjs1.begin(),strBjs1.end());
reverse(strJs1.begin(),strJs1.end());
string strRes1(strBjs1.size(),'');
for(int i=;i!=strJs1.size();++i)
{
int a=strBjs1[i]-'',b=strJs1[i]-'';
a=a-b-carry;
if(a>=)
{
carry=;
strRes1[i]=a+'';
}
else
{
carry=;
strRes1[i]=a++'';
}
}
for(int i=strJs1.size();i!=strBjs1.size();++i)
{
int a=strBjs1[i]-'';
a=a-carry;
if(a>=)
{
carry=;
strRes1[i]=a+'';
}
else
{
carry=;
strRes1[i]=a++'';
}
}
if(carry)//此时除数比被除数大,结果为负数
{
return "*";
}
//反转回来
reverse(strRes1.begin(),strRes1.end()); //清楚冗余0
string strTemp;
cntTemp=;
for(int i=;strRes1[i]=='';++i)++cntTemp;
for(int i=cntTemp;i!=strRes1.size();++i)
strTemp+=strRes1[i];
strRes1=strTemp;
//合并整数部分和小数部分
string strRes=strRes1+'.'+strRes2;
return strRes;
}
四、运行结果截图:


说明1:此处有一定的容错性,可以处理(.X或X.型的数据)

说明2:(*)表示结果为负数,不再处理

说明3:对输出格式统一控制为小数类型
[c++]大数运算1---利用C++ string实现任意长度正小数、整数之间的加减法的更多相关文章
- [c++]大数运算---利用C++ string实现任意长度正小数、整数之间的加减法
		
本文为大大维原创,最早于博客园发表,转载请注明出处!!! 一.概述 C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-4294 ...
 - 求任意长度数组的最大值(整数类型)。利用params参数实现任意长度的改变。
		
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
 - 收藏的一段关于java大数运算的代码
		
收藏的一段关于java大数运算的代码: package study_02.number; import java.math.BigDecimal; import java.math.BigIntege ...
 - [PKU2389]Bull Math (大数运算)
		
Description Bulls are so much better at math than the cows. They can multiply huge integers together ...
 - java 大数运算[转]
		
用JAVA 实现算术表达式(1234324234324 + 8938459043545)/5 + 343434343432.59845 因为JAVA语言中的long 定义的变量值的最大数受到限制,例如 ...
 - A+B大数运算
		
基础加法大数运算: [https://vjudge.net/problem/HDU-1002] 题目: 输入两个长度不超过1000的整数求出sum. 思路: 由于数字很大不能直接加,用字符串形式输入, ...
 - HOJ 2148&POJ 2680(DP递推,加大数运算)
		
Computer Transformation Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4561 Accepted: 17 ...
 - 九度OJ 1119:Integer Inquiry(整数相加) (大数运算)
		
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:679 解决:357 题目描述: One of the first users of BIT's new supercomputer was ...
 - lua实现大数运算
		
lua实现的大数运算,代码超短,眼下仅仅实现的加减乘运算 ------------------------------------------------ --name: bigInt --creat ...
 
随机推荐
- jQuery使用小结
			
$(document).ready( function(){} ); 选择器 $("p:first") 第一个元素 $("p.intro" ...
 - 前端随手优化不完全篇-SEO篇
			
一代码优化概述 关于代码优化的知识是纯理论的知识,学习的很枯燥.在学到CSS时,不免遇到CSS+div进行代码优化的知 识,因此在网上看了一些关于这方面的知识,简单的整合一下,梳理自己所了解的代码优化 ...
 - mySql 安装教程
			
看了好久别人的文章,今天就开始自己写第一篇.希望给别人能提供帮助,也可以方便自己查阅. 前两天自己安装了mysql,感觉是比oracle好装多了. mysql安装有两种方式,一种是安装包安装方式,一种 ...
 - Jmeter察看结果树的响应数据中的中文显示乱码问题处理
			
1.Jmeter的察看结果树的响应数据有中文时会显示乱码,如图,我访问百度HTTP请求,响应数据中的title处是一串乱码 2.我们需要改一个设置,打开jmeter\bin\jmeter.proper ...
 - sed命令详解-应用篇
			
本篇从实用的角度讲解sed,关于sed的详细帮助文档,请参考前篇 http://www.cnblogs.com/the-capricornus/p/5279979.html 本篇用到的选项请参考前篇. ...
 - lightoj1281快速幂+数学知识
			
https://vjudge.net/contest/70017#problem/E 后半部分快速幂就能求出来,要注意03lld不然001是输出错误为1.前半部分用log10() 对于给定的一个数n, ...
 - 如何高效的进行WebService接口性能测试
			
版权声明:本文为原创文章,转载请先联系并标明出处 关于接口测试的理解,主要有两类,一类是模块与模块间的调用,此类接口测试应该归属于单元测试的范畴,主要测试模块与模块之间联动调用与返回.此类测试大多关注 ...
 - hive集成sentry
			
1.安装配置sentry 详细步骤见上一篇安装配置sentry 2.配置hive 2.1 Hive-server2集成Sentry 在 /etc/hive/conf/hive-site.xml中添加: ...
 - c#实现windows远程桌面连接程序
			
c#实现windows远程桌面连接程序 使用winform制作windows远程桌面连接程序,windows自带了远程桌面连接,我们需要将远程桌面连接集成 到自己的winform程序,并实现管理远程主 ...
 - hdu 4552 怪盗基德的挑战书
			
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4552 思路: 其实可以用KMP+DP解决 我这里给出后缀数组的解题方法 思路: 初始化ans=n(n为 ...