[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 ...
随机推荐
- 浅析Thread类run()和start()的区别
1.先看看jdk文档 void run() If this thread was constructed using a separate Runnable run object, then that ...
- 【Azure】Azure学习方法和学习资料
学习方法: DEX为入门培训,fundamental book进阶材料,Azure 官方为补充权威材料,网站一些大拿的Blog是很多实践精华,推荐阅读. 推荐教材和学习内容: EDX培训:http:/ ...
- 一个简单的jquery左右列表内容切换应用
选中左边某个选项点击添加,即可将选中项添加到右边文本框中,点击选中全部即可将全部选项移到右边,移除按钮功能相同. html代码: <div id="main"> < ...
- 启动LUXContentTests过程中遇到的问题
首先,要想在localbox中使用Selenium,就得准备好浏览器的driver文件.比如chrome对应的chromedriver文件,该文件是一个exe可执行文件. 问题:当我尝试去跑LUXCo ...
- stm32中断学习总结
经过了两天,终于差不多能看懂32的中断了,由于是用的库函数操作的,所以有些内部知识并没有求甚解,只是理解知道是这样的.但对于要做简单开发的我来说这些已经够了. 我学习喜欢从一个例程来看,下面的程序是我 ...
- CF #284 div1 D. Traffic Jams in the Land 线段树
大意是有n段路,每一段路有个值a,通过每一端路需要1s,如果通过这一段路时刻t为a的倍数,则需要等待1s再走,也就是需要2s通过. 比较头疼的就是相邻两个数之间会因为数字不同制约,一开始想a的范围是2 ...
- oracle 归档日志满 报错ORA-00257: archiver error. Connect internal only, until freed
归档日志满导致无法用户无法登陆 具体处理办法 --用户登陆 Microsoft Windows [Version 6.1.7601] Copyright (c) Microsoft Corporati ...
- AOJ/搜索递归分治法习题集
ALDS1_4_A-LinearSearch. Description: You are given a sequence of n integers S and a sequence of diff ...
- 关于div+css布局值得注意的地方
注意项 我们知道,如果想要两个 div(即块级元素)挨着一起排列,可以将其设置为inline-block(行内-块元素). 不过要注意两个div内的内容的对齐方式将是垂直中间对齐,所以这时候就需要使用 ...
- 蓝桥杯-立方尾不变-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...