大数科学计算器 C++

打印 上一主题 下一主题

主题 552|帖子 552|积分 1656

大数计算器


目录

优点


  • 实现了任意大数字计算 突破了longlong的-92233720368547758089223372036854775807的限制
  • MyNum类的实现 尤其是内部数据成员的使用思路  是程序的关键也是核心部分  同样的数据结构能实现三种不同的功能
  • MyNum类的存储方式受到了IEEE754标准下浮点数存储方式的启发
  • 可以判断逻辑条件表达式  例如 1+1 >= 2 返回TRUE
  • 计算的时候可自定义精度
  • 输出可自定义精度 实现四舍五入 (这个跟上一点不重复  比如最后的答案是0.00079 我就可以输出0.0008  但这并不改变这个数字是0.00079的事实 只是输出变了)
  • 计算过程中运用了后缀表达式法也就是逆波兰表达式法 实现了优先级计算
  • 重载了+-*/^等基础运算符  大大提高代码可读性以及复用性
  • 自定义函数有很多使用了自定义实现

    • 对于三角函数 e^x函数 等一些函数 舍弃了库自带的函数  选择了利用泰勒展开数学迭代法进行自定义实现
    • 针对三角函数不但有泰勒展开 还进行了π优化 (比如27.75π化为1.75π) 大大提高精确度
    • 对于求幂指数符号^  实现了小数指数幂的计算(可以计算 20.412^9.423 这种复杂式子)
      内部思路是 指数拆为整数+小数  整数部分运用快速幂算法进行优化  小数部分运用log()函数以及泰勒展开进行求解
    • 实现了最小公倍数lcm 最大公约数gcd 这些有多个参数的多目函数  其中的算法是辗转相除法

  • 实现了查询历史记录功能  输入history即可查询本次运行期间运算的记录
  • 实现了多重错误输出功能  不然可以输出程序错误 而且同时产生多重错误时可以全部输出
实现思路

自定义类

运用C++ 类的封装  自定义了两个类: MyNum类 和 Method类
下面是这两个大类的简单归纳总结
MyNum类  ★★★


  • MyNum类起到三种作用: 1. 存放单个数字  2. 存放计算符号与函数(在计算时候的后缀表达式有大用处)  3.作为错误ERROR并且可以指示是何种错误
  • 内部数据成员
    1. std::deque<int> digits;
    2. int power;
    3. int sign;
    复制代码
    这个数据结构存储很有说法  哥们很引以为豪啊  虽然后面写函数的时候常常猪脑过载
    同样的三个数据成员  在三种不同作用的时候分别担任三种不同的工作  这三种不同作用是按照sign的值来区分的

    • 当MyNum作用是存放单个数字时 sign == -1 0 1 分别表示 负数,零和正数
      这个时候为了使MyNum既能表示整数也能表示小数 而且还要满足大数的要求
      首先存储数字使用了std::deque这个双向队列数据结构  他用起来的时候跟普通的数组差不多  而且比他功能更强大 所以就没用std::vector了 因为这个能存很多数字 所以就能实现大数的要求  不过之后的运算全都必须数组运算
      然后就是这个数据结构的思路  思路启发是IEEE754标准下的浮点数表示法:

      模仿的结果就是
      将一个数字abcde.fghij 表示成 0.abcdefghij * 10 ^ power 的形式
      跟IEEE一样并非传统的科学计数法(在小数点的前面留一个数字)  之前学的时候我不理解为什么 现在做这个计算器明白了
      IEEE舍弃掉整数位因为必定是1  但除此以外其实还有个好处
      如果是 0.xxxx 而不是 x.xxx 的话 这个指数power就很有用
      0.000233 = 0.233 * 10 ^ -3      指数 -3 拿出来可以瞬间知道 0.000233的小数点后面有3个0
      2333.3333 = 0.23333333 * 10 ^ 4  指数 4 拿出来可以瞬间知道 2333.3333的小数点前面有4位数
      std::deque digits 存放"有效数字" (不包括开头和末尾的所有0  比如1000只存个1 方便后续运算  所以不是数学上真正意义的有效数字)
      int power 存放指数
    • 当MyNum作用是存放计算符号和函数的时候  sign == 2
      这个时候 刚刚是存放有效数字的digits摇身一变 变成了存放符号名称的东西
      比如乘法符号 '*'  digit里面就是一个单独的{ '*' }   把char类型转换为int存进去
      如果是函数类型的计算  比如 log 函数  那digit里面就是 { 'l', 'o', 'g' }  总之就是把名字给放进去
      digits 没啥好说的  最最最关键的是这时候的power
      power此时不再存放指数(因为计算符号哪里有什么指数)   而是存放这个运算的优先级!!!!   这个在之后的后缀表达式求计算式答案的时候有大大大用
      1. // 里面定义的各种符号优先级如下:
      2. -1: 左括号(
      3. 0:  各种逻辑判断符 >= < != 等         //对你没有看错 还能求逻辑运算式
      4. 1:  加减+-
      5. 2:  乘除*/       
      6. 3:  乘方^
      7. 4:  各种函数运算 比如对数log 开根sqrt 三角函数sincos等
      8. 5:  百分号%  //这个符号很迷其实 因为一般百分号是取模 但这里放优先级5是只让他求"百分之"的功能没有取模的功能  所以这里比较随意不严谨 之后可以优化一下
      复制代码
      他有什么好处呢?  后缀表达式那里就体现出来了
    • 当MyNum作用是作为错误ERROR的时候  sign == -2
      这个时候power没啥用(主要是我也不知道能给他啥用)   但digits就十分重要
      利用digits能像数组一样存储多个int的性质  我们给他存入类似于 {0,0,1,1,0,1,...}这些玩意儿  这是干啥的?
      这里   不同位置对应不同的错误类型  比如这个数组里面第3位是1 那么说明此时发生了第3种错误; 第5位是0说明没有第5种错误
      1. // 定义的各种错误类型顺序如下
      2. 0: 出现除以0
      3. 1: 出现0的0次幂
      4. 2: 出现负数的分数次幂                //因为负数分数次幂就可能导致虚数  我干脆全给禁了
      5. 3: 计算表达式非法                        //有可能是括号配对错了 有可能是数字多了 总之表达式算不出来结果
      6. 4: log函数出现非正底数                //就是ln(x)里面x必须大于0
      复制代码
      还可以加各种各样的错误  如果你有需要的就告诉我 我看看能不能加进来

    OK  以上就是MyNum类的数据成员的一些说法

  • 内置的一些函数

    • 构造函数 & 拷贝构造拷贝赋值析构三大函数
      主要都是提供方便
      其中最重要的是从字符串类型构造MyNum类型   因为丢进去的字符串可能是 "-233.333" 这种正常的数字  也可能是 "sin()" 这种函数计算符号 所以它要作区分并生成正确的MyNum对象
    • 数学函数
      都是sqrt()  fabs() 这种数学的函数  其中很多函数舍弃掉了头文件中现有的函数 选择了自定义实现  目的就是提高精度!
      有些函数例如三角函数 e^x自然指数函数 这怎么自定义实现呢?
      方法:  **泰勒展开!! **   利用迭代 计算出泰勒展开中每项 然后就能得到自己想要精度的结果
      这个详细的过程在后面讲到函数实现的时候再说吧 目前看一下成果:

      准确率还是可以的
    • 转换函数
      就是MyNum类转换到其他类 比如什么int啊double啊啥的 主要也就是为了方便才整的  有要提的之后具体展开到函数实现再说
    • 运算符重载
      实现计算的时候肯定是用 + * 这些运算符来的方便  所以自定义的数字类必然要运算符重载
      也没啥太必要提的  还是之后函数实现细说 不过里面有关幂指数的^符号的实现比较有含金量一些
    • 显示函数
      就是输出到黑框框里面给人看的函数  也没啥重要的  函数实现再细说

Method类


  • Method类不像MyNum类有那么多功能  Method在数学上的意思是计算式表达式    Method类就是一个用来存储我们每一个计算式的类  比如6/3*(5+2.4-1)
  • 内部数据成员
    1. string calstr                       
    2. std::deque<MyNum> rpn
    3. int type                                //0 计算式  1 逻辑条件式
    4. MyNum ans                                //计算结果
    复制代码

    • string calstr:  就是calculate string  需要计算的原式 这个没啥特殊的  顶多就是输入的时候把输入的空格啥的给删了
    • std::deque rpn:  这个very的重要  这个rpn是 Reverse Polish Notation 逆波兰表示法/后缀表达式  我们后续的计算式求解思路 就是先把整个式子换成后缀表达式 然后进行求解
    • int type: 这个是用来指示这个计算式是什么个类型的  普通的计算式那就是算出个数字结果 但如果是1+1 >= 2这种逻辑式  就要把最后的1输出为"TRUE"  0就是"FALSE"  所以type就用0代表是计算式  1代表是逻辑条件式
    • MyNum ans: 这个更不用多说了  有计算式肯定要有结果的嘛  这个就是这个式子的结果

  • 内置的一些函数

    • 构造 & 三大函数
      没啥特殊的  过
    • 操作函数
      无非就是计算啊啥的
      不过里面最最最重要的  就是把原计算式转换为后缀表达式的那个函数  他是一切计算的起点 在之后函数实现的时候细说
    • 显示函数
      就是显示原式 显示答案之类的
      不过用户可以设定一个参数 来规定输出的类型  可以是简洁模式(按下回车之后只有答案)  也可以是详细模式(按下回车之后除了答案还能看到 原式以及原式变为的后缀表达式)
      除此以外 还可以在黑框框那边输入 setprecision 数字 来规定输出小数的精度  有四舍五入

具体函数实现

MyNum类的函数

构造 & 三大函数
  1. //构造函数
  2.         MyNum(const std::deque<int>& d=ZERODEQUE,int p=0,int s=0)
  3.                 :digits(d),power(p),sign(s){}
  4.         MyNum(int i);
  5.         MyNum(long long i);
  6.         MyNum(double d);
  7.         MyNum(std::string str);
  8. //拷贝构造拷贝赋值
  9.         MyNum(const MyNum& other)
  10.                 :digits(other.digits), power(other.power),sign(other.sign) {}
  11.         MyNum& operator= (const MyNum& other) {
  12.                 this->digits = other.digits;
  13.                 this->power = other.power;
  14.                 this->sign = other.sign;
  15.                 return *this;
  16.         }
复制代码
都比较普通  能拿出来说的也就是从字符串string构造MyNum
总体思路:

  • 判断string是否是类似 "fabs"的计算函数 或者 类似"+-*/"的计算符号

    • 如果是  那么sign赋值为2   表示这个MyNum是一个计算用的符号  接下来根据不同符号的不同优先级来定下MyNum中的power参数 接着把这个string变成int数组存进digits里面 这个在上面将MyNum的数据成员的时候细说过  如果忘了可以回去看看
    • 如果不是  说明这个string是个类似 "-233.333" 这样的数字 那么首先看正负定下sign  然后就要把有效数字放进digits 找到指数放进power里
      难点就在于定下指数power  可以把整数部分剥离开来  之后就好求digits了

源码:
  1. MyNum::MyNum(std::string str) {
  2.         if (str.size() && (str[0] < '0' || str[0]>'9')) {                //string不是数字是个计算符号
  3.                 if (!((str[0] == '-' || str[0] == '+') && str.size() > 1 && str[1] >= '0' && str[1] <= '9')) {
  4.                         this->sign = 2;
  5.                         if (str[0] >= 'a' && str[0] <= 'z' || str[0] >= 'A' && str[0] <= 'Z')         //函数类型计算  优先级4
  6.                                 power = 4;
  7.                         else {
  8.                                 if (str[0] == '(') power = -2;
  9.                                 if (str[0] == '=' || str[0] == '<' || str[0] == '>') power = 0;
  10.                                 if (str[0] == '+' || str[0] == '-') power = 1;
  11.                                 if (str[0] == '*' || str[0] == '/') power = 2;
  12.                                 if (str[0] == '^') power = 3;
  13.                                 if (str[0] == '%') power = 5;
  14.                                 if (str[0] == ',')        power = -1;                                //根据不同的符号 确定各自的优先级
  15.                         }
  16.                         for (int i = 0; i < str.size(); i++) {
  17.                                 this->digits.push_back(int(str[i]));                //将名字存进digits里面
  18.                         }
  19.                         return;
  20.                 }
  21.         }
  22.     //下面就是str表示的是数字情况
  23.         this->sign = 1;
  24.         int i = 0;
  25.         while (str[i] == ' ') i++;
  26.         if (str[i] == '-') {
  27.                 this->sign = -1; i++;
  28.         }
  29.         if (str[i] == '+') i++;
  30.         int retpower = 0;
  31.         bool startdigits = false;        //开始有效数字
  32.         int powerchange = 1;                //1表示每往后一格power++  -1就是小数情况
  33.         int ifdecimal = false;
  34.         bool ifmeetpoint = false;        //有无遇见小数点
  35.         while (i < str.size()) {
  36.                 if (startdigits && str[i]>='0' && str[i]<='9') {
  37.                         this->digits.push_back(str[i] - '0');
  38.                         if (!ifmeetpoint)
  39.                                 retpower++;
  40.                 }
  41.                 else {
  42.                         if (str[i] >= '1' && str[i] <= '9') {
  43.                                 startdigits = true;
  44.                                 this->digits.push_back(str[i] - '0');
  45.                                 if (!ifmeetpoint)
  46.                                         retpower++;
  47.                                 if (ifdecimal) {
  48.                                         this->power = retpower;
  49.                                 }
  50.                         }
  51.                         if (str[i] == '0' && ifdecimal) {
  52.                                 retpower--;
  53.                         }
  54.                         if (str[i] == '.') {
  55.                                 ifmeetpoint = true;
  56.                                 if (!startdigits) {        //小数
  57.                                         ifdecimal = true;
  58.                                 }
  59.                                 else {
  60.                                         this->power = retpower;
  61.                                 }
  62.                         }
  63.                 }
  64.                 i++;
  65.         }
  66.         while (!this->digits.empty() && this->digits.back() == 0)                //去除末尾的0 保证digits里是纯纯的有效数字
  67.                 this->digits.pop_back();
  68.         if (digits.empty()) {                //如果去掉0之后发现没东西了  那么说明这个数字就是0 返回ZERO零常量
  69.                 *this = ZERO;
  70.         }
  71.         this->power = retpower;
  72.         this->setPrecision();                //规定小数位数精度  毕竟无限小数不能有无限大的digits给你用
  73. }
复制代码
数学函数
  1. //数学函数
  2.         static MyNum getPI();        //求π
  3.   //单目数学函数
  4.         MyNum My_sqrt() const;
  5.         MyNum My_sin() const; MyNum My_cos() const; MyNum My_tan() const;
  6.         MyNum My_exp() const;
  7.         MyNum My_fabs() const;
  8.         MyNum My_neg() const;
  9.         MyNum My_log() const;
  10.   //多目数学函数
  11.         friend MyNum My_gcd(const MyNum& a, const MyNum& b);
  12.         friend MyNum My_lcm(const MyNum& a, const MyNum& b);
复制代码
其中值得拿出来说的一些函数是

  • 求π值函数getPI()
    这个函数是求出π之后在三角函数里实现π优化用的  实现方法是

    证明过程如下:

    源码:
    1. MyNum MyNum::getPI() {                //危!!! 会超时
    2.         MyNum ret;
    3.         MyNum add(1);
    4.         for (int i = 1; add.sign != 0; i+=2) {
    5.                 add = ONE / MyNum(i);
    6.                 if ((i / 2) % 2)
    7.                         ret -= add;
    8.                 else
    9.                         ret += add;
    10.         }
    11.         return ret*MyNum(4);
    12. }
    复制代码
    但是一定一定要注意 这个函数..... 不能实际应用出来   因为要算出来一个精度够用的π  时间会爆炸....
    求出来一个后20位的π 要这个里面跑tm好几小时  鬼才用.....  所以代码里我直接把π的真实值给拿来用了哈哈哈哈哈哈哈

  • 自然指数函数exp()
    这个有现成的exp()  不过返回的double有精度的限制  所以使用了泰勒展开进行迭代从而求出我们想要精度的结果

    源码:
    1. MyNum MyNum::My_exp() const {
    2.         if (this->sign == 0) return ONE;        //e^0=1
    3.         if(*this>MyNum(TAYLOR_LIMIT))
    4.                 return MyNum(exp(this->to_double()));        //如果x太大那么就直接用内置函数了  不然迭代计算量太大
    5.         MyNum ret;
    6.         MyNum add(1);
    7.         for (int i = 1; add.sign != 0; i++) {                //注意这里的跳出条件 如果add太小了变成0了 说明我们迭代到我们要的精度了 这个时候就可以跳出
    8.                 ret += add;
    9.                 add *= (*this) / MyNum(i);                //迭代
    10.         }
    11.         return ret;
    12. }
    复制代码
    看起来还是很简单的
  • 三角函数sin() cos() tan()
    首先 也是用了泰勒展开来求他们的值

    除此以外 针对三角函数x+2kπ的特性 也进行了π优化  把数字控制在[-2π,2π]之间
    源码:
    1. MyNum MyNum::My_sin() const {
    2.         if (this->sign == 0) return ZERO;        //sin(0)=0
    3.         MyNum cal(*this);
    4.         while (cal < -PIDOUBLE)
    5.                 cal += PIDOUBLE;
    6.         while (cal > PIDOUBLE)
    7.                 cal -= PIDOUBLE;        //PI优化
    8.         MyNum ret;
    9.         MyNum add(-1);
    10.         for (int i = 1; add.sign != 0; i++) {        //泰勒展开迭代过程 跳出条件还是跟exp一样 add为0说明精度够了
    11.                 add = add * cal / MyNum(i);
    12.                 if (i % 2) {
    13.                         add.sign *= -1;
    14.                         ret += add;
    15.                 }
    16.         }
    17.         return ret;
    18. }
    19. MyNum MyNum::My_cos() const{
    20.         if (this->sign == 0) return ZERO;        //cos(0)=1
    21.         MyNum cal(*this);
    22.         while (cal < -PIDOUBLE)
    23.                 cal += PIDOUBLE;
    24.         while (cal > PIDOUBLE)
    25.                 cal -= PIDOUBLE;        //PI优化
    26.         MyNum ret(1);
    27.         MyNum add(1);
    28.         for (int i = 1; add.sign != 0; i++) {        //同上 泰勒展开部分
    29.                 add = add * cal / MyNum(i);
    30.                 if (i % 2 == 0) {
    31.                         add.sign *= -1;
    32.                         ret += add;
    33.                 }
    34.         }
    35.         return ret;
    36. }
    37. MyNum MyNum::My_tan() const{        
    38.         return this->My_sin() / this->My_cos();                //tan就别泰勒展开了  会寄掉的 直接sin/cos
    39. }
    复制代码
    效果拔群:

  • 最大公约最小公倍gcd() lcm()
    主要就是一个辗转相除法
    没啥说的 直接放源码吧:
    1. MyNum My_gcd_recursion(MyNum& a, MyNum& b) {        //递归辗转相除
    2.         while (a > b)
    3.                 a -= b;
    4.         if (a == b) return a;
    5.         else return My_gcd_recursion(b, a);
    6. }
    7. MyNum My_gcd(const MyNum& a,const MyNum& b) {
    8.         if (a.sign != b.sign) return ERROR;
    9.         MyNum aa(a.digits,a.power,1),bb(b.digits,b.power,1);
    10.         MyNum ret(My_gcd_recursion(aa, bb));
    11.         ret.sign = a.sign;
    12.         return ret;
    13. }
    14. MyNum My_lcm(const MyNum& a,const MyNum& b) {
    15.         return a * b / My_gcd(a, b);                //注意这里lcm有个数学关系: lcm*gcd=a*b
    16. }
    复制代码
    注意这里实现了一个神奇的功能:  小数也可以求最大公约最小公倍!

转换函数
  1. //转换函数
  2.         double to_double() const;
  3.         int to_int() const;
  4.         long long to_longlong() const;
  5.         std::string to_string() const;
  6.         MyNum decimalpart() const;
  7.         MyNum addError(int i)const;
复制代码
正常的转换函数没啥好说的
要说的是里面最后一个addError()
给他一个参数i  i指的是要添加哪一种ERROR进去  什么叫哪一种ERROR?  在上文有说过 我们想要实现不同的错误类型的区分  所以就有了几个错误类型的划分 这里的i就是对应你要添加哪种错误类型
具体就是
如果是在原来ERROR的基础上添加一个新的错误类型  也就是要在digits的第i位置为1  那么先补全digits  然后置为1就好
源码:
  1. MyNum MyNum::addError(int i)const {
  2.         MyNum ret(ERROR);
  3.         ret.digits.clear();
  4.         if (this->sign == -2)
  5.                 ret = *this;
  6.         for (int temp = ret.digits.size(); temp <= i; temp++) {                //补全digits到i
  7.                 ret.digits.push_back(0);
  8.         }
  9.         ret.digits[i] = 1;
  10.         return ret;
  11. }
复制代码
最前面的部分是重载了一下ERROR+ERROR的情况  方便之后使用
-
减法跟加法大同小异 也是先对齐小数点然后逐位相减 然后从后往前处理 只是要注意一下处理完之后第一位被借没掉的情况  此时要变power
源码:
  1. //运算符重载
  2.         bool operator<(const MyNum& other)const;
  3.         bool operator>(const MyNum& other)const;
  4.         bool operator==(const MyNum& other)const;
  5.         bool operator!=(const MyNum& other)const;
  6.         bool operator<=(const MyNum& other)const;
  7.         bool operator>=(const MyNum& other)const;
  8.         MyNum operator+(const MyNum& other)const;
  9.         MyNum operator-()const;
  10.         MyNum operator-(const MyNum& other)const;
  11.         MyNum operator*(const MyNum& other)const;
  12.         MyNum operator/(const MyNum& other)const;
  13.         MyNum operator^(const MyNum& other)const;
  14.         MyNum power_int(int k)const;
  15.         MyNum power_decimal(const MyNum& decimal)const;
  16.         MyNum& operator+=(const MyNum& other);
  17.         MyNum& operator-=(const MyNum& other);
  18.         MyNum& operator*=(const MyNum& other);
  19.         MyNum& operator/=(const MyNum& other);
复制代码
*
还是列竖式  a的每一位数去乘b的每一位数  途中注意对齐问题  然后把所有的加起来 就是最终的结果 注意进位即可
  1. MyNum MyNum::operator+(const MyNum& other)const {
  2.         //ERROR
  3.         if ((*this).sign == -2 || other.sign == -2) {
  4.                 if ((*this).sign == -2 && other.sign == -2) {
  5.                         MyNum reterror(ERROR);
  6.                         for (int i = 0; i < this->digits.size(); i++) {
  7.                                 if (this->digits[i]) {
  8.                                         reterror = reterror.addError(i);
  9.                                 }
  10.                         }
  11.                         for (int i = 0; i < other.digits.size(); i++) {
  12.                                 if (other.digits[i]) {
  13.                                         reterror = reterror.addError(i);
  14.                                 }
  15.                         }
  16.                         return reterror;
  17.                 }
  18.                 if ((*this).sign == -2) return *this;
  19.                 if (other.sign == -2) return other;
  20.         }
  21.         //异号
  22.         if (this->sign * other.sign == -1) {
  23.                 if (this->sign < 0) return other - (-(*this));
  24.                 else return (*this) - (-other);
  25.         }
  26.         //0
  27.         if (this->sign == 0) return other;
  28.         if (other.sign == 0) return *this;
  29.         //同号
  30.         //找到较大的那个数 用它加上较小的数 比较省事
  31.         MyNum const *bigger,*smaller;
  32.         if (this->My_fabs() >= other.My_fabs())
  33.                 { bigger = this; smaller = &other; }
  34.         else
  35.                 { bigger = &other; smaller = this; }
  36.         int retpower = bigger->power;
  37.         int retsign = bigger->sign;
  38.         //对齐小数点后逐位相加
  39.         int diff = bigger->power - smaller->power;                //小数点偏差
  40.         std::deque<int> retdigits = bigger->digits;
  41.         int length = 0;
  42.         while (length < diff) {
  43.                 while (length >= retdigits.size())
  44.                         retdigits.push_back(0);
  45.                 length++;
  46.         }
  47.         for (int temp = 0; temp < smaller->digits.size(); temp++) {
  48.                 while (length >= retdigits.size())
  49.                         retdigits.push_back(0);
  50.                 retdigits[length++] += smaller->digits[temp];
  51.         }
  52.         //从后往前逐位校准
  53.         for (int temp = length - 1; temp >= 1; temp--) {
  54.                 retdigits[temp - 1] += retdigits[temp] / 10;
  55.                 retdigits[temp] %= 10;
  56.         }
  57.         if (retdigits[0] >= 10) {
  58.                 retdigits.push_front(retdigits[0] / 10);
  59.                 retdigits[1] %= 10;
  60.                 retpower++;
  61.         }
  62.         //末尾去0
  63.         while (!retdigits.empty() && retdigits.back() == 0)
  64.                 retdigits.pop_back();
  65.         if (retdigits.empty()) return ZERO;
  66.         MyNum ans(retdigits, retpower, retsign);
  67.         ans.setPrecision();
  68.         return ans;
  69. }
复制代码
/
除法算是比较难想的一个了 他也是列竖式 但是除法竖式本身就和之前的三种不一样  所以不是很容易
也是除数一位位往右边挪  一步步翻倍除数  一直到他大于被除数 这个时候翻了几倍就是这个位数的答案 接着把除数往后挪一格  重复以上过程
  1. MyNum MyNum::operator-(const MyNum& other)const {
  2.         //ERROR
  3.         if ((*this).sign == -2 || other.sign == -2) return *this+other;
  4.         //异号
  5.         if (this->sign * other.sign == -1) {
  6.                 if (this->sign < 0) return -(other + (-(*this)));
  7.                 else return (*this) + (-other);
  8.         }
  9.         //0
  10.         if (this->sign == 0) return -other;
  11.         if (other.sign == 0) return -(*this);
  12.         //同号
  13.         if ((*this) == other) return ZERO;
  14.         int retsign;
  15.         //找到绝对值较大的那个数 用它减去较小的数 比较省事
  16.         MyNum const *bigger, *smaller;
  17.         if (this->My_fabs() > other.My_fabs())
  18.                 { bigger = this; smaller = &other; retsign = bigger->sign; }
  19.         else
  20.                 { bigger = &other; smaller = this; retsign = -bigger->sign; }
  21.         int retpower = bigger->power;
  22.         //对齐小数点逐位相减
  23.         int diff = bigger->power - smaller->power;                //小数点偏差
  24.         std::deque<int> retdigits = bigger->digits;
  25.         int length = 0;
  26.         while (length < diff) {
  27.                 while (length >= retdigits.size())
  28.                         retdigits.push_back(0);
  29.                 length++;
  30.         }
  31.         for (int temp = 0; temp < smaller->digits.size(); temp++) {
  32.                 while (length >= retdigits.size())
  33.                         retdigits.push_back(0);
  34.                 retdigits[length++] -= smaller->digits[temp];
  35.         }
  36.         //从后往前逐位校准
  37.         for (int temp = length - 1; temp >= 1; temp--) {
  38.                 while (retdigits[temp] < 0) {
  39.                         retdigits[temp - 1]--;
  40.                         retdigits[temp] += 10;
  41.                 }
  42.         }
  43.         //去头0 去尾0
  44.         while (!retdigits.empty() && retdigits.front() == 0) {
  45.                 retdigits.pop_front();
  46.                 retpower--;
  47.         }
  48.         while (!retdigits.empty() && retdigits.back() == 0)
  49.                 retdigits.pop_back();
  50.         if (retdigits.empty()) return ZERO;
  51.         MyNum ans(retdigits, retpower, retsign);
  52.         ans.setPrecision();
  53.         return ans;
  54. }
复制代码
^
之前提过了  这些个运算里面最最有含金量的就是乘方运算  因为他实现了小数指数的计算
大致思路就是把小数指数 拆成整数和小数部分  其中整数部分操作的时候利用快速幂来进行优化  小数部分利用log()函数以及泰勒展开的技巧 迭代求出最后结果  两部分求出来之后最后乘到一起就是最终的结果
源码:
  1. MyNum MyNum::operator*(const MyNum& other)const {
  2.         //ERROR
  3.         if ((*this).sign == -2 || other.sign == -2) return *this + other;
  4.         //0
  5.         if (this->sign == 0) return ZERO;
  6.         if (other.sign == 0) return ZERO;
  7.         int retsign = this->sign * other.sign;
  8.         int retpower = this->power + other.power;
  9.         std::deque<int> retdigits;
  10.         for (int i = 0; i < this->digits.size(); i++) {
  11.                 if (this->digits[i] == 0) continue;
  12.                 int temp = i;
  13.                 for (int j = 0; j < other.digits.size(); j++) {
  14.                         while (temp >= retdigits.size())
  15.                                 retdigits.push_back(0);
  16.                         retdigits[temp++] += this->digits[i] * other.digits[j];
  17.                 }
  18.         }
  19.         for (int temp = retdigits.size() - 1; temp >= 1; temp--) {
  20.                 retdigits[temp - 1] += retdigits[temp] / 10;
  21.                 retdigits[temp] %= 10;
  22.         }
  23.         retpower--;
  24.         while (retdigits.front() >= 10) {
  25.                 retdigits.push_front(retdigits[0] / 10);
  26.                 retdigits[1] %= 10;
  27.                 retpower++;
  28.         }
  29.         MyNum ans(retdigits, retpower, retsign);
  30.         ans.setPrecision();
  31.         return ans;
  32. }
复制代码
这个还是挺有含金量的
</ul>显示函数
  1. MyNum MyNum::operator/(const MyNum& other)const {
  2.         //ERROR
  3.         if ((*this).sign == -2 || other.sign == -2) return *this + other;
  4.         //除0
  5.         if (other.sign == 0) {
  6.                 return ERROR.addError(0);
  7.         }
  8.         if (this->sign == 0) {
  9.                 return ZERO;
  10.         }
  11.         if (other == MyNum(1)) return *this;
  12.         if (other == MyNum(-1)) return -*this;
  13.         int retsign = this->sign * other.sign;
  14.         int retpower = this->power - other.power;
  15.         std::deque<int> a = this->digits;
  16.         std::deque<int> b = other.digits;
  17.         std::deque<int> ans;
  18.         for (int temp = 0; temp <= PRECISION + retsign; temp++) {                //除法核心部分
  19.                 int next = 0;
  20.                 while (cmp_digits(a, b) > 0) {
  21.                         minus_digits(a, b);
  22.                         next++;
  23.                 }
  24.                 if (cmp_digits(a, b) == 0) {
  25.                         next++;
  26.                         ans.push_back(next);
  27.                         break;
  28.                 }
  29.                 ans.push_back(next);
  30.                 b.push_front(0);
  31.         }
  32.         while (!ans.empty() && ans.front() == 0) {
  33.                 ans.pop_front();
  34.                 retpower--;
  35.         }
  36.         while (!ans.empty() && ans.back() == 0) {
  37.                 ans.pop_back();
  38.         }
  39.         retpower++;
  40.         MyNum ret(ans, retpower, retsign);
  41.         ret.setPrecision();
  42.         return ret;
  43. }
复制代码
都没啥好说的
show()里面有个显示ERROR内容  大致就是有一个存放各个error名字的数组  如果这个MyNum是ERROR  那么就根据他的digits去看对应了哪一种的ERROR  然后输出就行
源码:
  1. MyNum MyNum::operator^(const MyNum& other) const{
  2.         //ERROR
  3.         if ((*this).sign == -2 || other.sign == -2) return *this + other;
  4.         MyNum b(other);
  5.         if (b.sign == 0) return (this->sign == 0) ? ERROR.addError(1) : ZERO;
  6.         if (this->sign == 0) return (b.sign > 0) ? ZERO : ERROR.addError(0);
  7.         //仅排除了底数为零的情况 不保证幂指数的整数部分和小数部分不为0
  8.         if (b.sign > 0)
  9.                 return power_int(other.to_int()) * (power_decimal(other.decimalpart()));        //整数部分快速幂 小数部分泰勒展开
  10.         else
  11.                 return MyNum(1) / (power_int(-other.to_int()) * (power_decimal(-other.decimalpart())));
  12. }
  13. MyNum MyNum::power_int(int k)const {                //整数部分
  14.         if (k == 0) return MyNum(1);
  15.         if (k < 0) return MyNum(1) / ((*this) ^ (-k));
  16.         if (*this == MyNum(1)) return MyNum(1);
  17.        
  18.         //快速幂部分
  19.         MyNum ans(1);
  20.         MyNum bottom(*this);
  21.         while (k) {
  22.                 if (k & 1) {
  23.                         ans *= bottom;
  24.                 }
  25.                 bottom *= bottom;
  26.                 k >>= 1;
  27.         }
  28.         ans.setPrecision();
  29.         return ans;
  30. }       
  31. MyNum MyNum::power_decimal(const MyNum& decimal) const{                //小数部分
  32.         //ERROR
  33.         if ((*this).sign == -2) return *this;
  34.        
  35.         if (decimal.sign == 0) return MyNum(1);
  36.         if (this->sign < 0)        //底数负数 不可进行小数幂
  37.                 return ERROR.addError(2);
  38.         MyNum mult = this->My_log() * decimal;        //泰勒展开每一项要乘的东西
  39.         MyNum add(1);
  40.         MyNum ret;
  41.         for (int i = 1; add.sign != 0; i++) {
  42.                 ret += add;
  43.                 add = add * mult / MyNum(i);
  44.         }
  45.         return ret;
  46. }
复制代码
Method类的函数

构造函数
  1. //显示
  2.         void show() const;
  3.         void setPrecision(int prec = PRECISION);
复制代码
无要说的  就是正常的构造
操作函数
  1. void MyNum::show() const {
  2.         if (this->sign==-2) {
  3.                 printf("ERROR\n");
  4.                 for (int i = 0; i < digits.size(); i++) {
  5.                         if (digits[i])
  6.                                 std::cout << errorreason[i] << std::endl;
  7.                 }
  8.                 return;
  9.         }
  10.         if (sign == 2) {
  11.                 if (digits[0] == ',') return;
  12.                 for (int i = 0; i < digits.size(); i++)
  13.                         printf("%c", char(digits[i]));
  14.                 return;
  15.         }
  16.         int power = this->power;
  17.         int sign = this->sign;
  18.         std::deque<int> digits = this->digits;
  19.         if (sign == -1) printf("-");
  20.         if (sign == 0) { printf("0"); return; }
  21.         if (power <= 0) {
  22.                 printf("0.");
  23.                 while (power < 0) {
  24.                         printf("0"); power++;
  25.                 }
  26.                 power--;
  27.         }
  28.         for (int i = 0; i < digits.size(); i++) {
  29.                 if (power-- == 0) {
  30.                         printf(".");
  31.                 }
  32.                 printf("%d", digits[i]);
  33.         }
  34.         while (power > 0) {
  35.                 printf("0");
  36.                 power--;
  37.         }
  38. }
复制代码
重中之重就是一个把原计算式转换为后缀表达式的changetorpn()  还有一个计算函数calculate()
<ul>changetorpn()
简单思路: 通过遍历calstr计算式子字符串  把每个对应于数字的 对应于计算符号的  对应于计算函数的 全部一个个拆开来分成单独的MyNum 然后根据后缀表达式的转换规则  利用一个操作符单调栈opstack 按照操作符优先级的严格递增顺序进行入栈出栈 也就是严格单调栈  从而进行后缀表达式的转换
具体可以参见这篇文章: https://blog.csdn.net/a8425/article/details/119253258
源码:
  1. void Method::changetorpn() {        this->rpn.clear();        std::deque& retrpn = this->rpn;        std::deque opstack;        //符号栈(用deque模拟栈)        string nowdigits;        string op;        for (int i = 0; i < calstr.size(); i++) {                if (calstr[i] == ' ') continue;                if (calstr[i] == ',') {                        if (!nowdigits.empty()) {                                retrpn.push_back(MyNum(nowdigits));                                nowdigits.clear();                        }                        while (!opstack.empty() && opstack.back() != MyNum("(")) {                                retrpn.push_back(opstack.back());                                opstack.pop_back();                        }                        //opstack.pop_back();                        continue;                }                if (calstr[i] == '-' ) {                        if (!(!nowdigits.empty() || i > 0 && calstr[i - 1] == ')')) {        //'-'是负号不是减号                                if (!op.empty()) {                                        opstackpushback(opstack, MyNum(op));                                        op.clear();                                }                                opstackpushback(opstack, MyNum("neg"));                                continue;                        }                }                if (calstr[i] >= '0' && calstr[i]  12 && str.substr(0,12) == "setprecision") {                int newprecision = 0;                for (int i = 13; i < str.size(); i++) {                        newprecision *= 10;                        newprecision += str[i] - '0';                }                SHOW_PRECISION = newprecision;                return 4;        }        Method m(str);        history.push_back(m);        return 1;}void Func() {        int input = 1;        while(true) {                input = inputMethod();                if (input == 0) break;                if (input == 1) {                        history.back().show(showType);                        cout digits = other.digits;                this->power = other.power;                this->sign = other.sign;                return *this;        }        //析构        ~MyNum() {}        //数学函数        static MyNum getPI();        //求π        //单目数学函数        MyNum My_sqrt() const;        MyNum My_sin() const; MyNum My_cos() const; MyNum My_tan() const;        MyNum My_exp() const;        MyNum My_fabs() const;        MyNum My_neg() const;         MyNum My_log() const;        //多目数学函数                //见类外定义的非成员函数        friend MyNum My_gcd(const MyNum& a, const MyNum& b);        friend MyNum My_lcm(const MyNum& a, const MyNum& b);        //转换函数
  2.         double to_double() const;
  3.         int to_int() const;
  4.         long long to_longlong() const;
  5.         std::string to_string() const;
  6.         MyNum decimalpart() const;
  7.         MyNum addError(int i)const;        //运算符重载        bool operator(const MyNum& other)const;        bool operator==(const MyNum& other)const;        bool operator!=(const MyNum& other)const;        bool operator=(const MyNum& other)const;        MyNum operator+(const MyNum& other)const;        MyNum operator-()const;        MyNum operator-(const MyNum& other)const;        MyNum operator*(const MyNum& other)const;        MyNum operator/(const MyNum& other)const;        MyNum operator^(const MyNum& other)const;        MyNum power_int(int k)const;        MyNum power_decimal(const MyNum& decimal)const;        MyNum& operator+=(const MyNum& other);        MyNum& operator-=(const MyNum& other);        MyNum& operator*=(const MyNum& other);        MyNum& operator/=(const MyNum& other);        MyNum MyNum::operator/(const MyNum& other)const {
  8.         //ERROR
  9.         if ((*this).sign == -2 || other.sign == -2) return *this + other;
  10.         //除0
  11.         if (other.sign == 0) {
  12.                 return ERROR.addError(0);
  13.         }
  14.         if (this->sign == 0) {
  15.                 return ZERO;
  16.         }
  17.         if (other == MyNum(1)) return *this;
  18.         if (other == MyNum(-1)) return -*this;
  19.         int retsign = this->sign * other.sign;
  20.         int retpower = this->power - other.power;
  21.         std::deque<int> a = this->digits;
  22.         std::deque<int> b = other.digits;
  23.         std::deque<int> ans;
  24.         for (int temp = 0; temp <= PRECISION + retsign; temp++) {                //除法核心部分
  25.                 int next = 0;
  26.                 while (cmp_digits(a, b) > 0) {
  27.                         minus_digits(a, b);
  28.                         next++;
  29.                 }
  30.                 if (cmp_digits(a, b) == 0) {
  31.                         next++;
  32.                         ans.push_back(next);
  33.                         break;
  34.                 }
  35.                 ans.push_back(next);
  36.                 b.push_front(0);
  37.         }
  38.         while (!ans.empty() && ans.front() == 0) {
  39.                 ans.pop_front();
  40.                 retpower--;
  41.         }
  42.         while (!ans.empty() && ans.back() == 0) {
  43.                 ans.pop_back();
  44.         }
  45.         retpower++;
  46.         MyNum ret(ans, retpower, retsign);
  47.         ret.setPrecision();
  48.         return ret;
  49. }private:        std::deque digits;        int power;        int sign;        friend class Method;};MyNum My_gcd(const MyNum& a, const MyNum& b);MyNum My_lcm(const MyNum& a, const MyNum& b);#endif
复制代码
MyNum.cpp
  1. #define _CRT_SECURE_NO_WARNINGS#include "MyNum.h"#include #include #define ZERO_LIMIT 1e-6                //小于这个数字的浮点数 就判定为0#define TAYLOR_LIMIT 50                //数学函数里面使用泰勒展开的数据最大值 因为数据过大泰勒展开将会耗时过久extern const MyNum ZERO({ 0 }, 0, 0);extern const MyNum ERROR({}, 0, -2);extern const MyNum ONE(1);//const MyNum PI(MyNum::getPI());extern MyNum PI("3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446");                                //运用getPI函数将会超时... 因此直接读入pi会更好extern MyNum PIDOUBLE("6.2831853071795864769252867665590057683943387987502116419498891846156328125724179972560696506842341359642961730265646132941876892");//工具函数int getmin(int a, int b) { return a < b ? a : b; }int getmax(int a, int b) { return a > b ? a : b; }int inttodeque(std::deque& digits, int i) {        if (i == 0) {                digits.push_back(0);                return 0;        }        int retpower = 0;        i = i > 0 ? i : -i;        while (i) {                digits.push_front(i % 10);                i /= 10;                retpower++;        }        return retpower;}int cmp_digits(std::deque& a, std::deque& b) {        for (int i = 0; i < getmin(a.size(), b.size());i++) {                if (a[i] > b[i]) return 1;                if (a[i] < b[i]) return -1;        }        if (a.size() > b.size()) return 1;        if (a.size() < b.size()) return -1;        return 0;}int minus_digits(std::deque& a, std::deque& b) {        //前提确保了a>b        for (int i = 0; i < b.size(); i++) {                if (i == a.size())                        a.push_back(0);                a[i] -= b[i];        }        for (int i = a.size() - 1; i >= 1; i--) {                while (a[i] < 0) {                        a[i - 1] --;                        a[i] += 10;                }        }        int ret = 0;        //返回借位        while (a[0] < 0) {                ret++;                a[0]+=10;        }        return ret;}string digittostring(std::deque& digits) {                        string ans;        for (int i = 0; i < digits.size(); i++) {                ans.push_back(char(digits[i]));        }        return ans;}//构造函数MyNum::MyNum(int i) {        *this = MyNum((long long)i);}MyNum::MyNum(long long i) {        if (i == 0ll) {                *this = ZERO;                return;        }        int power = 0;        std::deque digits;        int sign = 1;        if (i < 0) sign = -1;        i *= sign;        while (i) {                digits.push_front(i % 10);                i /= 10;                power++;        }        while (digits.back() == 0)                digits.pop_back();        this->digits = digits;        this->power = power;        this->sign = sign;}MyNum::MyNum(double d) {        if (d < ZERO_LIMIT && d>-ZERO_LIMIT) {                *this = ZERO;                return;        }        this->sign = (d > 0) ? 1 : -1;        d *= sign;        int retpower = 0;        if(int(d)!=0)                 retpower = inttodeque(this->digits, int(d));        bool ifFindDemicalPoint = retpower >= 0;        //是否找到小数点        d -= int(d);        //只保留小数部分        while (d > ZERO_LIMIT || d < -ZERO_LIMIT) {                d *= 10;                int integer = int(d);                d -= integer;                if (ifFindDemicalPoint)                        this->digits.push_back(integer);                else {                        if (integer == 0)                                 retpower--;                        else                                 ifFindDemicalPoint = true;                }        }        this->power = retpower;        while (this->digits.back() == 0)                 this->digits.pop_back();        this->setPrecision();        /*char str[1000];        sprintf(str, "%lf", d);        *this = MyNum(std::string(str));*/                //sprintf转换成字符串只有6位小数的精度}MyNum::MyNum(std::string str) {        if (str.size() && (str[0] < '0' || str[0]>'9')) {                if (!((str[0] == '-' || str[0] == '+') && str.size() > 1 && str[1] >= '0' && str[1] sign = 2;                        if (str[0] >= 'a' && str[0] = 'A' && str[0] digits.push_back(int(str[i]));                        }                        return;                }        }        this->sign = 1;        int i = 0;        while (str[i] == ' ') i++;        if (str[i] == '-') {                this->sign = -1; i++;        }        if (str[i] == '+') i++;        int retpower = 0;        bool startdigits = false;        //开始有效数字        int powerchange = 1;                //1表示每往后一格power++  -1就是小数情况        int ifdecimal = false;        bool ifmeetpoint = false;        //有无遇见小数点        while (i < str.size()) {                if (startdigits && str[i]>='0' && str[i]digits.push_back(str[i] - '0');                        if (!ifmeetpoint)                                 retpower++;                }                else {                        if (str[i] >= '1' && str[i] digits.push_back(str[i] - '0');                                if (!ifmeetpoint)                                        retpower++;                                if (ifdecimal) {                                        this->power = retpower;                                }                        }                        if (str[i] == '0' && ifdecimal) {                                retpower--;                        }                        if (str[i] == '.') {                                ifmeetpoint = true;                                if (!startdigits) {        //小数                                        ifdecimal = true;                                }                                else {                                        this->power = retpower;                                }                        }                }                i++;        }        while (!this->digits.empty() && this->digits.back() == 0)                this->digits.pop_back();        if (digits.empty()) {                *this = ZERO;        }        this->power = retpower;        this->setPrecision();}//数学函数MyNum MyNum::getPI() {                MyNum ret;        MyNum add(1);        for (int i = 1; add.sign != 0; i+=2) {                add = ONE / MyNum(i);                if ((i / 2) % 2)                        ret -= add;                else                        ret += add;        }        return ret*MyNum(4);}//单目数学函数MyNum MyNum::My_sqrt() const {        //return *this^MyNum(0.5);        return MyNum(sqrt(this->to_double()));}MyNum MyNum::My_sin() const {        if (this->sign == 0) return ZERO;        MyNum cal(*this);        while (cal < -PIDOUBLE)                cal += PIDOUBLE;        while (cal > PIDOUBLE)                 cal -= PIDOUBLE;        //PI优化        MyNum ret;        MyNum add(-1);        for (int i = 1; add.sign != 0; i++) {                add = add * cal / MyNum(i);                if (i % 2) {                        add.sign *= -1;                        ret += add;                }        }        return ret;}MyNum MyNum::My_cos() const{         if (this->sign == 0) return MyNum(1);        MyNum cal(*this);        while (cal < -PIDOUBLE)                cal += PIDOUBLE;        while (cal > PIDOUBLE)                cal -= PIDOUBLE;        //PI优化        MyNum ret(1);        MyNum add(1);        for (int i = 1; add.sign != 0; i++) {                add = add * cal / MyNum(i);                if (i % 2 == 0) {                        add.sign *= -1;                        ret += add;                }        }        return ret;}MyNum MyNum::My_tan() const{         return this->My_sin() / this->My_cos();}MyNum MyNum::My_exp() const {         if (this->sign == 0) return ONE;        if(*this>MyNum(TAYLOR_LIMIT))                return MyNum(exp(this->to_double()));        MyNum ret;        MyNum add(1);        for (int i = 1; add.sign != 0; i++) {                ret += add;                add *= (*this) / MyNum(i);        }        return ret;}MyNum MyNum::My_fabs() const {        return MyNum(this->digits, this->power, (this->signsign addError(4);        }        return MyNum(log(this->to_double()));}//多目数学函数MyNum My_gcd_recursion(MyNum& a, MyNum& b) {        //递归辗转相除        while (a > b) {                a -= b;        }        if (a == b)                 return a;        else                 return My_gcd_recursion(b, a);}MyNum My_gcd(const MyNum& a,const MyNum& b) {        if (a.sign != b.sign) return ERROR;        MyNum aa(a.digits,a.power,1),bb(b.digits,b.power,1);        MyNum ret(My_gcd_recursion(aa, bb));        ret.sign = a.sign;        return ret;}MyNum My_lcm(const MyNum& a,const MyNum& b) {        return a * b / My_gcd(a, b);}//转换函数double MyNum::to_double() const {        double ret = 0;        const std::deque& digits=this->digits;        for (int i = digits.size() - 1; i >= 0; i--) {        //化为类科学计数法 0.xxx                ret += digits[i];                ret /= 10;        }        if(this->power>0)                for (int i = 0; i < this->power; i++)                        ret *= 10;        else {                for (int i = 0; i < -this->power; i++) {                        ret /= 10;                }        }        return ret;}int MyNum::to_int() const {        if (power digits[i];        }        return ret * this->sign;}long long MyNum::to_longlong() const {        if (power digits[i]);        }        return ret * this->sign;}std::string MyNum::to_string() const {        if (sign == -2) return "ERROR";        if (sign == 0) return "0";        string ans;        if (sign == -1) ans.push_back('-');        int power = this->power;        const std::deque& digits = this->digits;        if (power = digits.size())                                ans.push_back('0');                        else                                ans.push_back('0' + digits[i]);                }                if (i < digits.size()) {                        ans.push_back('.');                        for (; i < digits.size(); i++) {                                ans.push_back(digits[i]);                        }                }        }        return ans;}MyNum MyNum::decimalpart() const {        if (this->power sign == -2)                ret = *this;        for (int temp = ret.digits.size(); temp sign > other.sign) return false;        //下面同号情况        if (this->power < other.power) return sign == 1;        //绝对值小 判断是否正数        if (this->power > other.power) return sign == -1;        //绝对值小 判断是否正数        //同号 指数相同 比较有效数字        int i;        for (i = 0; i < getmin(this->digits.size(), other.digits.size()); i++) {                if (this->digits[i] < other.digits[i]) return sign == 1;                if (this->digits[i] > other.digits[i]) return sign == -1;        }        //有效数字重叠  判断哪个短        if (this->digits.size() < other.digits.size()) return sign == 1;        if (this->digits.size() > other.digits.size()) return sign == -1;        return false;}bool MyNum::operator>(const MyNum& other)const {        if (this->sign > other.sign) return true;        if (this->sign < other.sign) return false;        //下面同号情况        if (this->power > other.power) return sign == 1;        //绝对值大 判断是否正数        if (this->power < other.power) return sign == -1;        //同号 指数相同 比较有效数字        int i;        for (i = 0; i < getmin(this->digits.size(), other.digits.size()); i++) {                if (this->digits[i] > other.digits[i]) return sign == 1;                if (this->digits[i] < other.digits[i]) return sign == -1;        }        //有效数字重叠  判断哪个长        if (this->digits.size() > other.digits.size()) return sign == 1;        if (this->digits.size() < other.digits.size()) return sign == -1;        return false;}bool MyNum::operator==(const MyNum& other)const {        return (this->digits == other.digits && this->sign == other.sign && this->power == other.power);}bool MyNum::operator!=(const MyNum& other)const {        return !(this->operator==(other));}bool MyNum::operator=(const MyNum& other)const {        return (*this) > other || (*this) == other;}MyNum MyNum::operator+(const MyNum& other)const {        //ERROR        if ((*this).sign == -2 || other.sign == -2) {                if ((*this).sign == -2 && other.sign == -2) {                        MyNum reterror(ERROR);                        for (int i = 0; i < this->digits.size(); i++) {                                if (this->digits[i]) {                                        reterror = reterror.addError(i);                                }                        }                        for (int i = 0; i < other.digits.size(); i++) {                                if (other.digits[i]) {                                        reterror = reterror.addError(i);                                }                        }                        return reterror;                }                if ((*this).sign == -2) return *this;                if (other.sign == -2) return other;        }        //异号        if (this->sign * other.sign == -1) {                if (this->sign < 0) return other - (-(*this));                else return (*this) - (-other);        }        //0        if (this->sign == 0) return other;        if (other.sign == 0) return *this;        //同号        //找到较大的那个数 用它加上较小的数 比较省事        MyNum const *bigger,*smaller;        if (this->My_fabs() >= other.My_fabs())                 { bigger = this; smaller = &other; }        else                { bigger = &other; smaller = this; }        int retpower = bigger->power;        int retsign = bigger->sign;        //对齐小数点后逐位相加        int diff = bigger->power - smaller->power;                //小数点偏差        std::deque retdigits = bigger->digits;        int length = 0;        while (length < diff) {                while (length >= retdigits.size())                        retdigits.push_back(0);                length++;        }        for (int temp = 0; temp < smaller->digits.size(); temp++) {                while (length >= retdigits.size())                        retdigits.push_back(0);                retdigits[length++] += smaller->digits[temp];        }        //从后往前逐位校准        for (int temp = length - 1; temp >= 1; temp--) {                retdigits[temp - 1] += retdigits[temp] / 10;                retdigits[temp] %= 10;        }        if (retdigits[0] >= 10) {                retdigits.push_front(retdigits[0] / 10);                retdigits[1] %= 10;                retpower++;        }        //末尾去0        while (!retdigits.empty() && retdigits.back() == 0)                retdigits.pop_back();        if (retdigits.empty()) return ZERO;        MyNum ans(retdigits, retpower, retsign);        ans.setPrecision();        return ans;}MyNum MyNum::operator-()const {        return MyNum(this->digits, this->power, -(this->sign));}//运算符重载
  2.         bool operator<(const MyNum& other)const;
  3.         bool operator>(const MyNum& other)const;
  4.         bool operator==(const MyNum& other)const;
  5.         bool operator!=(const MyNum& other)const;
  6.         bool operator<=(const MyNum& other)const;
  7.         bool operator>=(const MyNum& other)const;
  8.         MyNum operator+(const MyNum& other)const;
  9.         MyNum operator-()const;
  10.         MyNum operator-(const MyNum& other)const;
  11.         MyNum operator*(const MyNum& other)const;
  12.         MyNum operator/(const MyNum& other)const;
  13.         MyNum operator^(const MyNum& other)const;
  14.         MyNum power_int(int k)const;
  15.         MyNum power_decimal(const MyNum& decimal)const;
  16.         MyNum& operator+=(const MyNum& other);
  17.         MyNum& operator-=(const MyNum& other);
  18.         MyNum& operator*=(const MyNum& other);
  19.         MyNum& operator/=(const MyNum& other);MyNum MyNum::operator+(const MyNum& other)const {
  20.         //ERROR
  21.         if ((*this).sign == -2 || other.sign == -2) {
  22.                 if ((*this).sign == -2 && other.sign == -2) {
  23.                         MyNum reterror(ERROR);
  24.                         for (int i = 0; i < this->digits.size(); i++) {
  25.                                 if (this->digits[i]) {
  26.                                         reterror = reterror.addError(i);
  27.                                 }
  28.                         }
  29.                         for (int i = 0; i < other.digits.size(); i++) {
  30.                                 if (other.digits[i]) {
  31.                                         reterror = reterror.addError(i);
  32.                                 }
  33.                         }
  34.                         return reterror;
  35.                 }
  36.                 if ((*this).sign == -2) return *this;
  37.                 if (other.sign == -2) return other;
  38.         }
  39.         //异号
  40.         if (this->sign * other.sign == -1) {
  41.                 if (this->sign < 0) return other - (-(*this));
  42.                 else return (*this) - (-other);
  43.         }
  44.         //0
  45.         if (this->sign == 0) return other;
  46.         if (other.sign == 0) return *this;
  47.         //同号
  48.         //找到较大的那个数 用它加上较小的数 比较省事
  49.         MyNum const *bigger,*smaller;
  50.         if (this->My_fabs() >= other.My_fabs())
  51.                 { bigger = this; smaller = &other; }
  52.         else
  53.                 { bigger = &other; smaller = this; }
  54.         int retpower = bigger->power;
  55.         int retsign = bigger->sign;
  56.         //对齐小数点后逐位相加
  57.         int diff = bigger->power - smaller->power;                //小数点偏差
  58.         std::deque<int> retdigits = bigger->digits;
  59.         int length = 0;
  60.         while (length < diff) {
  61.                 while (length >= retdigits.size())
  62.                         retdigits.push_back(0);
  63.                 length++;
  64.         }
  65.         for (int temp = 0; temp < smaller->digits.size(); temp++) {
  66.                 while (length >= retdigits.size())
  67.                         retdigits.push_back(0);
  68.                 retdigits[length++] += smaller->digits[temp];
  69.         }
  70.         //从后往前逐位校准
  71.         for (int temp = length - 1; temp >= 1; temp--) {
  72.                 retdigits[temp - 1] += retdigits[temp] / 10;
  73.                 retdigits[temp] %= 10;
  74.         }
  75.         if (retdigits[0] >= 10) {
  76.                 retdigits.push_front(retdigits[0] / 10);
  77.                 retdigits[1] %= 10;
  78.                 retpower++;
  79.         }
  80.         //末尾去0
  81.         while (!retdigits.empty() && retdigits.back() == 0)
  82.                 retdigits.pop_back();
  83.         if (retdigits.empty()) return ZERO;
  84.         MyNum ans(retdigits, retpower, retsign);
  85.         ans.setPrecision();
  86.         return ans;
  87. }MyNum MyNum::operator-(const MyNum& other)const {
  88.         //ERROR
  89.         if ((*this).sign == -2 || other.sign == -2) return *this+other;
  90.         //异号
  91.         if (this->sign * other.sign == -1) {
  92.                 if (this->sign < 0) return -(other + (-(*this)));
  93.                 else return (*this) + (-other);
  94.         }
  95.         //0
  96.         if (this->sign == 0) return -other;
  97.         if (other.sign == 0) return -(*this);
  98.         //同号
  99.         if ((*this) == other) return ZERO;
  100.         int retsign;
  101.         //找到绝对值较大的那个数 用它减去较小的数 比较省事
  102.         MyNum const *bigger, *smaller;
  103.         if (this->My_fabs() > other.My_fabs())
  104.                 { bigger = this; smaller = &other; retsign = bigger->sign; }
  105.         else
  106.                 { bigger = &other; smaller = this; retsign = -bigger->sign; }
  107.         int retpower = bigger->power;
  108.         //对齐小数点逐位相减
  109.         int diff = bigger->power - smaller->power;                //小数点偏差
  110.         std::deque<int> retdigits = bigger->digits;
  111.         int length = 0;
  112.         while (length < diff) {
  113.                 while (length >= retdigits.size())
  114.                         retdigits.push_back(0);
  115.                 length++;
  116.         }
  117.         for (int temp = 0; temp < smaller->digits.size(); temp++) {
  118.                 while (length >= retdigits.size())
  119.                         retdigits.push_back(0);
  120.                 retdigits[length++] -= smaller->digits[temp];
  121.         }
  122.         //从后往前逐位校准
  123.         for (int temp = length - 1; temp >= 1; temp--) {
  124.                 while (retdigits[temp] < 0) {
  125.                         retdigits[temp - 1]--;
  126.                         retdigits[temp] += 10;
  127.                 }
  128.         }
  129.         //去头0 去尾0
  130.         while (!retdigits.empty() && retdigits.front() == 0) {
  131.                 retdigits.pop_front();
  132.                 retpower--;
  133.         }
  134.         while (!retdigits.empty() && retdigits.back() == 0)
  135.                 retdigits.pop_back();
  136.         if (retdigits.empty()) return ZERO;
  137.         MyNum ans(retdigits, retpower, retsign);
  138.         ans.setPrecision();
  139.         return ans;
  140. }MyNum MyNum::operator^(const MyNum& other) const{        //ERROR        if ((*this).sign == -2 || other.sign == -2) return *this + other;        MyNum b(other);        if (b.sign == 0) return (this->sign == 0) ? ERROR.addError(1) : ZERO;        if (this->sign == 0) return (b.sign > 0) ? ZERO : ERROR.addError(0);        //仅排除了底数为零的情况 不保证幂指数的整数部分和小数部分不为0        if (b.sign > 0)                return power_int(other.to_int()) * (power_decimal(other.decimalpart()));        //整数部分快速幂 小数部分泰勒展开        else                return MyNum(1) / (power_int(-other.to_int()) * (power_decimal(-other.decimalpart())));}MyNum MyNum::power_int(int k)const {                if (k == 0) return MyNum(1);        if (k < 0) return MyNum(1) / ((*this) ^ (-k));        if (*this == MyNum(1)) return MyNum(1);                //快速幂部分        MyNum ans(1);        MyNum bottom(*this);        while (k) {                if (k & 1) {                        ans *= bottom;                }                bottom *= bottom;                k >>= 1;        }        ans.setPrecision();        return ans;}MyNum MyNum::power_decimal(const MyNum& decimal) const{        //ERROR        if ((*this).sign == -2) return *this;                if (decimal.sign == 0) return MyNum(1);        if (this->sign < 0)        //底数负数 不可进行小数幂                return ERROR.addError(2);        MyNum mult = this->My_log() * decimal;        //泰勒展开每一项要乘的东西        MyNum add(1);        MyNum ret;        for (int i = 1; add.sign != 0; i++) {                ret += add;                add = add * mult / MyNum(i);        }        return ret;}MyNum& MyNum::operator+=(const MyNum& other) {        *this = *this + other;        return *this;}MyNum& MyNum::operator-=(const MyNum& other) {        *this = *this - other;        return *this;}MyNum& MyNum::operator*=(const MyNum& other) {        *this = *this * other;        return *this;}MyNum& MyNum::operator/=(const MyNum& other) {        *this = *this / other;        return *this;}//显示MyNum MyNum::operator^(const MyNum& other) const{
  141.         //ERROR
  142.         if ((*this).sign == -2 || other.sign == -2) return *this + other;
  143.         MyNum b(other);
  144.         if (b.sign == 0) return (this->sign == 0) ? ERROR.addError(1) : ZERO;
  145.         if (this->sign == 0) return (b.sign > 0) ? ZERO : ERROR.addError(0);
  146.         //仅排除了底数为零的情况 不保证幂指数的整数部分和小数部分不为0
  147.         if (b.sign > 0)
  148.                 return power_int(other.to_int()) * (power_decimal(other.decimalpart()));        //整数部分快速幂 小数部分泰勒展开
  149.         else
  150.                 return MyNum(1) / (power_int(-other.to_int()) * (power_decimal(-other.decimalpart())));
  151. }
  152. MyNum MyNum::power_int(int k)const {                //整数部分
  153.         if (k == 0) return MyNum(1);
  154.         if (k < 0) return MyNum(1) / ((*this) ^ (-k));
  155.         if (*this == MyNum(1)) return MyNum(1);
  156.        
  157.         //快速幂部分
  158.         MyNum ans(1);
  159.         MyNum bottom(*this);
  160.         while (k) {
  161.                 if (k & 1) {
  162.                         ans *= bottom;
  163.                 }
  164.                 bottom *= bottom;
  165.                 k >>= 1;
  166.         }
  167.         ans.setPrecision();
  168.         return ans;
  169. }       
  170. MyNum MyNum::power_decimal(const MyNum& decimal) const{                //小数部分
  171.         //ERROR
  172.         if ((*this).sign == -2) return *this;
  173.        
  174.         if (decimal.sign == 0) return MyNum(1);
  175.         if (this->sign < 0)        //底数负数 不可进行小数幂
  176.                 return ERROR.addError(2);
  177.         MyNum mult = this->My_log() * decimal;        //泰勒展开每一项要乘的东西
  178.         MyNum add(1);
  179.         MyNum ret;
  180.         for (int i = 1; add.sign != 0; i++) {
  181.                 ret += add;
  182.                 add = add * mult / MyNum(i);
  183.         }
  184.         return ret;
  185. }void MyNum::setPrecision(int prec) {        int decimalpart = this->digits.size() - this->power;        //小数部分长度        if (decimalpart digits.empty())                        this->digits.pop_back();        int diff = 0;        //四舍五入的偏差值        if (!this->digits.empty()) {                if (this->digits.back() >= 5) {                        diff = 1;        //进1                }                this->digits.pop_back();        }        if (this->digits.empty()) {                *this = ZERO;        }        else {                int i = this->digits.size() - 1;                while (diff) {                        if (i == -1) break;                        this->digits[i] += diff;                        diff = this->digits[i] / 10;                        this->digits[i] %= 10;                        i--;                }                if (i == -1 && diff) {                        this->power++;                        this->digits.front() %= 10;                        this->digits.push_front(1);                }        }}
复制代码
Method.h
  1. #ifndef _METHOD_H_#define _METHOD_H_/*        Method类  存放计算式的原式 后缀表达式 以及 计算答案        string calstr                        //计算的原式        std::deque rpn        //ReversePolishNotation 逆波兰表示法/后缀表达式        int type                                //0 计算式  1 逻辑条件式        MyNum ans                                //计算结果*/#include #include #include #include "MyNum.h"using std::string;extern int SHOW_PRECISION;class Method{public:        //显示
  2.         void show() const;
  3.         void setPrecision(int prec = PRECISION);        void MyNum::show() const {
  4.         if (this->sign==-2) {
  5.                 printf("ERROR\n");
  6.                 for (int i = 0; i < digits.size(); i++) {
  7.                         if (digits[i])
  8.                                 std::cout << errorreason[i] << std::endl;
  9.                 }
  10.                 return;
  11.         }
  12.         if (sign == 2) {
  13.                 if (digits[0] == ',') return;
  14.                 for (int i = 0; i < digits.size(); i++)
  15.                         printf("%c", char(digits[i]));
  16.                 return;
  17.         }
  18.         int power = this->power;
  19.         int sign = this->sign;
  20.         std::deque<int> digits = this->digits;
  21.         if (sign == -1) printf("-");
  22.         if (sign == 0) { printf("0"); return; }
  23.         if (power <= 0) {
  24.                 printf("0.");
  25.                 while (power < 0) {
  26.                         printf("0"); power++;
  27.                 }
  28.                 power--;
  29.         }
  30.         for (int i = 0; i < digits.size(); i++) {
  31.                 if (power-- == 0) {
  32.                         printf(".");
  33.                 }
  34.                 printf("%d", digits[i]);
  35.         }
  36.         while (power > 0) {
  37.                 printf("0");
  38.                 power--;
  39.         }
  40. }        //显示        void showCalstr();        void showRPN();        void showAns(int showprecision=SHOW_PRECISION);        void show(int type = 0);private:        string calstr;        std::deque rpn;        int type;        MyNum ans;};#endif
复制代码
Method.cpp

[code]#include "Method.h"extern const MyNum ZERO;extern const MyNum ERROR;extern const MyNum ONE;//操作函数void Method::input(std::string str) {                //输入 将字符串中计算部分提取出来        for (int i = 0; i < str.size(); i++) {                if (str != ' ')                        calstr.push_back(str);        }}void Method::opstackpushback(std::deque& opstack,MyNum op) {        while (!opstack.empty() && opstack.back().power >= op.power) {                rpn.push_back(opstack.back());                opstack.pop_back();        }        opstack.push_back(op);}bool judgeop(char c) {                //判断是否为函数型op        if ((c < 'a' || c>'z') && (c < 'A' || c>'Z')) return false;        else return true;        return false;}void Method::changetorpn() {        this->rpn.clear();        std::deque& retrpn = this->rpn;        std::deque opstack;        //符号栈(用deque模拟栈)        string nowdigits;        string op;        for (int i = 0; i < calstr.size(); i++) {                if (calstr == ' ') continue;                if (calstr == ',') {                        if (!nowdigits.empty()) {                                retrpn.push_back(MyNum(nowdigits));                                nowdigits.clear();                        }                        while (!opstack.empty() && opstack.back() != MyNum("(")) {                                retrpn.push_back(opstack.back());                                opstack.pop_back();                        }                        //opstack.pop_back();                        continue;                }                if (calstr == '-' ) {                        if (!(!nowdigits.empty() || i > 0 && calstr[i - 1] == ')')) {        //'-'是负号不是减号                                if (!op.empty()) {                                        opstackpushback(opstack, MyNum(op));                                        op.clear();                                }                                opstackpushback(opstack, MyNum("neg"));                                continue;                        }                }                if (calstr >= '0' && calstr  b));                        }                        if (rpn == MyNum(">=")) {                                tempans.push_back(MyNum(a >= b));                        }                        if (rpn == MyNum("> ";        fflush(stdin);        scanf("%[^\n]", s);        string str(s);        if (str.empty()) {                getchar();                return -1;        }        if (str == "end")                 return 0;        if (str == "history") {                return 2;        }        if (str == "changeshowtype") {                showType = 1 - showType;                return 3;        }        if (str.size() > 12 && str.substr(0,12) == "setprecision") {                int newprecision = 0;                for (int i = 13; i < str.size(); i++) {                        newprecision *= 10;                        newprecision += str - '0';                }                SHOW_PRECISION = newprecision;                return 4;        }        Method m(str);        history.push_back(m);        return 1;}void Func() {        int input = 1;        while(true) {                input = inputMethod();                if (input == 0) break;                if (input == 1) {                        history.back().show(showType);                        cout "后输入计算式 回车即可显现结果  输入"end"回车即结束程序高级功能:        * 输入"changeshowtype"即可更改显示模式                - 简洁模式: 类似Matlab 回车只输出答案                - 详细模式: 输出原式, 后缀表达式 以及答案        * 输入"history"即可查看本次运行期间的计算记录        * 输入"setprecision 数字"即可更改显示答案精度 最高不超过20位)"

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

守听

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表