本文为大大维原创,最早于博客园发表,转载请注明出处!!!

一、概述

  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++]大数运算---利用C++ string实现任意长度正小数、整数之间的加减法的更多相关文章

  1. [c++]大数运算1---利用C++ string实现任意长度正小数、整数之间的加减法

    一.概述 本文属于大大维原创,未经笔者本人允许,严禁转载!!! C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-429496 ...

  2. 求任意长度数组的最大值(整数类型)。利用params参数实现任意长度的改变。

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. 收藏的一段关于java大数运算的代码

    收藏的一段关于java大数运算的代码: package study_02.number; import java.math.BigDecimal; import java.math.BigIntege ...

  4. [PKU2389]Bull Math (大数运算)

    Description Bulls are so much better at math than the cows. They can multiply huge integers together ...

  5. java 大数运算[转]

    用JAVA 实现算术表达式(1234324234324 + 8938459043545)/5 + 343434343432.59845 因为JAVA语言中的long 定义的变量值的最大数受到限制,例如 ...

  6. A+B大数运算

    基础加法大数运算: [https://vjudge.net/problem/HDU-1002] 题目: 输入两个长度不超过1000的整数求出sum. 思路: 由于数字很大不能直接加,用字符串形式输入, ...

  7. HOJ 2148&POJ 2680(DP递推,加大数运算)

    Computer Transformation Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4561 Accepted: 17 ...

  8. 九度OJ 1119:Integer Inquiry(整数相加) (大数运算)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:679 解决:357 题目描述: One of the first users of BIT's new supercomputer was ...

  9. lua实现大数运算

    lua实现的大数运算,代码超短,眼下仅仅实现的加减乘运算 ------------------------------------------------ --name: bigInt --creat ...

随机推荐

  1. layui 根据根据后台数据动态创建下拉框并同时默认选中

        第一步 form表单里写好一个下拉框 <div class="layui-form-item"> <label class="layui-for ...

  2. dedecmsV5.7和discuz!X3.4整合之后免激活登陆

    问题:dedecmsv5.7和discuz!X3.4整合之后,从dede过去的用户,第一次登陆discuz!X3.4,需要激活.后来我就上百度了一番,找到了一个方法 我找到的方法: 1.在dedecm ...

  3. CF-551-D-树dp/思维

    http://codeforces.com/contest/1153/problem/D 给出一颗有根树,叶子节点可以从1开始赋值但不能相同,每个节点有一个属性max/min表示选择所有儿子值中的ma ...

  4. JQuery的常用选择器 转

    JQuery的常用选择器 刚开始学JQuery写的如有错误欢迎批评指正 JQuery拥有的选择器可以让我们更快更方便找到想要的元素,然后对相应的元素进行操作 简单介绍一下一些常用的选择器: 1.基本选 ...

  5. jquery等待特定元素加载再执行相关函数

    jQuery.fn.wait = function (func, times, interval) { var _times = times || 100, //100次 _interval = in ...

  6. Linux 下各文件夹的含义

    /bin 该目录中存放Linux的常用命令./boot 该目录默认下存放的是Linux的启动文件和内核./cdrom 该目录在刚安装系统时是空的,你可以将光驱文件系统挂在这个目录下./dev 该目录包 ...

  7. python----数据驱动@ddt.file_data结合yaml文件的使用

    一.创建yaml文件1. 安装yaml模块 pip install pyyaml2. 新建yaml文件 右键任意文件夹-->New-->File,输入文件名并以.yaml或.yml结尾 二 ...

  8. git操作大全

    分支克隆 1. git clone [git路径] #克隆仓库代码 2. git clone [Git路径] -b [分支name] #克隆仓库下某分支代码 查看分支 1.git branch #查看 ...

  9. day 11 装饰器

    1.day 10 内容复习 # 之前做得的题 以后再遇到能保证会 # 下周二考 :所有的知识 # 面试题:认真对待 # # 三元运算符 # 接收结果的变量 = 条件为真的结果 if 条件 else 条 ...

  10. c++中各类型数据所占字节数(二)

    转自:https://blog.csdn.net/allen_tony/article/details/76973906 https://blog.csdn.net/zzwdkxx/article/d ...