一.为什仫要实现大数运算?
我们知道在数学领域中,数值的大小是没有上限的,但是计算机中,由于字长的限制,计算机所能表示的范围是有限的,当我们在实际的应用中进行大量的数据处理的时候,会发现参与运算的数往往超过计算机的基本数据类型的表示范围。假设一个数据的类型是long long那仫它最多可表示的数据是8个字节,一但超出这个范围,就无法用编程语言的内置类型存储,因此就产生了大数运算这种方法。
二.大数运算是如何实现的?
1).将大数转换成字符串存储在数组里面,然后再对每一位做单独的加减乘除运算。
2).设计一个大数的数据类型,让这种数据类型既可以进行大数的运算,也可以支持没有超出内置类型范围的数的运算。
3).当然了如果数据本身就没有超出范围当然就不需要每一个位都计算啦!如果要运算的数可以用内置类型表示,且计算结果也可以用内置类型表示,那么我们就直接进行运算。如果要运算的数超出范围,或者计算结果超出范围,那么我们就使用大数的运算法则。
三.代码实现
1).首先需要的是将一个大数存储起来,当然要处理不合理的情况啦,感觉有点模拟atoi的感觉!!!
@空串
@是否存在空白字符,如果全部是空白字符
@是否存在’+’或者是’-‘号
@是否存在字符’0’,如果全部是字符’0’
@是否存在非数字字符

BigData::BigData(const std::string& str):_value(0),_strData("+0")
{//空串if(str.empty())return ;char *pData=(char *)str.c_str();//跳过空格while(isspace(*pData)){pData++;}//可能一个串全部是空格if(*pData == '\0')return ;//确定符号位char sign=*pData;if(*pData == '+' || *pData == '-')pData++;else if(isdigit(*pData))sign='+';elsereturn ;//可能前面存在字符0while(*pData == '0'){pData++;}//全0if(*pData == '\0')return ;_strData.resize(strlen(pData)+1);_strData[0]=sign;   //第一位存放符号位size_t count=1;//如果是数字则在_value和_strData中都保存一份while(*pData >= '0' && *pData <= '9'){_value=_value*10+*pData-'0';_strData[count++]=*pData;pData++;}if(sign == '-')_value=0-_value;_strData.resize(count);  //缩小当前的空间大小
}

2).判断数据是否溢出
如果数据的大小在long long所能表示的8个字节的范围内则可以直接计算,如果超出了呢?则需要自定义处理,如何判断是否超出?

//判断数据是否溢出
bool BigData::IsINT64OverFlow(const string& strData)
{const string maxValue="+9223372036854775807";const string minValue="-9223372036854775808";if(strData.size() < maxValue.size())return false;else if(strData.size() == maxValue.size()){if(strData[0] == '+' && strData <= maxValue \|| strData[0] == '-' && strData >= minValue)return false;}return true;
}

3).大数运算

BigData BigData::operator+(const BigData& b)
{if(!IsINT64OverFlow(_strData) && !IsINT64OverFlow(b._strData)){if(_strData[0] != b._strData[0]) //两个数字异号的话直接相加{return BigData(_value+b._value);}else if(_strData[0] == '+' && MaxValue-_value >= b._value || \_strData[0] == '-' && MinValue-_value <= b._value){return BigData(_value+b._value);}}if(_strData[0] == b._strData[0])   //同号相加,调用Add函数{return BigData(Add(_strData,b._strData));}else{//异号相加转化为正数相减string left=_strData;string right=b._strData;left='+';right='+';if(_strData[0] == '-')std::swap(left,right);return BigData(Sub(left,right));}
}BigData BigData::operator-(const BigData& b)
{if(_strData[0] == b._strData[0])   //同号的话直接相减return Sub(_strData,b._strData);return BigData(Add(_strData,b._strData));  //异号
}BigData BigData::operator*(const BigData& b)
{if(_strData == "+0" || b._strData == "+0")return BigData(0);if(!IsINT64OverFlow(_strData) && !IsINT64OverFlow(b._strData)){INT64 maxValue=9223372036854775807;INT64 minValue=0-9223372036854775808;if(_strData[0] == b._strData[0])   //同号{if((_strData[0] == '+' && maxValue / _value >= b._value) || \(_strData[0] == '-' && maxValue / _value <= b._value))return _value*b._value;}else  //异号{if(_strData[0] == '+' && minValue / _value <= b._value || \_strData[0] == '-' && minValue / _value >= b._value)return BigData(_value*b._value);}}//判断是否存在正负1的情况if(_strData[0] == '+1')return BigData(b._strData);if(b._strData[0] == '+1')return BigData(_strData);if(_strData[0] == '-1'){string tmp=b._strData;if(b._strData[0] == '-')  //- -tmp[0]='+';else   // - +tmp[0]='-';return BigData(tmp);}if(b._strData[0] == '-1'){string tmp=_strData;if(_strData[0] == '-') //- -tmp[0]='+';else  //+ -tmp[0]='-';return BigData(tmp);}return BigData(Mul(_strData,b._strData));
}BigData BigData::Add(string left,string right)
{size_t leftsize=left.size();size_t rightsize=right.size();if(rightsize > leftsize)   //始终保持左边的数据比右边的数据大{std::swap(left,right);std::swap(leftsize,rightsize);}string result;result.resize(leftsize+1);result[0]=left[0];//保存符号char step=0;      //保存进位for(size_t index=1;index<leftsize;++index){char ret=left[leftsize-index]-'0';if(index < rightsize)ret=ret+right[rightsize-index]-'0';ret += step;step=ret/10;    //更新进位的值,取较高位result[leftsize+1-index]=ret%10+'0';}result[1]=step+'0'; //相加到最后一位也有可能产生进位return result;
}BigData BigData::Sub(string left,string right)
{char sign=left[0];size_t leftsize=left.size();size_t rightsize=right.size();if(leftsize < rightsize || leftsize == rightsize && left < right)  //总是左边的小{if(right[0] == '+')sign='-';elsesign='+';std::swap(left,right);std::swap(leftsize,rightsize);}string result;result.resize(leftsize);result[0]=sign;for(size_t index=1;index<leftsize;++index){char ret=left[leftsize-index]-'0';if(index < rightsize)ret=ret-(right[rightsize-index]-'0');if(ret < 0)  //减出的结果为负数,从高位借位,以1当10{left[leftsize-index-1] -= 1;ret += 10;}result[leftsize-index]=ret+'0';}return result;
}BigData BigData::Mul(string left,string right)
{//确定最终结果的符号位char sign='+';if(left[0] != right[0])sign='-';size_t leftsize=left.size();size_t rightsize=right.size();//确保左边数的长度小于右边数据的长度if(leftsize > rightsize){std::swap(left,right);std::swap(leftsize,rightsize);}string result;result.resize(leftsize+rightsize-1,'0');result[0]=sign;char step=0;    //存储进位char iOffset=0; //存储偏移量//乘法的原理是获取左边的一位数据分别乘以另一个数的每一位,所以用到两个循环for(size_t i=1;i<leftsize;++i){char tmp=left[leftsize-i]-'0';if(tmp == 0)   //过滤掉中间的0{iOffset++;continue;}step=0;     //进位的值归零for(size_t j=1;j<rightsize;++j){char ret=tmp*(right[rightsize-j]-'0');ret += step;ret = ret + (result[leftsize+rightsize-1-j-iOffset]-'0');step=ret/10;   //跟新进位的值result[leftsize+rightsize-1-j-iOffset]=ret%10+'0';}result[leftsize-iOffset-1] = step+'0';iOffset++;}return result;
}

在大数运算里面我觉得除法是最不好理解的,下面是我画的一个除法的原理图:

由上图可知,我用了一个指针pleft+dataLen来查找一个能够除过除数的数,使用循环递减的方法来确定商。
商*除数+余数=最终结果,来判断计算结果是否正确。

BigData BigData::Div(string left,string right)
{char sign='+';if(left[0] != right[0])sign='-';size_t leftsize=left.size();size_t rightsize=right.size();char *pleft=(char *)left.c_str()+1;char *pright=(char *)right.c_str()+1;size_t dataLen=0;string tmp;tmp.append(1,sign);  //存放符号位while(*(pleft+dataLen-1) != '\0'){if(*pleft == '0')  //将数据高位出现的0过滤掉{pleft++;tmp.append(1,'0');continue;}if(!IsLeftLarge(pleft,dataLen,pright,rightsize-1)){tmp.append(1,'0');dataLen++;}else{tmp.append(1,SubLoop(pleft, dataLen, pright, rightsize)+'0');dataLen++;}}return tmp;
}//判断是否左边大
bool BigData::IsLeftLarge(const char *pleft,const size_t dataLen,const char *pright,const size_t rightsize)
{if(dataLen > rightsize)return true;else if(dataLen == rightsize){if(strncmp(pleft,pright,dataLen) >= 0)return true;}return false;
}char BigData::SubLoop(char*& pleft, size_t& dataLen, const char *pright,const size_t rightsize)
{char count = 0;//确保左边大于右边while (IsLeftLarge(pleft,dataLen,pright,rightsize-1)){for (size_t index=1;index<=dataLen;index++){char ret=pleft[dataLen-index]-'0';if (index < rightsize){ret -= pright[rightsize-index-1]-'0';}if (ret < 0)  //向高位借位,以1当10{pleft[dataLen-index-1] -= 1;ret += 10;}pleft[dataLen-index]=ret+'0';}count++;while (*pleft == '0' && dataLen > 0)  //跳过高位的0{pleft++;dataLen--;}}return count;
}

点击查看源码

模拟计算器的简单实现相关推荐

  1. Java制作一个盒子程序_编写一个简单的Java程序,模拟计算器的功能。

    提问:编写一个简单的Java程序,模拟计算器的功能. 网友回答: 程序参考: import java.awt.*; import java.awt.event.ActionEvent; import ...

  2. 最简单的用js模拟计算器进行计算(初级)

    用js模拟计算器进行计算 今天我们来讲一下怎么使用js来模拟计算器的加减乘除基本运算.代码如下: HTML代码: <h1>计算器</h1><input type=&quo ...

  3. c语言计算器实训任务案例,C/C++经典实例之模拟计算器示例代码

    前言 本文主要给大家介绍了关于利用C/C++如何实现模拟计算器的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. Problem Description 简单计算器模拟:输入 ...

  4. 【蓝桥杯】【入门题】【算法提高VIP】1480:模拟计算器

    题目 1480:模拟计算器 蓝桥杯刷题群已成立,微信后台回复[蓝桥杯],即可进入. 如果加入了之前的社群不需要重复加入. 时间限制: 1Sec 内存限制: 128MB 1. 题目描述 使用Switch ...

  5. 模拟计算器进行四则运算(同等优先级)(内测第2届第3题)

    题目要求 问题描述:模拟计算器进行四则运算.假设只有+.-.*./.=五种运算符,且它们优先级相等.输入=后会显示计算结果. 样例输入:8.5+0.5*2.5= 样例输出:22.5 解决方案 比起需要 ...

  6. 7-105 sdut-C语言实验——三个数排序7-106 sdut-C语言实验——模拟计算器7-107 sdut-C语言实验——找中间数

    目录 7-105 sdut-C语言实验--三个数排序 7-106 sdut-C语言实验--模拟计算器 7-107 sdut-C语言实验--找中间数 7-105 sdut-C语言实验--三个数排序 分数 ...

  7. PTA 7-106 sdut-C语言实验——模拟计算器

    PTA 7-106 sdut-C语言实验--模拟计算器 分数 12 作者 马新娟 单位 山东理工大学 简单计算器模拟:输入两个整数和一个运算符,输出运算结果. 输入格式: 第一行输入两个整数,用空格分 ...

  8. python计算器总结_Python 计算器的简单示例

    这篇文章主要为大家详细介绍了Python 计算器的简单示例,具有一定的参考价值,可以用来参考一下. 对python这个高级语言感兴趣的小伙伴,下面一起跟随512笔记的小编两巴掌来看看吧! 简介 在这篇 ...

  9. JAVA同时输入用户名和密码_用java模拟设计一个简单的“用户注册”程序。当用户输入用户名和密码时,单击“注...

    用java模拟设计一个简单的"用户注册"程序.当用户输入用户名和密码时,单击"注 2020 - 9 - 26 TAG : 所有功能均已实现,如有不满意的地方我再修改imp ...

最新文章

  1. threshold 二值化的实现
  2. 费马定理中值定理_数论-欧拉函数、欧拉定理
  3. Linux进程间通信中的文件和文件锁
  4. java 程序执行后 强制gc_【GC系列】JVM的常用GC参数及GC日志解析
  5. go build编译不同环境
  6. 阿里云数据库mysql 创建数据库服务器_如何使用mysql创建数据库服务器
  7. ROS入门 小乌龟跟随示例
  8. 简单poi创建execl
  9. Python爬虫从入门到放弃(二十一)之 Scrapy分布式部署
  10. yuicompressor java_YUI Compressor
  11. [不好分类]《凤凰项目》读后感
  12. 【教你几种禁止修改IP的方法】
  13. python输入多个数用逗号隔开、计算平均值_python实现输入五个数并求平均值
  14. 我买了个5g手机,但是手机卡是4g的,能使用吗?
  15. 安卓流畅度测试方法二:FPS Meter测试安卓帧数
  16. 什么是线程安全 什么是线程不安全
  17. Excel高级图表之四象限图制作
  18. 【时间复杂度】你还在担心时间复杂度太高吗?
  19. Ubuntu系统安装、配置与美化(Ubuntu20.04)
  20. Web前端 | HTML表单form

热门文章

  1. 虚拟机VMWARE安装win7没有网卡声音等问题解决记录
  2. python作业 银行(定义一个账户类,可以创建账户,存款,取款,查询余额,以及销户等操作)
  3. 一个门店省市店名三级联动
  4. 水培郁金香流程和记录
  5. python计算机语言论坛,自学IT吧论坛国外大神-计算机科学及 Python 编程导论-中文字幕编程语言资源天地 - www.zxit8.com...
  6. 2020 Top10计算机视觉论文总结:论文,代码,解读,还有demo视频!
  7. 细数荧幕中令人痛恨的十大反派
  8. 百度Ueditor富文本编辑器修改上传图片的默认路径绝对能用,并且回显,并且超级简单,超级详情,有用点赞好评!
  9. 求生之路linux和windows,《求生之路2》在Linux系统下运行比WIN7流畅
  10. 2021年互联网影视峰会!原创报道,Adobe国际认证助力摄影前途