大数运算#

在这里插入图片描述
 大数,就是C/C++中利用基本类型所不能存储的数字,少则数十位,大则几万位,如何存储和计算大数就是本文的内容。

 在C和C++中,没有存储大数的数据结构,就算 unsigned long long也只能表示19位的数字
在这里插入图片描述
 如果我们用double则会出现精度不准确的问题,如果我们想精确储存计算大数,学习本文是必要的。
 存储大数的方法有两种,不管是数组还是字符串,在运算时他们的原理其实是相同的。
看下边两道题,带你了解大数的计算方法

字符串相加
在这里插入图片描述
在这里插入图片描述
 这道题的思路很简单,不能将字符串转换为整数形式,就算转了我们也过不了这道题。因为数据的范围很大。
在这里插入图片描述
 长度为一万的数字字符串,这就是一个很大的数了。
 解决思路:还记得我们小学时是如何进行加法运算的吗?我们从地位算起,如果两个加数和大于10,我们就会进一,按照这种思路依次进行计算,知道求出结果为止。
在这里插入图片描述
通过这种思路我们可以写出这样的代码

class Solution {
public:string addStrings(string num1, string num2) {int i = num1.length() - 1, j = num2.length() - 1, add = 0;string ans = "";while (i >= 0 || j >= 0) {int x = i >= 0 ? num1[i] - '0' : 0;int y = j >= 0 ? num2[j] - '0' : 0;int result = x + y + add;ans.insert(ans.begin(),'0' + result % 10);add = result / 10;i -= 1;j -= 1;}return ans;}
};

 可以看出,计算时是从字符串末尾一次项前进行求和计算。如果该数大于10,就会将进位更新为1,改为的结果直接将相加后的值模上10的计算结果头插进去即可。
在这里插入图片描述

 三目运算符十分巧妙,在求和时,要一直将两数组的元素全部加一遍,如果短的数组已经加完就作为0,这样也不会出现越界访问,还解决了要判断是哪个数组更短的问题,统一对待。在每次对应位计算完成之后更新add(进位数)。然后继续加进位的数字。
信心满满提交
在这里插入图片描述
 最后一次进位的情况被我们忽略了,就像上边的错误用例一样。所以当i和j全部减到零,并且进位add也等于0时循环结束。

class Solution {
public:string addStrings(string num1, string num2) {int i = num1.length() - 1, j = num2.length() - 1, add = 0;string ans = "";while (i >= 0 || j >= 0 || add != 0) {int x = i >= 0 ? num1[i] - '0' : 0;int y = j >= 0 ? num2[j] - '0' : 0;int result = x + y + add;//该位置上两个数字求和结果ans.insert(ans.begin(),'0' + result % 10);add = result / 10;i -= 1;//向前一位进发j -= 1;}return ans;}
};

这道题就完成了。
就算两个字符串很长很长,计算也很快,结果也是准确的。
在这里插入图片描述

用数组进行存储运算

 用数组存储的话,要保证数组中任意元素不大于10,这才是无误的存储方法,如果某个元素大于10,那就全乱了,一般请况下我们都是用数组进行存储大数操作,而不是计算。就算是要计算的话还要给你提供每个元素都是小于10的数字,用上边字符串的思路进行计算就可以了。

存储大数,一般是通过数组保存运算后很大的数字。
例如求某数的阶乘
在这里插入图片描述
100的阶乘long long就已经受不了了,那么如何进行精确计算呢?
还是回忆小学时候我们如何计算乘法的呢?
在这里插入图片描述
 上边的字符串相加的题目中,我们可以发现进位add只有两种,0或者1,因为就算两个9相加,结果也还是18,进位仍然是1,在这里就不同了。
 我们可以把99*99看做在数组中保存的两个9分别乘以99,他们在数组中的位置表示他们的位数。
在这里插入图片描述
 如果是求阶乘的话,就是要将两个数字相乘之后的数字再乘以一个数而已,同样的思路,多了一层循环。
 就像上边,再乘以98的话,就是数组中每一位的数字都乘以98,然后重复上边的操作就可以了。在乘以下一个数之前,要知道上一次乘完的结果的位数,起始时可以将计算的第一个数字乘以1,然后判断出位数,再次运算时就使数组中每一位的数字乘以要乘以的数字。
 例如100的阶乘,让数组中首元素为1,第一次运算完成之后数组中前三个元素就是0,0,1,有三位数字,位数为cout=3。然后乘以99,就是数组中前三个元素乘以99,前两个数字不变,最后的数字是大于10的,在进位结束后,判断数组下标为2(一共3位数字,最后一位下标为2)的位置是否大于10,如果大于就进位,此时需要进位一个9,同时位数cout加1,当然,这是一个循环,如果最后一位乘的数不是99而是101,就要进位两次,第一次进位10,第二次进位1,当然位数就要加2。
有了上边的思路就可以写代码了

int main()
{int num = 0;scanf("%d", &num);if (num == 0){printf("1");}int a[10000] = { 0 };a[0] = 1;int cout = 1;//分为三步处理for (int i = num; i > 0; i--){int j = 0;//cout是位数,将所有的位数都乘以i。for (; j < cout; j++){a[j] *= i;}//将每个位判断一下,如果大于等于10,就向前进位for (int k = 0; k < cout; k++){if (a[k] >= 10){a[k + 1] += a[k] / 10;a[k] = a[k] % 10;}}//从最后一位进行判断,找到新的位数for (int l = cout; a[l] >0; l++){cout++;a[l + 1] = a[l] / 10;a[l] = a[l] % 10;}		}for (int i = cout-1; i >0; i--)//从后向前遍历打印{printf("%d ", a[i]);}return 0;
}

 在循环结束时的cout就是结果的位数,同是数组中存放的就是结果的逆序。我在里开的空间是10000,如果计算出的数位数更大的话可以扩宽数组大小。
 本文到这里就结束啦,有用的话留一个赞再走叭,如果你的慧眼金睛发现了问题,一定要说哦,我会虚心改正哒。

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

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

相关文章

linux之缓冲区

行缓冲。在这种情况下&#xff0c;当在输入和输出中遇到换行符时&#xff0c;标准I/O库执行I/O操作。这允许我们一次输出一个字符&#xff0c;但只有在写了一行之后才进行实际I/O操作。当流涉及一个终端时&#xff0c;通常使用行缓冲。 第一个例子&#xff1a;&#xff08;he…

linux之地址空间

程序&#xff1a;一组指令的有效集合。它是静态的&#xff0c;不具有任何的运行意义。程序最终转换为二进制文件。 进程&#xff1a;程序的执行就是进程。可以把它看成独立的程序&#xff0c;在内存中有其对应的代码空间和数据空间。一个进程所拥有的数据和代码只属于自己。进…

C语言随机数生成超详解

1.首先来看一段简单的代码 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <time.h>int main(void) {int i;printf(" %6d\n", rand());system("pause"); }printf(" %6d\n", rand());sys…

模板

模板是泛型编程的基础&#xff0c;即与类型无关的逻辑代码。 利用模板机制可以显著减少冗余信息&#xff0c;能大幅度地节约程序代码&#xff0c;进一步提高面向对象程序的可重用性和可维护性。 模板是实现代码重用机制的一种工具&#xff0c;它可以实现类型参数化&#xff1b;…

linux-----强大的find

我又回来了。哈哈。今天我们来说一下linux中的另一个强大的find命令&#xff0c;灰常重要&#xff0c;灰常重要&#xff0c;灰常重要。显而易见&#xff0c;find就是对某一个文件或者目录的查找喽。但是它的一个显著的特点就是&#xff1a;一般放在后台执行&#xff0c;从整个文…

C语言模拟实现标准库函数之strcmp()

strcmp() C/C函数&#xff0c;比较两个字符串 设这两个字符串为str1&#xff0c;str2&#xff0c; 若str1str2&#xff0c;则返回零&#xff1b; 若str1<str2&#xff0c;则返回负数&#xff1b; 若str1>str2&#xff0c;则返回正数。 char * my_strcmp(char *key,…

linux之task_struct

每个进程中都有一个进程控制块--PCB。PCB--维护进程相关的信息。然而&#xff0c;linux内核的进程控制块就是task_struct结构体&#xff0c;它可以保存进程的信息。 所有运行在系统里的进程都以task_struct链表的形式存在内核里。 每个进程都将它的信息放在task_struct结构体…

C语言模拟实现标准库函数之memcpy()

memcpy&#xff08;&#xff09; 1.如果我们需要对一个数组初始化&#xff0c;把数组的内容全部置0&#xff0c;那么能不能用strcpy() int main() {char arr1[10] { 0 };char arr2[10] " abcdefg ";strcpy(arr2, arr1);system("pause");return 0; } 我…

说说堆及堆排序

堆&#xff1a;是一种数组对象&#xff0c;它可以被看成是一种二叉树结构。 我们把堆的二叉树存储方式分为两种&#xff1a;即大堆和小堆。那么问题来了&#xff0c;什么大堆&#xff1f;什么是小堆&#xff1f; 大堆&#xff1a;让每个父节点的值都大于孩子节点的值。 小堆…

linux之父子进程的输出

首先&#xff0c;我们来回忆一下父进程与子进程&#xff0c;前几节讲了如何创建子进程&#xff0c;像这样的&#xff0c;pid_t id fork(); 这样我们就创建好了一个子进程&#xff0c;然而fork()函数的返回值是什么呢&#xff1f;这里要记住&#xff1a;子进程返回0&#xff0c…

linux---谈谈vfork和fork的区别及exit与return

fork()&#xff1a;创建子进程的函数&#xff0c;是大家比较熟悉的吧。pid_t id fork(); 这里的vfork();也是创建子进程的函数。现在我们来剖析一下它们吧。 第一例&#xff1a; 先看一个fork()的例子哦。 对于fork()而言&#xff0c;创建子进程成功后直接打印出父子进程执…

C语言模拟实现标准库函数之qsort()

qsort 编译器函数库自带的快速排序函数。 void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*)); 参数解释&#xff1a; void*base-待排序数组首地址size_t num-数组中待排序元素数量size_t width-各元素的占用空间大小int(__cde…

linux之管道

管道&#xff08;PIPE&#xff09;是linux中一个重要的通信方式&#xff0c;在进程中&#xff0c;我们通过从一个进程中读取到的数据转到另一个进程中的写数据中&#xff0c;这时就要有不同的进程之间共享同一份资源&#xff0c;就是所谓的进程间通信。由于进程的特点是资源独占…

linux之多线程(1)

我们之前讲了进程&#xff0c;今天我们重新认识另外一个概念---线程。我们首先会想到的是进程和线程有什么区别和联系&#xff0c;对吧&#xff1f;进程是由程序执行起来&#xff0c;跑在操作系统的&#xff0c;是系统进行资源分配和调度的基本单位。进程具有资源独占性&#x…

linux之睡眠函数(my_sleep)

我们在程序中&#xff0c;很多次用到sleep()函数&#xff0c;让它睡眠几秒后再执行该进程。今天呢&#xff0c;我要给大家实现一下sleep函数。 看看代码哦&#xff1a; 运行结果&#xff1a; 结果中每隔三秒钟&#xff0c;打印一条语句。实现了sleep(3)的功能。 关于sleep函数…

C语言 防止头文件被多次引用

comm.h和comm.c是公共模块。 test1.h和test1.c使用了公共模块。 test2.h和test2.c使用了了公共模块。 test.h和test.c使⽤用了了test1模块和test2模块。 这样最终程序中就会出现两份comm.h的内容。这样就造成了了文件内容的重复。 1.方法1 文件开头加上这一句就ok #prag…

详解强制类型转换

今天谈谈类型转换的问题吧&#xff0c;之前我们也遇到过类型转换&#xff0c;比如c语言中这样的赋值&#xff1a; 显然&#xff0c;i和j是不同类型的变量&#xff0c;但是却可以完成赋值&#xff0c;结果是这样的&#xff1a; 其实它们是做了隐式的类型转换&#xff0c;相当于&…

c++之类型萃取

刚刚我们接触过模板类&#xff0c;类似于这样的&#xff1a; 在这个类中&#xff0c;我们如何知道它是什么类型的呢&#xff1f;这里&#xff0c;我们可以在类中加入一个内嵌类型&#xff0c;如&#xff1a; 这样就可以知道它是用户自定义的还是本身类型就拥有的&#xff0c;我…

时间复杂度空间复杂度

我们编过不少代码&#xff0c;起初学习的时候我们习惯性的认为&#xff0c;只要代码能正确的运行就ok啦~很少考虑代码的优化带来的好处。今天说一下影响代码性能的两个重要指标--时间复杂度&空间复杂度。 时间复杂度&#xff1a;就是函数&#xff08;指数学中的函数&#…

C语言 函数递归例题解析

1.接受一个整形值&#xff08;无符号&#xff09;&#xff0c;把它转换为 字符并打印它模拟实现strlen()函数。3.求n的阶乘4.斐波那契数列总结 1.接受一个整形值&#xff08;无符号&#xff09;&#xff0c;把它转换为 字符并打印它 void fun(int x) {if (x > 9){fun(x/10)…