(C++)大数计算问题

文章目录

  • 一、实验目的、内容
  • 二、实验程序设计及结构
    • 1.需求分析
      • 变量
      • 函数
    • 2.设计结构或流程图
  • 三、设计过程
  • 四、测试分析
    • 第一组
    • 第二组
    • 实验中出现的bug及解决方案
  • 五、设计的特点和结果

一、实验目的、内容

大数是超过整数表示范围的整数,针对正整数运算,定义一个大数类,并编写两个大数类对象的加法和减法函数。

二、实验程序设计及结构

1.需求分析

bigu,内含p(unsigned char*)、n(size_t)数据成员及构造函数、析构函数等成员函数。

变量

bigu类型数据ab,用于测试数据。

函数

主函数、运算符重载函数及bigu类的成员函数。

2.设计结构或流程图

  1. 进行ab的输入。(调用构造函数及istream& operator>>(istream& c, bigu& x)
    1. 从输入的第一个数字字符开始,定义unsigned short临时数组(看作256进制数)。
    2. 每输入一个数字字符,每个数组元素乘10。
    3. 遍历临时数组,将超过255的元素执行进位操作;若数组长度不够,重新定义数组并拷贝。
    4. 不断输入直到遇到非数字字符为止。
    5. 将临时数组的数据拷贝进unsigned char数组并存储。
  2. 进行ab的加法并输出。(调用bigu operator+(const bigu& x, const bigu& y)ostream& operator<<(ostream& c, const bigu& x)
    1. 加法运算
      1. 根据整数运算进位的性质,和的元素个数为max(x.n,y.n)max(x.n,y.n)+1,故定义max(x.n,y.n)+1长度的临时数组。
      2. x.ny.n的大小分类讨论。
      3. 将临时数组初始化为xy各位元素之和。
      4. 遍历临时数组,对值超过255的执行进位操作。
      5. 将临时数组的数据拷贝进unsigned char数组并存储。
    2. 输出
      1. 定义临时数组。
      2. 从最高位开始,将超过9的数据进行十进制展开。
      3. 每次加新数之前将原来的所有元素乘256并对超过9的数进行进位。
      4. 输出并释放临时数组。
  3. 比较ab的大小,作差后输出。(调用bool operator>(const bigu& x, const bigu& y)bigu operator-(const bigu& x, const bigu& y)ostream& operator<<(ostream& c, const bigu& x)
    1. 大于运算
      1. 若两者元素个数不同,直接返回结果。
      2. 逐位比较,直到两者不相等为止。
    2. 减法运算(与加法类似)

三、设计过程

#include <iostream>
using namespace std;
class bigu
{
public:unsigned char *p;                                  // 指向正整数数组size_t n;                                          // 数组长度bigu() { *(p = new unsigned char[n = 1]) = '\0'; } // 默认构造函数:初始化为0// 带参数构造(无符号整型)bigu(unsigned long long x){unsigned char a[8], *q(a), *t(q);*q = x;while (x >>= 8)*++q = x; // 逐字节读取*(p = new unsigned char[n = ++q - t]) = *t;while (++t < q)*++p = *t;++(p -= n);}// 为了防止浅拷贝的问题,重写拷贝构造函数bigu(const bigu &x){delete[] p; // 防止内存泄漏const unsigned char *q(x.p);*(p = new unsigned char[n = x.n]) = *q;while (--n)*++p = *++q;++(p -= n = x.n);}~bigu() { delete[] p; } // 析构函数// 为了加快效率、避免拷贝的有参构造函数bigu(unsigned char *a, size_t b){p = a;n = b;}
};
// 重载关系运算符
bool operator>(const bigu &x, const bigu &y)
{if (x.n > y.n)return true;if (y.n > x.n)return false;const unsigned char *p(x.p + x.n), *q(y.p + y.n);doif (*--p > *--q)return true;else if (*p < *q)return false;while (p > x.p);return false;
}
// 重载加法运算符
bigu operator+(const bigu &x, const bigu &y)
{const unsigned char *p(x.p), *q(y.p); // 读取数据// 考虑新数组大小将会是x,y中较大的那个或是较大的加1// 故分类讨论if (y.n > x.n){size_t n(x.n);unsigned short *a(new unsigned short[y.n + 1]), *t(a + y.n); // 定义临时数组// 向临时数组输入数据*a = *p + *q;while (--n)*++a = *++p + *++q;while (++a < t)*a = *++q;// 处理首位if (*(a -= (n = y.n)--) > 255){*(a + 1) += *a / 256;*a %= 256;}// 处理头尾之间while (--n)if (*++a > 255){*(a + 1) += *a / 256;*a %= 256;}// 处理最高位if (*++a > 255) // 超过了unsigned char表示的范围{// 拷贝、释放并返回unsigned char *u(new unsigned char[y.n + 1] + (n = y.n));*u = *a / 256;*a %= 256;do*--u = *--t;while (--n);delete[] t;return bigu(u, y.n + 1);}// 未超过unsigned char表示的范围unsigned char *u(new unsigned char[n = y.n] + y.n);*--u = *a;while (--n)*--u = *--a;delete[] a;return bigu(u, y.n);}// 此时x的位数大于等于y的位数// 操作过程同理if (x.n == 1)return bigu(*p + *q);size_t n(y.n);unsigned short *a(new unsigned short[x.n + 1]), *t(a + x.n);*a = *p + *q;while (--n)*++a = *++p + *++q;while (++a < t)*a = *++p;if (*(a -= (n = x.n)--) > 255){*(a + 1) += *a / 256;*a %= 256;}while (--n)if (*++a > 255){*(a + 1) += *a / 256;*a %= 256;}if (*++a > 255){unsigned char *u(new unsigned char[x.n + 1] + (n = x.n));*u = *a / 256;*a %= 256;do*--u = *--t;while (--n);delete[] t;return bigu(u, x.n + 1);}unsigned char *u(new unsigned char[n = x.n] + x.n);*--u = *a;while (--n)*--u = *--a;delete[] a;return bigu(u, x.n);
}
// 重载减法运算符
// 默认x>=y
bigu operator-(const bigu &x, const bigu &y)
{if (x.n == 1) // 由于y<=x,只需要1字节内存空间{unsigned char *a(new unsigned char[1]);*a = *x.p - *y.p;return bigu(a, 1);}const unsigned char *p(x.p), *q(y.p);             // 读取short *a(new short[x.n]), *t(a), *r(a + x.n - 1); // 定义临时数组*t = *p - *q;size_t n(y.n);while (--n)*++t = short(*++p) - short(*++q); // 由于p,q为无符号指针,需要进行强制类型转换while (++t <= r)*t = *++p;if (*(t = a) < 0){--*(t + 1);*t += 256;} // 对首位进行退位操作while (++t < r)if (*t < 0){*(t + 1) += *t / 256 - 1;(*t %= 256) += 256;} // 对其余各位进行退位操作++t;while (!*--t); // 找到首个大于0的高位// 拷贝数据进新的合适大小的数组unsigned char *u(new unsigned char[n = ++t - a] + n);do*--u = *--t;while (t > a);delete[] a; // 防止内存泄漏return bigu(u, n);
}
// 重载右移运算符,用以输入
istream &operator>>(istream &c, bigu &x)
{delete[] x.p; // 释放原来的数组,防止内存泄漏char s;       // 由于不知道大数的上限,采用逐字节读取方式doc.get(s);while (s == ' ' || s == '\n' || s == '\t'); // 排除空格、水平制表符和换行if (s < '0' || s > '9')                     // 如果输入的不是数字,按0处理{*(x.p = new unsigned char[x.n = 1]) = 0;return c;}unsigned short *a(new unsigned short[x.n = 10]), *b(a), *p; // 定义临时数组,用范围比unsigned char稍大的类型进行临时存储,a指向最低位,b指向目前的最高位*a = s - '0';                                               // 存储第一位c.get(s);while (s >= '0' && s <= '9'){(*(p = a) *= 10) += s - '0'; // 加上新数并乘10(位权)while (++p <= b)*p *= 10;       // 每一位乘10if (*(p = a) > 255) // 最低位超过了unsigned char的范围if (p == b)     // 只有1位的情况{*++b = *p / 256; // 改变尾指针*p %= 256;goto F; // 直接进行下一位的读取}else{*(p + 1) += *p / 256;*p %= 256;}else if (p == b)goto F;     // 只有1位而且不需要处理while (++p < b) // 处理头尾之间的数据if (*p > 255){*(p + 1) += *p / 256;*p %= 256;}if (*p > 255)           // 最高位需要进位if (++b - a == x.n) // 事先的上限不够用,重新申请更大的存储空间并拷贝{unsigned short *u(a), *v(new unsigned short[x.n += 10]);*(p = v) = *a;while (++a < b)*++p = *a;delete[] u;a = v;*(b = p + 1) = *p / 256;*p %= 256;}else // 够用,直接处理{*b = *p / 256;*p %= 256;}F:c.get(s);}// 将处理结果拷贝进unsigned char数组并释放临时数组unsigned char *q(x.p = new unsigned char[x.n = ++b - (p = a)]);*q = *p;while (++p < b)*++q = *p;delete[] a;return c;
}
// 重载左移运算符,用以输出
ostream &operator<<(ostream &c, const bigu &x)
{size_t m(10);                                           // 先假定一个上限unsigned short *t(new unsigned short[m]), *a(t), *b(t); // 用范围比unsigned char稍大的类型进行临时存储,a指向最低位,b指向目前的最高位const unsigned char *q(x.p + x.n);                      // 用于读取数据的指针if ((*t = *--q) > 9)do{*++b = *t / 10;*t %= 10;} while (*++t > 9); // 如果最高位大于等于10while (--q >= x.p){(*(t = a) *= 256) += *q; // 新位加上原来的乘上位权(256)while (++t <= b)*t *= 256; // 各高位乘位权(256)t = a;while (t != b) // 处理头尾之间的位,使它们都小于10{*(t + 1) += *t / 10;*t %= 10;++t;}if (*t > 9) // 如果最高位需要处理{if (false)F:{ // 预先的上限不够用,重新申请更大的存储空间unsigned short *u(t = new unsigned short[m += 30]), *v(a);*u = *a;while (++a < b)*++u = *a;delete[] v;a = t;t = b = u;}// 处理最高位do{if (++b - a == m)goto F;*b = *t / 10;*t++ %= 10;} while (*b > 9);}}c << *b; // 输出最高位while (--b >= a)c << *b; // 输出其余各位delete[] a;  // 释放临时数组return c;
}
// 主函数
// 用以测试数据
int main()
{bigu a, b;cout << "请输入大数a:\n";cin >> a;cout << "请输入大数b:\n";cin >> b;cout << "a+b=" << a + b << endl;if (a > b)cout << "a-b=" << a - b << endl;elsecout << "b-a=" << b - a << endl;system("pause");return 0;
}

四、测试分析

第一组

在这里插入图片描述

第二组

在这里插入图片描述

实验中出现的bug及解决方案

实验中出现的bug:忽略了大数的进位、退位问题。

解决方案:定义更大的临时数据数组并逐位处理。

五、设计的特点和结果

设计采用的数据结构为数组。为了表示大数,把unsigned char数组看作256进制的数,而不是十进制数,节约了内存空间,并利用动态内存分配技术,解决了大数问题。在实验过程中,我原本是打算逐个扩充数组(每次数组长度加1),后来发现运行的效率很低,就采用了和标准库类型vector类似的内存分配方法,每次多扩充29位,解决了效率低的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/412533.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

配置zabbix监控平台

目录 内容纯手敲&#xff0c;难免有误&#xff0c;若发现请私信我。 配置zabbix监控平台 一、进入官网 ​编辑​ 二、配置zabbix-server&#xff08;服务端&#xff09; 1.下载zabbix的yum源 2.安装Zabbix服务器、前端、代理 3.安装Zabbix前端 4.编辑文件/etc/yum.rep…

渗透测试之Kali2022 如何安装Nessus10.3.0

环境: KALI 2022 Nessus 10.3.0 问题描述: Kali2022 如何安装Nessus 10.3.0 A 解决方案: 1.Kali里面用浏览器前往官网下载Nessus https://www.tenable.com/downloads/nessus2.打开文件所在文件夹,在里面打开终端 dpkg -i Nessus-10.3.0-debian9_amd64.deb ──(ro…

投简历没回复?先做到这点。。

大家好&#xff0c;我是程序员鱼皮。 秋招告一段落&#xff0c;几家欢喜几家愁。不过这都无所谓了&#xff0c;上岸的同学继续努力&#xff0c;没上岸的同学发现问题&#xff0c;抓紧准备春招才是。 如果你投了几百份简历都没回复&#xff0c;那么一定有原因。比如环境、运气、…

蓝桥杯每日一题---基数排序

题目 分析 在实际的比赛过程中很少会自己手写排序&#xff0c;顶多是定义一下排序规则。之所以要练习一下基数排序&#xff0c;是因为在后续学习过程中学到后缀数组时需要自己手写基数排序&#xff0c;那么这里使用的方法也和后缀数组一致&#xff0c;理解这里也便于后缀数组的…

LabVIEW交变配流泵性能测试系统

利用LabVIEW软件与高级硬件结合&#xff0c;开发交变配流泵性能测试系统。该系统不仅提高了测试精度&#xff0c;还优化了工业自动化流程&#xff0c;代表了液压系统测试技术的进步。 开发了一种高精度的测试系统&#xff0c;该系统能够综合评估交变配流泵的性能&#xff0c;包…

架构篇04-复杂度来源:高性能

文章目录 单机复杂度集群的复杂度小结 从本篇开始&#xff0c;我们一起深入分析架构设计复杂度的 6 个来源&#xff0c;先来聊聊复杂度的来源之一高性能。 对性能孜孜不倦的追求是整个人类技术不断发展的根本驱动力。例如计算机&#xff0c;从电子管计算机到晶体管计算机再到集…

网页设计(六)表格与表格页面布局

一、设计《TF43: 前端的发展与未来》日程表 《TF43: 前端的发展与未来》日程表 文字素材&#xff1a; 前端是互联网技术的重要一环&#xff0c;自上世纪80年代万维网技术创立以来&#xff0c;Web成就了大量成功的商业公司&#xff0c;也诞生了诸多优秀的技术解决方案。因其标…

python贪吃蛇游戏

为了实现这个游戏&#xff0c;需要用到Python的pygame模块&#xff0c;它是一个专门用于开发游戏的模块&#xff0c;提供了很多方便的功能&#xff0c;比如窗口、图形、音效、事件处理等。 用pygame来创建一个窗口&#xff0c;设置游戏的背景色&#xff0c;画出蛇和食物&#…

什么是关键字?C语言的关键字有哪些?

目录 一、问题 二、解答 1、数据类型关键字&#xff08;12个&#xff09; (1) 声明和定义的区别 (2) 数据类型关键字 • char&#xff1a;声明字符型变量 1、声明字符变量 2、字符数组 3、ASCII码表示 4、指针与字符数组 5、多字节字符集&#xff08;如UTF-8&#xff…

Flutter中使用minio_new库

前言 在移动开发中&#xff0c;我们常常会遇到需要在App中处理文件上传和下载的需求。Minio是一个开源的对象存储服务&#xff0c;它兼容Amazon S3云存储服务接口&#xff0c;可以用于存储大规模非结构化的数据。 开始之前 在pubspec.yaml文件中添加minio_new库的依赖&#xf…

mac下配置git自定义快捷命令

1. 指定自定义别名 vi ~/.bash_profile open ~/.bash_profile 配置环境变量,插入类似下面的内容 .bash_profile文件 alias gcgit checkout alias gmgit commit -m alias gcbgit checkout -balias gtgit statusalias gagit add .alias glggit logalias gdgit diffalias gr…

一文教你V3+TS(保姆级教程)

TS 与 JS 的区别 基础类型 ts 的常用类型 ts 的常用基础类型分为两种&#xff1a; js 已有类型 原始类型&#xff1a;number/string/boolean/null/undefined/symbol 对象类型&#xff1a;object&#xff08;包括&#xff0c;数组、对象、函数等对象&#xff09; 每次编写前…