大数运算#

在这里插入图片描述
 大数,就是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,一经查实,立即删除!

相关文章

乘法口诀表的C语言编程

#include "stdio.h"int main() {int i,j,q0;for(i 1;i < 10; i){for(j 1;j < 10;j){q i*j;printf("%d*%d%d\n",i,j,q);}}} 按照课本上的排列做出的优化 #include "stdio.h"int main() {int i,j;for(i 1;i < 10; i){for(j 1;j <…

打印100-200之间的素数

素数 是指除了1和它本身以外,不能被任何整数整除的数 例如17就是素数,因为它不能被2~16的任一整数整除。 #include "stdio.h"int main() {int i,j;for(i 100; i < 200; i){for(j 2;j < i-1;j){if(i%j 0)break;}if(j i)printf("%d\n",i);}} C语言…

判断1000-2000之间的闰年(优化写法)

闰年普通年&#xff08;不能被100整除的年份&#xff09;能被4整除的为闰年。&#xff08;如2004年就是闰年,1999年不是闰年&#xff09;&#xff1b;世纪年&#xff08;能被100整除的年份&#xff09;能被400整除的是闰年。(如2000年是闰年&#xff0c;1900年不是闰年)&#x…

四种方法实现数组交换

方法一&#xff1a; //该方法主要用逻辑运算将数组对应的每个元素进行交换&#xff0c;然后用for循环将整个数组元素进行交换#include<stdio.h>int main(){ int i,j,k;int A[10];int B[10];int C[10];printf("请输入A数组的内容&#xff1a;\n");for(i0;i<1…

结构体变量初始化

// // main.c // C语言学习 #include <stdio.h> int main(int argc, const charchar * argv[]) { //定义结构体类型 struct Person { charchar *name; int age; double heigth; }; //初始化的4种方式 //1.定义的同时初始化 struct Person p1 {"z…

C语言的细小知识点整理

1、register修饰符暗示编译程序相应的变量将被频繁地使用&#xff0c;如果可能的话&#xff0c;应将其保存在CPU的寄存器中&#xff0c;以加快其存储速度 2、static是某个特定函数的局部变量&#xff0c;即只能在定义该变量的函数内使用该变量 static int a 40; char …

二维数组初始化规则

二维数组初始化的形式为&#xff1a;数据类型 数组名[整常量表达式][ 整常量表达式]{ 初始化数据 }&#xff1b;在{ }中给出各数组元素的初值&#xff0c;各初值之间用逗号分开。把{ }中的初值依次赋给各数组元素。有如下几种初始化方式&#xff1a;⑴ 分行进行初始化int a[2][…

linux之缓冲区

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

输出一个整数的每一位(3种方法)

1.使用数组按个数输入再按照个数输出 int i, j, k, num, count;int a[10];printf("几位数\n");scanf("%d", &k);for (i 1; i < k; i){scanf("%d", &a[i]);}for (i k; i > 1; i--){printf("%d\n", a[i]);} 2.使用递归…

linux之地址空间

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

C语言操作符 进阶 (常见错误及细节)

1.算术操作符- * / % % 只适用于整数类型运算&#xff0c;其余运算符也可用于浮点运算。2.移位操作符 左移&#xff1a;左边丢弃&#xff0c;右边补0&#xff1b; 右移&#xff1a;不同编译器采取的移位方式不同&#xff0c;所有有了“右移”的程序不可移植1.逻辑移位&#xff…

输出该数二进制表示中1的个数。求取十进制数字元素1的个数 (3种方法)

/* ***求取十进制数字元素1的个数 */int fun(int x) {int count 0;int i, j, k;/***方法2 负数不可计算&#xff0c;需要改进*/while (x ! 0){if (x & 1 1){count;}x x >> 1;}/****方法1*/while (x ! 0){x x&(x - 1);count;}return count; }int main() {in…

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…

可变参数列表

一个函数在不同的时候接受不同数目的参数。 stdarg宏可变参数列表是通过宏来实现的&#xff0c;这些宏定义于stdarg.h头文件中。这个头文件声明了一个类型va_list和三个宏---va_start,va_arg,va_end。va_list用于声明变量的类型。va_start准备访问可变参数。va_arg用于访问参数…

完成猜数字游戏 //C语言 猜数字游戏(编写过程详解)

int i, j, k;int num 0;/*生成随机数字*/num rand();printf("%d\n", num); 选择玩游戏还是退出 void play(int x) {printf("%d\n", x);printf("开始游戏"); } scanf("%d", &k);switch (k){case 1:play(num);case 2:break;} 循环…

静态顺序表

顺序表是在计算机内存中以数组的形式保存的线性表&#xff0c;是指用一组地址连续的存储单元依次存储数据元素的线性结构。线性表采用顺序存储的方式存储就称之为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中。 顺序表分为静态存储的顺序表和动…

C语言 浅谈可变参数

1.可变参数产生原因 首先来看一个简单的例子。 int Add(int x, int y) {return x y; } int main() {int sum 0;sum Add(1, 2);//sum Add(1, 2, 3);//sum Add(1);system("pause");return 0; } 我们可以看到&#xff0c;对于这个代码只可以计算两个数的加法。 …

有两个链表a,b,设结点包括学号,姓名。从a链表中删去与b链表中有相同学号的那些结点。

#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct linknode { int num;char name[20];struct linknode *next; }node; node *creat() { node *h NULL,*s,*t;int d;int i 1; char name1[20];while(1) { printf("输入第…

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

strlen() strlen所作的仅仅是一个计数器的工作&#xff0c;它从内存的某个位置 &#xff08;可以是字符串开头&#xff0c;中间某个位置&#xff0c;甚至是某个不确定的内存区域&#xff09; 开始扫描&#xff0c;直到碰到第一个字符串结束符\0为止&#xff0c;然后返回计数…

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

strcpy(dest,src) strcpy是一种C语言的标准库函数&#xff0c;strcpy把从src地址开始且含有\0结束符的字符串复制到以dest开始的地址空间&#xff0c;返回值的类型为char*。 char * my_strcpy(char *str2, char *str1) {assert(*str2);assert(*str1);while(*str1!0){ *str2 …