大数运算之C语言实现
一、 前言
在我们代码编程过程中,我们经常需要处理各种规模的数值。从日常工作中的一些简单算术在到科学研究中的复杂计算,数字无处不在。然而,当数值变的异常庞大时,就需要用到大数运算来进行实现。本文我们将介绍大数运算的基本概念以及C语言实现大数运算的方法。
二、 概念
我们常见的数据其数据范围大都在int(-2^31 ~ 2^31-1)或者long long( -2^62 — 2^62-1)之内,但在一些情况下,我们会遇到超过这个范围的数据,这些数据我们就称之为大数。当然,大数不只是大整数,对于位数较多的小数,如123456799.987654321也适用于大数运算。
大数运算涉及对超出常规数据类型范围的数字进行加减乘除,阶乘,取余等运算。对于大数,我们通常以字符数组的形式存储,因为单个变量无法容纳如此多的位数,其中每个数组元素都对应一个数位。而实现这些运算的大致思路都是模拟竖式计算的过程,即通过模拟进位,借位,取余操作完成计算。
三、 代码实现
下面我们将对大数进行加减乘除,阶乘,取余等运算。
-
大数加法运算
#include <stdio.h> #include <stdlib.h> #include <string.h>// 函数声明 char* reverseString(const char* str); char* addLargeNumbers(const char* num1, const char* num2);// 主函数 int main() {// 输入两个大数char num1[1001]; // 假设大数的最大位数为1000,多加一位用于存储字符串结束符'\0'char num2[1001];printf("请输入第一个大数: ");scanf("%1000s", num1); // 限制输入长度,防止缓冲区溢出printf("请输入第二个大数: ");scanf("%1000s", num2);// 调用大数相加函数char* result = addLargeNumbers(num1, num2);// 输出结果printf("结果: %s\n", result);// 释放动态分配的内存free(result);return 0; }// 字符串反转函数 char* reverseString(const char* str) {int len = strlen(str);char* reversed = (char*)malloc((len + 1) * sizeof(char)); // 分配内存用于存储反转后的字符串for (int i = 0; i < len; i++) {reversed[i] = str[len - 1 - i]; // 反转字符串}reversed[len] = '\0'; // 添加字符串结束符return reversed; }// 大数相加函数 char* addLargeNumbers(const char* num1, const char* num2) {char* reversedNum1 = reverseString(num1); // 反转字符串,便于从低位开始相加char* reversedNum2 = reverseString(num2);int len1 = strlen(reversedNum1);int len2 = strlen(reversedNum2);int maxLen = len1 > len2 ? len1 : len2;int carry = 0; // 进位char* result = (char*)malloc((maxLen + 2) * sizeof(char)); // 分配内存用于存储结果,多加一位用于可能的进位和一位用于字符串结束符// 从低位开始逐位相加for (int i = 0; i < maxLen; i++) {int digit1 = i < len1 ? reversedNum1[i] - '0' : 0;int digit2 = i < len2 ? reversedNum2[i] - '0' : 0;int sum = digit1 + digit2 + carry;carry = sum / 10;result[i] = sum % 10 + '0';}// 处理剩余的进位if (carry) {result[maxLen] = carry + '0';maxLen++;}// 添加字符串结束符result[maxLen] = '\0';// 反转结果字符串,得到正确的顺序char* finalResult = reverseString(result);free(reversedNum1); // 释放反转后的输入字符串内存free(reversedNum2);free(result); // 释放中间结果字符串内存return finalResult; // 返回最终结果字符串 }演示:

-
大数减法运算
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h>// 函数声明 char* reverseString(const char* str); char* subtractLargeNumbers(const char* num1, const char* num2);// 主函数 int main() {// 输入两个大数char num1[1001]; // 假设大数的最大位数为1000,多加一位用于存储字符串结束符'\0'char num2[1001];printf("请输入被减数: ");scanf("%1000s", num1); // 限制输入长度,防止缓冲区溢出printf("请输入减数: ");scanf("%1000s", num2);// 验证被减数是否大于等于减数(简单比较字符串长度,如果不等则按字典序比较)if (strlen(num1) < strlen(num2) || (strlen(num1) == strlen(num2) && strcmp(num1, num2) < 0)) {printf("错误: 被减数必须大于等于减数。\n");return 1;}// 调用大数相减函数char* result = subtractLargeNumbers(num1, num2);// 输出结果printf("结果: %s\n", result);// 释放动态分配的内存free(result);return 0; }// 字符串反转函数(与大数加法中相同) char* reverseString(const char* str) {int len = strlen(str);char* reversed = (char*)malloc((len + 1) * sizeof(char));for (int i = 0; i < len; i++) {reversed[i] = str[len - 1 - i];}reversed[len] = '\0';return reversed; }// 大数相减函数 char* subtractLargeNumbers(const char* num1, const char* num2) {char* reversedNum1 = reverseString(num1);char* reversedNum2 = reverseString(num2);int len1 = strlen(reversedNum1);int len2 = strlen(reversedNum2);int maxLen = len1;bool isNegative = false; // 标记结果是否为负数(本实现假设被减数大于等于减数,所以结果不为负数)char* result = (char*)malloc((maxLen + 1) * sizeof(char)); // 分配内存,注意这里不需要额外位用于借位,因为我们已经假设被减数足够大// 从低位开始逐位相减for (int i = 0; i < maxLen; i++) {int digit1 = i < len1 ? reversedNum1[i] - '0' : 0;int digit2 = i < len2 ? reversedNum2[i] - '0' : 0;int diff = digit1 - digit2;// 如果当前位不够减,则从前一位借位if (diff < 0) {diff += 10;// 注意:这里我们不需要修改前一位的值,因为我们是逐位计算并存储结果的// 但是在实际实现中,如果需要保留借位的过程,可以引入一个额外的数组来记录借位情况}result[i] = diff + '0';}// 去除结果前导零int start = 0;while (start < maxLen && result[start] == '0') {start++;}// 如果整个结果都是0,则结果应为"0"if (start == maxLen) {strcpy(result, "0");} else {// 将结果字符串前移,以去除前导零for (int i = 0; i < maxLen - start; i++) {result[i] = result[start + i];}result[maxLen - start] = '\0';}// 反转结果字符串,得到正确的顺序char* finalResult = reverseString(result);free(reversedNum1);free(reversedNum2);free(result); // 注意:这里释放的是去除前导零之前的result内存return finalResult; }演示:

-
大数乘法运算
#include <stdio.h> #include <stdlib.h> #include <string.h>char* multiplyLargeNumbers(const char* num1, const char* num2);int main() {char num1[1001], num2[1001];printf("请输入第一个大数: ");scanf("%1000s", num1);printf("请输入第二个大数: ");scanf("%1000s", num2);char* result = multiplyLargeNumbers(num1, num2);printf("结果: %s\n", result);free(result - (result[0] == '0' && *(result + 1) == '\0')); // Adjust free pointer if leading '0' was logically removedreturn 0; }char* multiplyLargeNumbers(const char* num1, const char* num2) {int len1 = strlen(num1);int len2 = strlen(num2);int maxLen = len1 + len2;char* result = (char*)calloc(maxLen + 1, sizeof(char)); // +1 for null terminator// Initialize result array with zerosmemset(result, '0', maxLen);result[maxLen] = '\0';// Perform multiplicationfor (int i = len1 - 1; i >= 0; i--) {for (int j = len2 - 1, k = i + j; j >= 0; j--, k--) {int mul = (num1[i] - '0') * (num2[j] - '0');int sum = mul + (result[k + 1] - '0');result[k + 1] = (sum % 10) + '0';result[k] += sum / 10;if (result[k] > '9') {int carry = result[k] - '0' / 10;result[k] = (result[k] - carry * 10) + '0';if (k > 0) {result[k - 1] += carry;} else {// Handle carry overflow, resize result if necessarychar* temp = (char*)realloc(result, maxLen + 2);if (temp) {result = temp;memmove(result + 1, result, maxLen + 1);result[0] = '0' + carry;maxLen++;} else {// Allocation failed, handle errorfree(result);return NULL;}}}}}// Find the start of the non-zero part of the resultint start = 0;while (start < maxLen && result[start] == '0') {start++;}// Shift the result to the left and null-terminate itmemmove(result, result + start, maxLen - start + 1);return result; }演示:

-
大数除法及取余运算
#include <stdio.h> #include <string.h>void divideLargeNumber(int *largeNumberArray, int divisionFactor, int numberOfDigits);int main() {char largeNumberStr[1000]; // 存储大整数的字符串int divisor; // 除数printf("请输入一个大整数(不超过999位)和一个除数(以空格分隔):");scanf("%s%d", largeNumberStr, &divisor);int largeNumberDigits[1000]; // 存储大整数的每一位数字int numberLength = strlen(largeNumberStr); // 大整数的长度for (int i = 0; i < numberLength; i++)largeNumberDigits[i] = largeNumberStr[i] - '0';divideLargeNumber(largeNumberDigits, divisor, numberLength);return 0; }void divideLargeNumber(int *largeNumberArray, int divisionFactor, int numberOfDigits) // 开始操作 {int partialSum = 0; // 当前部分和(累加当前位及之前的数字)int firstDigitOutputFlag = 0; // 标记是否已输出第一个非零商位int remainder = 0; // 余数for (int i = 0; i < numberOfDigits; i++) // 这里没有将商存下来,而是找到一位就输出{partialSum += largeNumberArray[i];if (partialSum < divisionFactor && firstDigitOutputFlag){remainder = partialSum; // 记录有可能最后加上最后一位还是小于divisionFactor的情况的余数printf("0"); // 输出商位为0的情况}if (partialSum >= divisionFactor){printf("商位: %d", partialSum / divisionFactor);partialSum %= divisionFactor; // 更新余数remainder = partialSum; // 记录最后加上最后一位大于divisionFactor的情况的余数partialSum *= 10; // 为下一位数字做准备firstDigitOutputFlag = 1; // 在找到第一个商位之后改变标记状态}else{partialSum *= 10; // 如果当前部分和小于除数,则继续累加下一位数字}}printf("\n");printf("余数:%d\n", remainder); // 输出余数 }演示:

-
大数阶乘运算
#include <stdio.h> #include <string.h> #include <stdbool.h>#define MAX_DIGITS 1000 // 假设最大阶乘位数不超过1000// 辅助函数:打印大数 void printLargeNumber(int result[], int length) {for (int i = length - 1; i >= 0; i--) {printf("%d", result[i]);}printf("\n"); }// 大数阶乘函数 void factorialLargeNumber(int n, int result[], int* length) {// 初始化结果数组为1(阶乘的初始值)memset(result, 0, sizeof(int) * MAX_DIGITS);result[0] = 1;*length = 1;// 计算阶乘for (int i = 2; i <= n; i++) {int carry = 0; // 进位for (int j = 0; j < *length; j++) {int product = result[j] * i + carry;result[j] = product % 10; // 当前位的值carry = product / 10; // 进位}// 处理进位while (carry) {result[*length] = carry % 10;carry = carry / 10;(*length)++;}} }int main() {int n;printf("请输入一个整数: ");scanf("%d", &n);int result[MAX_DIGITS];int length = 0;factorialLargeNumber(n, result, &length);printf("%d! = ", n);printLargeNumber(result, length);return 0; }演示:

四、小结
好了,关于大数运算的代码实现到我们这里就结束了,后面遇到其它我会在继续接着补充,希望对大家有所帮助。
相关文章:
大数运算之C语言实现
一、 前言 在我们代码编程过程中,我们经常需要处理各种规模的数值。从日常工作中的一些简单算术在到科学研究中的复杂计算,数字无处不在。然而,当数值变的异常庞大时,就需要用到大数运算来进行实现。本文我们将介绍大数运算的基本…...
安装最小化的CentOS7后,执行yum命令报错Could not resolve host mirrorlist.centos.org; 未知的错误
文章目录 安装最小化的CentOS7后,执行yum命令报错"Could not resolve host: mirrorlist.centos.org; 未知的错误"错误解决方案: 安装最小化的CentOS7后,执行yum命令报错"Could not resolve host: mirrorlist.centos.org; 未知…...
Avalonia+ReactiveUI跨平台路由:打造丝滑UI交互的奇幻冒险
一、引言 在当今数字化时代,跨平台应用开发已成为大势所趋。开发者们迫切需要一种高效、灵活的方式,能够让应用程序在不同操作系统上无缝运行,为用户提供一致的体验。Avalonia 和 ReactiveUI 的组合,宛如一对天作之合的舞者&…...
Java导出通过Word模板导出docx文件并通过QQ邮箱发送
一、创建Word模板 {{company}}{{Date}}服务器运行情况报告一、服务器:总告警次数:{{ServerTotal}} 服务器IP:{{IPA}},总共告警次数:{{ServerATotal}} 服务器IP:{{IPB}},总共告警次数:{{ServerBTotal}} 服务器IP:{{IPC}}&#x…...
Linux系统编程:进程状态和进程优先级/nice
目录 一,相对于OS的进程状态 1.1运行状态 1.2阻塞状态 1.3挂起状态 二,并发执行与进程切换 2.1,CPU并发执行 2.2进程切换 三,Linux内核管理进程状态的方法 3.1查看进程状态 3.2R状态 3.3S状态 3.4D状态 3.5T状态 3.6X状态 3.7Z状态 3.8孤儿进程 四,进程优先级 …...
JavaScript系列(40)--虚拟DOM实现详解
JavaScript虚拟DOM实现详解 🌳 今天,让我们深入了解虚拟DOM的实现原理,这是现代前端框架中非常重要的一个概念,它通过最小化实际DOM操作来提升应用性能。 虚拟DOM基础概念 🌟 💡 小知识:虚拟D…...
SpringAI基于API对大语言模型调用
引言 随着人工智能技术的迅猛发展,大型语言模型(LLM)在各个领域的应用越来越广泛。SpringAI作为一个旨在简化AI集成的框架,为开发者提供了高效、便捷的工具来连接和调用这些大模型。本文将详细探讨如何使用SpringAI整合通义千问等…...
0 基础学运维:解锁 K8s 云计算运维工程师成长密码
前言:作为一个过来人,我曾站在技术的门槛之外,连电脑运行内存和内存空间都傻傻分不清,完完全全的零基础。但如今,我已成长为一名资深的k8s云计算运维工程师。回顾这段历程,我深知踏上这条技术之路的艰辛与不…...
在 vscode + cmake + GNU 工具链的基础上配置 JLINK
安装 JLINK JLINK 官网链接 下载安装后找到安装路径下的可执行文件 将此路径添加到环境变量的 Path 中。 创建 JFlash 项目 打开 JFlash,选择新建项目 选择单片机型号 在弹出的窗口中搜索单片机 其他参数根据实际情况填写 新建完成: 接下来设置…...
【全栈】SprintBoot+vue3迷你商城(9)
【全栈】SprintBootvue3迷你商城(9) 往期的文章都在这里啦,大家有兴趣可以看一下 后端部分: 【全栈】SprintBootvue3迷你商城(1) 【全栈】SprintBootvue3迷你商城(2) 【全栈】Spr…...
自动化实现的思路变化
阶段一: 1、成功调用。第一步,一般是用现用的工具,或者脚本成功调用接口 2、解决关联接口的参数传递。有的接口直接,存在参数的传递,一般的思路,就是将这个参数设置为变量。 3、简化代码。总会有些东西是重…...
省市区三级联动
引言 在网页中,经常会遇到需要用户选择地区的场景,如注册表单、地址填写等。为了提供更好的用户体验,我们可以实现一个三级联动的地区选择器,让用户依次选择省份、城市和地区。 效果展示: 只有先选择省份后才可以选择…...
Mac安装Redis并设置launchd自启动
下载和编译redis源码 方便mac同学,不想使用brew方式安装,又想开机自启动redis,简单记录一下。首先下载redis7.0.15.tar.gz源码包 tar -xf tar -zxf redis-7.0.15.tar.gz开始编译源码 cd redis-7.0.15 sudo cp redis.conf /etc/redis.conf …...
Fullcalendar @fullcalendar/react 样式错乱丢失问题和导致页面卡顿崩溃问题
问题描述: 我使用 fullcalendar的react版本时,出现了一个诡异的问题,当我切换到 一个iframe页面时(整个页面是一个iframe嵌入的),再切换回来日历的样式丢失了!不仅丢失了样式还导致页面崩溃了&…...
dm8在Linux环境安装精简步骤说明(2024年12月更新版dm8)
dm8在Linux环境安装详细步骤 - - 2025年1月之后dm8 环境介绍1 修改操作系统资源限制2 操作系统创建用户3 操作系统配置4 数据库安装5 初始化数据库6 实例参数优化7 登录数据库配置归档与备份8 配置审计9 创建用户10 屏蔽关键字与数据库兼容模式11 jdbc连接串配置12 更多达梦数据…...
Linux MySQL离线安装
一、准备工作 1. 下载MySQL安装包 访问MySQL官方网站,选择适合您Linux系统的MySQL版本进行下载。通常推荐下载Generic Linux (glibc 2.12)版本的.tar.gz压缩包,例如mysql-8.0.33-linux-glibc2.12-x86_64.tar.xz。将下载好的安装包拷贝到Linux服务器的某…...
S4 HANA更改Tax base Amount的字段控制
本文主要介绍在S4 HANA OP中Tax base Amount的字段控制相关设置。具体请参照如下内容: 1. 更改Tax base Amount的字段控制 以上配置用于控制FB60/FB65/FB70/FB75/MIRO的页签“Tax”界面是否可以修改“Tax base Amount”, 如果勾选Change 表示可以修改T…...
JVM堆空间
一、堆空间的核心概述 一个JVM实例只存在一个堆内存,堆也是Java内存管理的核心区域。Java堆区在JVM启动的时候即被创建,其空间大小也就确定了。是JVM管理的最大一块内存空间。 堆内存的大小是可以调节的。堆可以处于物理上不连续的内存空间中ÿ…...
《深入解析:DOS检测的技术原理与方法》
DDOS入侵检测与防御 一、实现Linux下DDOS的入侵检测与防御 利用Python编程实现对wrk的泛洪攻击检测,并让程序触发调用Linux命令实现防御: 1、泛洪攻击的检测,可以考虑使用的命令,这些命令可以通过Python进行调用和分析 (1) netstat -ant …...
PID如何调试,如何配置P,I,D值,如何适配pwm的定时器配置,如何给小车配电源
首先你要搞清楚PID公式原理 PID算法解析PID算法解析_pid滤波算法-CSDN博客 然后你要明白调试原理 首先要确定一个电源 电源决定了你后面调试时电机转动速度大小和pwm占空比的关系,电源电压越大那要转到同一速度所需的占空比越小,反之电源电压越小那要…...
小马模拟器-第三方全街机游戏模拟器
链接:https://pan.xunlei.com/s/VOHSiB6st-f3RWlIK01MS2fUA1?pwd44v7# 1.小马模拟器是一款完全免费的游戏模拟器软件,支持街机(FBA,MAME,PGM2),3DS,WII,NGC,DC,SS,DOS,MD,WSC,NDS,JAVA,PCE,FC,SFC,GBA,GBC,PSP,PS,N64等多种游戏…...
Qwen2-VL:在任何分辨率下增强视觉语言模型对世界的感知 (大型视觉模型 核心技术 分享)
摘要 我们推出了Qwen2-VL系列,这是对之前Qwen-VL模型的高级升级,重新定义了视觉处理中的常规预设分辨率方法。Qwen2-VL引入了Naive Dynamic Resolution机制,使模型能够动态地将不同分辨率的图像转换为不同的视觉令牌数量。这种方法允许模型生成更高效和准确的视觉表示,紧密…...
微信小程序date picker的一些说明
微信小程序的picker是一个功能强大的组件,它可以是一个普通选择器,也可以是多项选择器,也可以是时间、日期、省市区选择器。 官方文档在这里 这里讲一下date picker的用法。 <view class"section"><view class"se…...
MySQL 基础学习(2): INSERT 操作
在这篇文章中,我们将专注于 MySQL 中的 INSERT 操作,深入了解如何高效地向表中插入数据,并探索插入操作中的一些常见错误与解决方案。 一、基础 INSERT 语法 在 MySQL 中,INSERT 操作用于向表中插入新记录,基本语法如…...
关于opensips的帮助命令的解释
opensips -help以下是 opensips 命令及其选项的中文解释(基于 3.6.0-dev 版本): 命令用法 opensips -l 地址 [-l 地址 ...] [选项]选项说明 选项功能-f 文件指定配置文件(默认为 /usr/local//etc/opensips/opensips.cfg&#x…...
新项目传到git步骤
1.首先创建远程仓库,创建一个空白项目,即可生成一个克隆URL,可以是http也可以是SSH,copy下这个地址 2.找到项目的本机目录,进入根目录,打开git bash here命令行 3.初始化: git init 4.关联远程地址: git remote add origin "远程仓库的URL" 5.查看关联 git re…...
【力扣每日一题】LeetCode 2412: 完成所有交易的初始最少钱数
LeetCode 2412: 完成所有交易的初始最少钱数 题目解析 问题描述 给定一个二维数组 transactions,每个元素 transactions[i] [costi, cashbacki] 表示一个交易。对于每笔交易,要求你完成该交易时有足够的初始资金 money,并且交易会减少或增…...
【算法】递归型枚举与回溯剪枝初识
递归型枚举与回溯剪枝初识 1.枚举子集2.组合型枚举3.枚举排列4.全排列问题 什么是搜索?搜索,是一种枚举,通过穷举所有的情况来找到最优解,或者统计合法解的个数。因此,搜索有时候也叫作暴搜。搜索一般分为深度优先搜索…...
pytorch 多机多卡训练方法
在深度学习训练中,使用多机多卡(多台机器和多块 GPU)可以显著加速模型训练过程。 PyTorch 提供了多种方法来实现多机多卡训练,以下是一些常用的方法和步骤: 1. 使用 torch.distributed 包 PyTorch 的 torch.distribut…...
InfiniBand客户端注册机制详解:ib_register_client函数的作用与实现
在Linux内核的InfiniBand(IB)子系统中,ib_register_client函数扮演着至关重要的角色。它允许上层用户(如特定的IB设备驱动程序或相关应用模块)注册为IB客户端,并定义在IB设备添加或移除时应执行的回调函数。这一机制确保了IB设备的动态管理,以及资源的有效分配和回收。本…...
