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

一、概述

  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. /*
  2. 大数的运算1--加法:
  3. 利用C++ string实现任意长度正小数、整数之间的加减法
  4. 作者:大大维
  5. 2017/5/5
  6. */
  7. #include<iostream>
  8. #include<string>
  9. #include<cctype>
  10. #include<algorithm>
  11. using namespace std;
  12. string sum(string,string,string,string);
  13. string sub(string,string,string,string);
  14. int main()
  15. {
  16. string num1,num2;
  17. cout<<"Input num1 , num2:"<<endl;
  18. cin>>num1>>num2;
  19. string num11,num12,num21,num22;
  20. //输入检查
  21. //是否是小数的标志
  22. bool num1Flag=false,num2Flag=false;
  23. for(auto c:num1)
  24. {
  25. //由数字或者数字加一个.组成
  26. if(!isdigit(c)||num1.empty())
  27. {
  28. if(c=='.'&&!num1Flag)
  29. {
  30. num1Flag=true;
  31. }
  32. else
  33. {
  34. cout<<"num1: Please input correct form!!!"<<endl;
  35. return ;
  36. }
  37. }
  38. }
  39. for(auto c:num2)
  40. {
  41. if(!isdigit(c)||num2.empty())
  42. {
  43. if(c=='.'&&!num2Flag)
  44. {
  45. num2Flag=true;
  46. }
  47. else
  48. {
  49. cout<<"num2: Please input correct form!!!"<<endl;
  50. return ;
  51. }
  52. }
  53. }
  54.  
  55. //字符串分割{整数部分和小数部分)
  56. if(num1Flag)//如果是小数
  57. {
  58. int i=;
  59. while(i!=num1.size()&&num1[i]!='.')
  60. {
  61. num11+=num1[i];
  62. ++i;
  63. }
  64. while(++i!=num1.size())
  65. {
  66. num12+=num1[i];
  67. }
  68. //用于.XXX或XXX.型输入的控制
  69. if(num11.empty())
  70. num11+='';
  71. if(num12.empty())
  72. num12+='';
  73. }
  74. else//如果是整数
  75. {
  76. num11=num1;
  77. num12+='';
  78. }
  79. if(num2Flag)//如果是小数
  80. {
  81. int i=;
  82. while(i!=num2.size()&&num2[i]!='.')
  83. {
  84. num21+=num2[i];
  85. ++i;
  86. }
  87. while(++i!=num2.size())
  88. {
  89. num22+=num2[i];
  90. }
  91. //用于.XXX或XXX.型输入的控制
  92. if(num21.empty())
  93. num21+='';
  94. if(num22.empty())
  95. num22+='';
  96. }
  97. else//如果是整数str
  98. {
  99. num21=num2;
  100. num22+='';
  101. }
  102.  
  103. cout<<"The Sum result = "<<sum(num11,num12,num21,num22)<<endl;
  104. cout<<"The Sub result = "<<sub(num11,num12,num21,num22)<<endl;
  105. }
  106.  
  107. //加法 较长的整数部分 较长的小数部分 较短的整数部分 较短的小数部分
  108. string sum(string strLong1,string strLong2,string strShort1,string strShort2)
  109. {
  110. //小数部分计算
  111. if(strLong2.size()<strShort2.size())
  112. {
  113. string strTemp=strLong2;
  114. strLong2=strShort2;
  115. strShort2=strTemp;
  116. }
  117. //补0
  118. for(int i=strShort2.size(); i<strLong2.size(); ++i)
  119. strShort2+='';
  120. //反转字符串
  121. reverse(strLong2.begin(),strLong2.end());
  122. reverse(strShort2.begin(),strShort2.end());
  123. //小数部分进行加法计算
  124. string strRes2(strLong2.size(),'');
  125. int carry=;//进位
  126. for(int i=; i!=strLong2.size(); ++i)
  127. {
  128. int a=strShort2[i]-'',b=strLong2[i]-'';
  129. a=a+b+carry;
  130. carry=a/;
  131. strRes2[i]=(a%)+'';
  132. }
  133. //反转回来
  134. reverse(strRes2.begin(),strRes2.end());
  135.  
  136. //整数部分计算
  137. if(strLong1.size()<strShort1.size())
  138. {
  139. string strTemp=strLong1;
  140. strLong1=strShort1;
  141. strShort1=strTemp;
  142. }
  143. //反转字符串
  144. reverse(strLong1.begin(),strLong1.end());
  145. reverse(strShort1.begin(),strShort1.end());
  146.  
  147. string strRes1(strLong1.size(),'');
  148. for(int i=; i!=strShort1.size(); ++i)
  149. {
  150. int a=strShort1[i]-'',b=strLong1[i]-'';
  151. a=a+b+carry;
  152. carry=a/;
  153. strRes1[i]=(a%)+'';
  154. }
  155. for(int i=strShort1.size(); i!=strLong1.size(); ++i)
  156. {
  157. int b=strLong1[i]-'';
  158. b+=carry;
  159. carry=b/;
  160. strRes1[i]=b%+'';
  161. }
  162. if(carry)
  163. {
  164. strRes1+=(carry+'');
  165. }
  166. //反转回来
  167. reverse(strRes1.begin(),strRes1.end());
  168.  
  169. //合并整数部分和小数部分
  170. string strRes=strRes1+'.'+strRes2;
  171. return strRes;
  172. }
  173.  
  174. //减法 被减数的整数部分 被减数的小数部分 减数的整数部分 减数的小数部分
  175. string sub(string strBjs1,string strBjs2,string strJs1,string strJs2)
  176. {
  177. //小数部分进行减法计算
  178. int cntTemp=strBjs2.size()-strJs2.size();
  179. //补0
  180. if(cntTemp<=)
  181. {
  182. for(int i=cntTemp;i!=;++i)
  183. {
  184. strBjs2+='';
  185. }
  186. }
  187. else
  188. {
  189. for(int i=cntTemp;i!=;--i)
  190. {
  191. strJs2+='';
  192. }
  193. }
  194.  
  195. //反转字符串
  196. reverse(strBjs2.begin(),strBjs2.end());
  197. reverse(strJs2.begin(),strJs2.end());
  198. string strRes2(strBjs2.size(),'');
  199. int carry=;//进位
  200. for(int i=; i!=strBjs2.size(); ++i)
  201. {
  202. int a=strBjs2[i]-'',b=strJs2[i]-'';
  203. a=a-b-carry;
  204. if(a>=)
  205. {
  206. carry=;
  207. strRes2[i]=a+'';
  208. }
  209. else
  210. {
  211. carry=;
  212. strRes2[i]=a++'';
  213. }
  214. }
  215. //反转回来
  216. reverse(strRes2.begin(),strRes2.end());
  217.  
  218. //整数部分进行减法计算
  219. //反转字符串
  220. reverse(strBjs1.begin(),strBjs1.end());
  221. reverse(strJs1.begin(),strJs1.end());
  222. string strRes1(strBjs1.size(),'');
  223. for(int i=;i!=strJs1.size();++i)
  224. {
  225. int a=strBjs1[i]-'',b=strJs1[i]-'';
  226. a=a-b-carry;
  227. if(a>=)
  228. {
  229. carry=;
  230. strRes1[i]=a+'';
  231. }
  232. else
  233. {
  234. carry=;
  235. strRes1[i]=a++'';
  236. }
  237. }
  238. for(int i=strJs1.size();i!=strBjs1.size();++i)
  239. {
  240. int a=strBjs1[i]-'';
  241. a=a-carry;
  242. if(a>=)
  243. {
  244. carry=;
  245. strRes1[i]=a+'';
  246. }
  247. else
  248. {
  249. carry=;
  250. strRes1[i]=a++'';
  251. }
  252. }
  253. if(carry)//此时除数比被除数大,结果为负数
  254. {
  255. return "*";
  256. }
  257. //反转回来
  258. reverse(strRes1.begin(),strRes1.end());
  259.  
  260. //清楚冗余0
  261. string strTemp;
  262. cntTemp=;
  263. for(int i=;strRes1[i]=='';++i)++cntTemp;
  264. for(int i=cntTemp;i!=strRes1.size();++i)
  265. strTemp+=strRes1[i];
  266. strRes1=strTemp;
  267. //合并整数部分和小数部分
  268. string strRes=strRes1+'.'+strRes2;
  269. return strRes;
  270. }

四、运行结果截图:

说明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. python 学习笔记 5 ----> dive into python 3

    字符串 文本:屏幕上显示的字符或者其他的记号 计算机认识的东西:位(bit)和字节(byte) 文本的本质:某种字符编码方式保存的内容. 字符编码:一种映射(显示的内容  ----> 内存.磁盘 ...

  2. 在Mac os 10.11 下编译Berkeley caffe

    安装各种补丁和组件,缺啥装啥. python 采用 2.7.13 最新版. 安装工具  homebrew , pip 很繁琐,但是没难度. 由于本人macbook pro不支持CUDA,所以不用安装. ...

  3. Visual Studio 删除空行

    Visual Studio 没有提供此功能,只能用正则表达式,具体做法如下: 一.ctrl+ H 打开替换框 二.在替换框中的源中输入 ^(?([^\r\n])\s)*\r?$\r?\n 图如下: 完 ...

  4. 李航《统计学习方法》CH01

    CH01 统计学方法概论 前言 章节目录 统计学习 监督学习 基本概念 问题的形式化 统计学习三要素 模型 策略 算法 模型评估与模型选择 训练误差与测试误差 过拟合与模型选择 正则化与交叉验证 正则 ...

  5. 跟随我在oracle学习php(15)

    开发环境 独立开发环境:组成 Windows/Linux php Apache MySQL 集成开发环境:phpstudy wamp xammp 关系数据库: SQL: Struct Query La ...

  6. JAVA实现简单的四则运算

    GitHub 项目地址 https://github.com/745421831/-/tree/master PSP PSP2.1 Personal Software Process Stages 预 ...

  7. Rhino学习教程——1.5

    图形面板 图形面板是Rhino为了方便用户操作设置的一个区域,默认提供了“属性”.“图层”.“说明”3个面板(我自定义过了,新增了一个“显示”功能 ). trip:如果要打开更多的图版,可以点击图形面 ...

  8. 记-统计svn与git的log日志中的代码行变更

    任务要求 统计指定时间内,指定git地址与svn地址上的所有人员的代码行变更情况. 解决方案 最初为根据数据库中存储的所有git与svn地址来统计所有人员的提交代码行.之后由于库中存储的地址不全,改为 ...

  9. aspectj编程简介

    现在java生态中spring大行其道,一般使用aspectj进行切面编程使用注解方式实现,比较少使用原生的aspectj编程,网上的资料也比较少.最近工作中需要封装redisson客户端提供统一的r ...

  10. 微信小程序-解决下拉刷新报错

    关于“enablePullDownRefresh”: “true” 一.使用方式 在 Page 中定义 onPullDownRefresh 处理函数,监听该页面用户下拉刷新事件.需要在 config ...