[c++]大数运算---利用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++]大数运算---利用C++ string实现任意长度正小数、整数之间的加减法的更多相关文章
- [c++]大数运算1---利用C++ string实现任意长度正小数、整数之间的加减法
一.概述 本文属于大大维原创,未经笔者本人允许,严禁转载!!! C/C++中的int类型能表示的范围是-2E31-2E31–1.unsigned类型能表示的范围是0-2E32–1,即 0-429496 ...
- 求任意长度数组的最大值(整数类型)。利用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 ...
随机推荐
- python两个列表合并为字典,一个作为key,一个作为value
两个列表合并为一个字典函数list_dic(list1,list2)可以直接复制拿走 传入的参数为两个列表,list1准备作为key,list2准备作为value,key和value位置一一对应. d ...
- shift and算法
1. CF 914F Substrings in a String 大意: 给定一个串s, q个询问, (1)单点修改, (2)询问[l,r]范围内串y的出现次数. shift and算法板子题 #p ...
- BUAA_OO第二单元作业总结——多线程
OO第二单元作业总结——多线程 单元任务 本单元主要的内容是通过模拟电梯的运行来熟悉多线程的实现,从简单的单部FAFS电梯开始,ALS电梯,到最后的多部ALS电梯. 一.设计策略分析总结 1.1 多线 ...
- mui底部选项卡切换实现
MUI提供了两种webview和div模式,来实现底部选项卡切换 效果相同,div是在同一个页面实现所有切换块的页面,根据id导航,而webview是由多个页面组成,形成页面之间的来回跳转
- Oracle数据加载和卸载
一. 平面文件卸载数据泵卸载 EXP/IMP; EXPDP/IMPDP sqlldr的两种模式:传统路径直接路径 控制文件:INSERT.APPEND.TRUNCATE.REPLACE 1.定界数据2 ...
- java Arrays.asList方法注意事项
1. 简介 Arrays.asList()方法可以将数组转化为长度固定的列表. 该方法强调了列表的长度是固定的,因此不能使用list的add和remove方法修改list长度. 2. 示例 impor ...
- vue-组件注册
<div id="app-7"> <ol> <!-- 现在我们为每个 todo-item 提供 todo 对象 todo 对象是变量,即其内容可以是动 ...
- lumion物体系统,导入模型6.3
选择物体后可以改变它的颜色 “导入”“导入新模型.”su中模型分正面反面.在lumion中显示是不一样的.正面是可以显示出来的,反面就是透明的,lumion只能识别不同的材质,所以在su中要用不同的颜 ...
- 关于html的基础标签
html: 超文本标记语言 h1 -- h6: 标题标签 一级标题,一个页面中只能存在一个h1 数字越大,标题的级别越小br:换行p:段落 自带换行,前后自带间隙a::::href属性---指定将要跳 ...
- 使用java命令出现Error: A JNI error has occurred, please check your installation and try again的错误
运行Java程序,javac运行.java文件没有报错,但java运行的时候报错 仔细看一下报错 Exception in thread "main" java.lang. ...