基于大整形的运算收录

目录

目录

目录

前言

为什么要大整数

大整形的加/减法

大整形的乘法

大整形除法

大整形开方

代码实现


前言

好久没有更新博客了,hhh。时隔三个月,我又回来了。先来点简单的大整形,虽说简单,但是在编写的时候还是debug了好久。

申明:本文代码为博主自行编写,尚有不足还望海涵,也希望大佬可以指点一二。

为什么要大整数

这是一个令人尴尬的问题。个人看法是除了竞赛大概率碰不上大整形,或者使用c/c++处理大整形的几率很小。我想有的小伙伴要问了,为什么说c/c++处理大整形的几率很小。请看c/c++的语言标准。时至今日,c/c++语言标准都没有明确规定相关生产商必须提供大整形。而在实际的生产中,只有GCC一方提供了“大整形” -- 128位整形。事实上,128位整型并不是内嵌的、官方认定的类型,换句话说只要128位系统没出现,128位类型就不能内嵌,一定是一个认为实现的标准库。在现实生活中,64位整数已经能够处理我们日常生活中的事情。正如有人调侃,微软当初使用64位整型是因为需要64位来存放比尔盖茨的财产,但是32位对于我们普通人来说足够了。由此可见,实际生活没有那么多的大整形。凡事皆有例外,为金融、航天等机密仪器所设计的程序可能会面临大整形、高精度的需求。因此,你发现python在金融称王称霸是合理的。python处理大整形、高精度有着天然优势。但是在精密仪器上应该还是c/cpp开发的程序较多。

总而言之,就是当64位整数不能够满足需求时,就需要按需设计一个存储结构。这个存储结构就是大整形。顺便一提这里不建议使用128位整数,因为可移植性比较差。

大整形的加/减法

大整形的加减法是最为简单的,简单来说就是按位相加减,事后借进位

大整形的乘法

乘法的实现也比较低,相较于加减法难一丢丢。如果我们有如下的式子:

number=a_n*base^{n}+a_{n-1}*base^{n-1}+\dots+a_{0}*base^{0}

那么,现在有number_{1},number_{2}可以像如上式子表达。为了方便表示结果存储在 result ,并且number[i]=a_{i}*base^{i}

于是我们知道number_{1}*number_{2}=\sum_{i=0}^{n_{1}}(number_{1}[i])*\sum_{i=0}^{n_{2}}(number_{2}[i]),进一步推导得到result[k]=\sum_{i}^{k}(number_{1}[i]*number_{2}[k-i])

大整形除法

除法最简单的直观的方式就是位对齐,减试商。这里还可以来一个小优化,就是试商的时候可以不用循环尝试,使用二分搜索尝试,这样会快一点。因为我们的基底不一定是10。如果是大基底循环试商就太慢了,而选用小基底空间上又太浪费。

当然还有数学方法,如果基于数学算法,大整形的运算速度都可以提升到O(nlog^{n})。但是,我太菜了,不能理解。所以就不出来瞎掰扯了,误人子弟了。

大整形开方

这里也是使用了试根法。也有数学方法来着,不过是基于除法实现。so,除法不懂,这里就更不懂了(苦笑ing...)。

代码实现

1000位(十进制)以内目前没发现bug。仍有待测试和完善,乘法计算速度尚可。里面的减法只实现了移位减法供除法使用。一般的减法设计可参看加法 + 移位减法中的检测机制。

里面虽然是无符号类型,但是无符号和有符号的计算效果是一样的。也就是说,如果你需要设计有符号的大整形,可以标注最高位的无符号第1个二进制位就是符号位。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>class BigInt : public std::vector<unsigned long long> {
public:BigInt(unsigned long long n = 0) {int i = 0;do {push_back(0);at(i++) = n % base;n /= base;} while (n);};BigInt(char* s) {int len = strlen(s);for (int i = len - 1; i >= 0; i -= log_10_base) {unsigned long long num = 0;for (int j = i - log_10_base + 1 < 0 ? 0 : i - log_10_base + 1; j <= i; ++j)num = num * 10 + (s[j] - '0');push_back(num);}}const int theBase() const { return base; };// 赋值号BigInt& operator = (const BigInt& other) {for (int i = 0, j = 0; i < other.size(); ++i, ++j) {if (i >= size()) push_back(0);at(j) = other[i];}for (int i = other.size(); i < size(); ++i) pop_back();return *this;};// 加法类BigInt operator+ (const BigInt& other) {int min_digital = std::min(size(), other.size());int max_digital = std::max(size(), other.size());BigInt ret;for (int i = max_digital - 1; i > 0; --i) ret.push_back(0);for (int i = 0; i < min_digital; ++i) ret[i] = at(i) + other[i];for (int i = min_digital; i < size(); ++i) ret[i] = at(i);for (int i = min_digital; i < other.size(); ++i) ret[i] = other[i];ret.process();return ret;};BigInt& operator+= (const BigInt& other) {int min_digital = std::min(size(), other.size());int max_digital = std::max(size(), other.size());for (int i = 0; i < min_digital; ++i) at(i) += other[i];for (int i = min_digital; i < other.size(); ++i) {push_back(0);at(i) = other[i];}process();return *this;};// 乘法类BigInt operator* (const BigInt& other) {BigInt ret;for (int i = size() + other.size() - 1; i > 0; --i) ret.push_back(0);for (int i = 0; i < size(); ++i)for (int j = 0; j < other.size(); ++j)ret[i + j] += at(i) * other[j];ret.process();return ret;};BigInt operator* (const long long num) {BigInt ret;for (int i = size() - 1; i > 0; --i) ret.push_back(0);for (int i = 0; i < size(); ++i)ret[i] = at(i) * num;ret.process();return ret;};BigInt& operator*= (const int num) {for (int i = 0; i < size(); ++i)at(i) *= num;process();return *this;};BigInt operator*= (const BigInt& other) {BigInt ret;for (int i = size() + other.size() - 1; i > 0; --i) ret.push_back(0);for (int i = 0; i < size(); ++i)for (int j = 0; j < other.size(); ++j)ret[i + j] += at(i) * other[j];ret.process();for (int i = 0; i < ret.size(); ++i) {if (i >= size()) push_back(0);at(i) = ret[i];}return *this;};// 减法类// *this - (num << shl) the base is class_base void sub_with_shl(const BigInt& num, int shl) {for (int i = 0; i < num.size(); ++i) {unsigned long long check = at(i + shl);at(i + shl) -= num[i];if (check - num[i] > check) { // 如果发生结尾at(i + shl) += base;at(i + shl + 1) -= 1;int higher = i + shl + 1;while (at(higher) >= base) { // 是否会产生连续借位at(higher) += base;higher += 1;at(higher) -= 1;} // } // }process();};// 除法类// 最简单的方法就是一直循环减// 实际上还有数学方法,本人能力有限无法实现,涉及到多项式环快速逆,Crypto的知识。BigInt operator/ (BigInt& divisor) {if (*this < divisor) return BigInt((unsigned long long) 0);BigInt quotiend;BigInt remainder = *this;int shl = size() - divisor.size(); // 移位if (!divisor.less_equal_with_shl(*this, shl)) shl -= 1;while (divisor <= remainder) {unsigned long long q = remainder.search_quotient(divisor, shl);remainder.sub_with_shl(divisor * (q - 1), shl);quotiend[quotiend.size() - 1] = q - 1;quotiend.push_back(0);if (shl) shl -= 1;}quotiend.pop_back();quotiend.reverse();quotiend.process();return quotiend;}BigInt operator% (BigInt& divisor) {if (*this < divisor) return *this;BigInt quotiend;BigInt remainder = *this;int shl = size() - divisor.size(); // 移位if (!divisor.less_equal_with_shl(*this, shl)) shl -= 1;while (divisor <= remainder) {unsigned long long q = remainder.search_quotient(divisor, shl);remainder.sub_with_shl(divisor * (q - 1), shl);quotiend[quotiend.size() - 1] = q - 1;quotiend.push_back(0);if (shl) shl -= 1;}return remainder;}int operator% (int divisor) {int r = 0;for (int i = size() - 1; i >= 0; --i) {// r = r * base + at(i);r = (r * (base % divisor) + at(i) % divisor) % divisor;}return r;}// 开方运算 -- 1000位精确BigInt sqrt() {BigInt ret;int sz = 0;if (size() % 2 == 0) ret.resize(sz = size() >> 1);else ret.resize(sz = (size() >> 1) + 1);for (int i = sz - 1; i >= 0; --i) {search_root_for_ith_digital(ret, i);}ret.process();return ret;}// 比较类bool operator<(const BigInt& other) const {if (size() != other.size()) return size() < other.size();for (int i = size() - 1; i >= 0; --i)if (at(i) != other[i]) return at(i) < other[i];return false;}bool operator<=(const BigInt& other) const {if (size() != other.size()) return size() < other.size();for (int i = size() - 1; i >= 0; --i)if (at(i) != other[i]) return at(i) < other[i];return true;}// *this << shl <= otherbool less_equal_with_shl(const BigInt& other, int shl) const {if (size() + shl != other.size()) return size() + shl < other.size();for (int i = size() - 1; i >= 0; --i)if (at(i) != other[i + shl]) return at(i) < other[i + shl];return true;}// 输出void output() {printf("%Id", at(size() - 1));for (int i = size() - 2; i >= 0; --i) {for (int j = base / 10; j > 0; j /= 10)printf("%Id", at(i) % (j * 10) / j);}puts("");}
private:void process() {for (int i = 0; i < size(); ++i) {if (at(i) < base) continue;if (i + 1 == size()) push_back(0);at(i + 1) += at(i) / base;at(i) %= base;}for (int i = size() - 1; at(i) == 0 && i > 0; --i) pop_back();}// 为除法设计 -- 小优化long long search_quotient(BigInt& divisor, int shl) {long long l = 1, r = base;while (l < r) {long long mid = l + (r - l >> 1);BigInt tmp = divisor * mid;if (tmp.less_equal_with_shl(*this, shl)) l = mid + 1;else r = mid;}return l;}BigInt& reverse() {for (int i = 0, j = size() - 1; i < j; ++i, --j) {unsigned long long tmp = at(i);at(i) = at(j);at(j) = tmp;}return *this;}void search_root_for_ith_digital(BigInt& ret, int i) {long long l = 1, r = base;while (l < r) {ret[i] = l + (r - l >> 1);BigInt tmp = ret * ret;if (tmp.less_equal_with_shl(*this, 0)) l = ret[i] + 1;else r = ret[i];}ret[i] = l;unsigned long long check = ret[i];ret[i] -= 1;if (ret[i] > check) {int higner = i + 1;ret[i] += base;ret[higner] -= 1;while (ret[higner] > base) {ret[higner] += base;higner += 1;ret[higner] -= 1;}}return;}
private:const static int base = 1000000000;const static int log_10_base = 9;
};

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

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

相关文章

学校门禁管理技巧,一招轻松学会!

随着社会的不断发展和科技的不断进步&#xff0c;安全管理成为各个领域至关重要的议题之一。门禁监控系统作为现代安全管理的关键组成部分&#xff0c;不仅为建筑物提供了有效的访问控制&#xff0c;还在提高整体安全性和管理效率方面发挥了关键作用。 客户案例 公司办公楼门禁…

php no input file specified

一、修改 .user.ini 文件 内容 open_basedir/wab/led-sportslight.com/:/tmp/ led-sportslight.com是项目根目录位置 改好后保存并清空缓存硬刷新网站就行了 二、mkdir(): Permission denied /core/library/think/cache/driver/File.php 第 84 行左右 mkdir(): Permission de…

2024最新最全【网络安全面试题含答案】(非常详细),零基础入门到精通

防范常见的 Web 攻击 什么是SQL注入攻击 攻击者在HTTP请求中注入恶意的SQL代码&#xff0c;服务器使用参数构建数据库SQL命令时&#xff0c;恶意SQL被一起构造&#xff0c;并在数据库中执行。 用户登录&#xff0c;输入用户名 lianggzone&#xff0c;密码 ‘ or ‘1’’1 &a…

使用 OpenCV 添加(混合)两个图像

目标 在本教程中&#xff0c;您将学习&#xff1a; 什么是线性混合以及为什么它有用;如何使用 addWeighted&#xff08;&#xff09; 添加两个图像 理论 注意 下面的解释属于Richard Szeliski的《计算机视觉&#xff1a;算法和应用》一书 从我们之前的教程中&#xff0c;…

LabVIEW扫描探针显微镜系统开发

在纳米技术对高精度材料特性测量的需求日益增长。介绍了基于LabVIEW开发的扫描探针显微镜&#xff08;SPM&#xff09;系统。该系统不仅可以高效地测量材料的热物性&#xff0c;还能在纳米尺度上探究热电性质&#xff0c;为材料研究提供了强大的工具。 系统基于扫描探针显微技…

(2)(2.1) Andruav Android Cellular(二)

文章目录 前言 5 Andruav Web Client 6 Andruav Telemetry 7 Andruav高级功能 8 将Andruav与SITL配合使用 9 FAQ 10 术语表 前言 Andruav 是一个基于安卓的互联系统&#xff0c;它将安卓手机作为公司计算机&#xff0c;为你的无人机和遥控车增添先进功能。 5 Andruav W…

数学建模--PageRank算法的Python实现

文章目录 1. P a g e R a n k PageRank PageRank算法背景2. P a g e R a n k PageRank PageRank算法基础2.1. P a g e R a n k PageRank PageRank问题描述2.2.有向图模型2.3.随机游走模型 3. P a g e R a n k PageRank PageRank算法定义3.1. P a g e R a n k PageRank PageRank…

GD32接收不定长数据包

接收不定长数据 Cubemx生成代码过程忽略 首先在main函数中创建接收缓存区 并在main.h中定义 接下来就是重写串口的中断函数中的内容&#xff0c;把原有内容注释掉 main中创建一个记录接收数据长度的变量和标志位 然后再在主函数中添加一个验证代码&#xff0c;这样MCU收到数据…

Cesium叠加超图二维服务、三维场景模型

前言 Cesium作为开源的库要加超图的服务则需要适配层去桥接超图与Cesium的数据格式。这个工作iClient系列已经做好&#xff0c;相比用过超图二维的道友们可以理解&#xff1a;要用Openlayer加载超图二维&#xff0c;那就用iClient for Openlayer库去加载&#xff1b;同样的要用…

Git与GitHub零基础教学

大家好&#xff0c;我是星恒&#xff0c;这个帖子给大家分享的是git和github的全套教程&#xff0c;包含github初始&#xff0c;git常用命令以及基本使用&#xff0c;git的ssh链接github&#xff0c;github使用token登录&#xff0c;github和idea的配合&#xff0c;一些平时常用…

Flink编程——基础环境搭建

基础环境搭建 文章目录 基础环境搭建准备环境搭建源码环境搭建克隆代码编译导入IDEA 集群环境搭建本地模式安装步骤 1&#xff1a;下载步骤 2&#xff1a;启动集群步骤 3&#xff1a;提交作业&#xff08;Job&#xff09;步骤 4&#xff1a;停止集群 总结 准备环境搭建 我们先…

web3d-three.js场景设计器-天空包围盒-TWEEN.js

THREE.JS 实现场景天空包围盒&#xff0c;为了让场景背景更具体&#xff0c;而不是呆板的纯色&#xff0c;可以给厂家添加围绕的包围盒。 这里使用球体来实现&#xff0c;球体中央则是场景给球体添加天空的渐变色加入场景 代码如下 function createSky( hemiLight) { const …

学习笔记——克里金插值

有一篇大神的文章写得非常的具体&#xff0c; https://xg1990.com/blog/archives/222 下面写下一些学习笔记&#xff1a; 1、关于克里金插值的基本原理 克里金插值来源于地理学&#xff0c;它的前提是地理学第一定律&#xff1a;所有事物都与其他事务相关&#xff0c;但是近…

应用层—HTTP详解(抓包工具、报文格式、构造http等……)

文章目录 HTTP1. 抓包工具的使用1.1 配置信息1.2 观察数据 2. 分析 https 抓包结果3. HTTP请求详解3.1 认识 URL3.1.1 URL 基本格式3.1.2 查询字符串 (query string)3.1.3 关于 URL Encode 3.2 认识 http 方法3.2.1 [经典问题] Get 和 Post 主要的区别是什么&#xff1f;&#…

Java多线程并发篇----第二十九篇

系列文章目录 文章目录 系列文章目录前言一、什么是不可变对象,它对写并发应用有什么帮助二、Java 中用到的线程调度算法是什么?三、什么是线程组,为什么在 Java 中不推荐使用?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点…

C++11手撕线程池 call_once 单例模式 Singleton / condition_variable 与其使用场景

一、call_once 单例模式 Singleton 大家可以先看这篇文章&#xff1a;https://zh.cppreference.com/w/cpp/thread/call_once /*std::call_oncevoid call_once( std::once_flag& flag, Callable&& f, Args&&... args ); */ #include <iostream> #i…

DT浏览器的人工智能是如何学习知识的

DT浏览器的人工智能是如何学习知识的&#xff0c;DT浏览器的人工智能通过大量的数据和算法来实现知识学习的。这是一些学习知识的方式&#xff1a; 1. 数据驱动学习&#xff1a;通过处理和分析大量的文本数据来学习语言知识和语言模式。这些数据可以来自各种来源&#xff0c;如…

解决 pnpm : 无法加载文件 C:\Program Files\nodejs\pnpm.ps1,因为在此系统上禁止运行脚本。

执行下面命令进行安装pnpm安装后 npm install -g pnpm 然后执行pnpm 报错 解决办法&#xff1a; 以管理员身份运行 Windows PowerShell &#xff0c; 在命令行输入以下命令后按回车&#xff0c; set-ExecutionPolicy RemoteSigned 再输入Y 回车即可。 再回到控制台输入p…

k8s---包管理器helm

内容预知 目录 内容预知 helm相关知识 Helm的简介与了解 helm的三个重要概念 helm的安装和使用 将软件包拖入master01上 使用 helm 安装 Chart 对chart的基本使用 查看chart信息 安装chart 对chart的基本管理 helm自定义模板 在镜像仓库中拉取chart&#xff0c;查…

大路灯和台灯哪个对眼睛好?学生备考大灯推荐

最近家长圈里开始流行这么一句话&#xff1a;鸡娃的尽头&#xff0c;是鸡眼。曾经绘画课、科学课、乐高课、思维课一样没落下&#xff0c;讲绘本、学英语也是每天的日常&#xff0c;周一到周日孩子的行程排得满满当当。可没想到有一天带着孩子去医院体检视力的时候&#xff0c;…