压位高精度整数2.7
stripe_python · · 科技·工程
板子
-
BigInteger 2.7
-
BigInteger 2.6.2
-
BigInteger 2.6
-
BigInteger 2.5
-
BigInteger 2.4.2
-
BigInteger 2.4
-
BigInteger 2.3
-
BigInteger 2.2
-
BigInteger 2.1
-
BigInteger 2.0
-
BigInteger 扩展
更新
BigInteger 2.7
时间:2025/04/06。
- 修复 @Xudongning 指出的若干 bug
- 在 @Xudongning 帮助下,使位运算支持负数
- 实现
O(n \log n) 开根 - 增加对
__int128
的支持 - 新增阶乘函数
经过对开根的优化,BigInteger 2.7 在 U473176 速度优化 10 倍,超过 pypy 200ms。在 P2293 跑进最优解第一页。
BigInteger 2.6.2
时间:2025/03/29。
修复了 @Xudongning 指出的关于取模的 bug,在此感谢。
BigInteger 2.6
时间:2025/01/23。
为 BigDecimal
项目需要,修复若干 bug。
BigInteger 2.5
时间:2024/08/28。
- 修改扩容函数为
y=x(x+1)^{\frac{1}{8}} ,替代y=1.5n - 将
FFT_LIMIT
调整为32 - 添加
sqrt
函数用于开平方 - 将
move_l
,move_r
改为public
函数 - 新增
_digit_len
函数 - 新增按位取反
BigInteger 2.4.2
时间:2024/07/24。
- 修改左移右移的实现方式
- 优化牛迭除法
BugFixed
时间:2024/07/03。
感谢 konyakest 神仙指错,原 push
中的扩容存在严重问题,导致计算
现将所有 BigInteger2 版本修复。
BigInteger 2.4
时间:2024/06/21。
- 为 FFT 压
4 位需要,将压位位数w 修改为8 - 对 FFT 添加模板递归 + 分裂基 + 分段单位根优化
- 实现
O(n \log^2 n) 的高精度开根(虽然常数极大) - 将原本的
sqrt
函数名改为root
- 添加二进制互转功能
- 实现位运算功能
经过对 FFT 的大量优化,BigInteger 2.4 在 P1919 的平均用时仅 49ms,跑到最优解第
BigInteger 2.3
时间:2024/06/15。
- 完成牛顿迭代
O(n \log n) 除法,通过 P5432
BigInteger 2.2
时间:2024/06/07。
- 增加高精乘单精功能
- 极大优化除法,卡过 LOJ 模板
- 增加对三路比较的支持
BigInteger 2.1
时间:2024/05/31。
- 将
FFT_LIMIT
调整为512 - 修复等于 / 不等于的 BUG
- 修复赋
0 的 BUG - 优化除法的空间复杂度
- 将除法 + 取余统一写为
divmod
函数,大大优化取余速度 - 优化除
2 的常数 - 优化
sqrt
的常数,通过 P2293 - 增加
gcd
/lcm
功能,通过 P2152
BigInteger 2.0
时间:2024/04/04。
重构全是锅的 BigInteger 1.0。
- 将
std::vector
改为手动分配空间 - 对 FFT 添加压
3 位优化 + 递归改迭代 + 三次变两次等优化,效率提升三倍 - 将
O(n^3) 的二分除法改为O(n^2) 的倍增除法,效率提升一倍
BigInteger 1.0
时间:2023/12/01。
见 这篇博客。
在大量的锅中发现了少量板子。
FFT 模板能跑到 948ms,高精除高精 727ms,全套模板 481ms,常数极大。
Todo
支持操作
以下,记
表达式 | 含义 | 时间复杂度 | 空间复杂度 | 备注 |
---|---|---|---|---|
a <=> b |
高精度比较 | |||
a + b |
高精度加法 | |||
a - b |
高精度减法 | |||
a * b |
高精度乘法(普通) | |||
a * b |
高精度乘法(FFT) | |||
a / b |
高精度除法(普通) | |||
a / b |
高精度除法(牛迭) | 2.3 新增 | ||
a % b |
高精度取余(普通) | |||
a % b |
高精度取余(牛迭) | 2.3 新增 | ||
a.root(x) |
计算 |
2.0 新增,2.4 前名为 sqrt ,2.7 前复杂度为 |
||
a.sqrt(x) |
计算 |
2.5 新增,速度快于 root(2) ,2.7 前复杂度为 |
||
a.abs() |
求绝对值 | |||
-a |
求相反数 | |||
~a |
计算 |
|||
a.divmod(b) |
除法 + 取余(普通) | 2.1 新增 | ||
a.divmod(b) |
除法 + 取余(牛迭) | 2.3 新增 | ||
a.div2() |
计算 |
2.1 新增 | ||
a.gcd(b) |
计算 |
2.1 新增 | ||
a.lcm(b) |
计算 |
2.1 新增 | ||
a.to_binary() |
返回 |
2.4 新增 | ||
a & b |
高精度按位与 | 2.4 新增 | ||
a \| b |
高精度按位或 | 2.4 新增 | ||
a ^ b |
高精度按位异或 | 2.4 新增 | ||
a >> x |
计算 |
2.4 新增 | ||
a._move_l(x) |
计算 |
2.5 新增 | ||
a._move_r(x) |
计算 |
2.5 新增 | ||
a._digit_len() |
计算 |
2.5 新增 |
本模板能以优秀的时间通过 这个题单 中的所有题目。
优缺点
为什么要使用这个板子?
- 高度封装,几乎支持
int
类型所有操作,无需手写。 - 速度快,特别是 FFT 乘法及开根。大部分操作已优化到一个较优秀的复杂度。
- 代码不算太长(约 30K),可以交上题。
这个板子有哪些缺点?
- 位运算慢的要死。
- 整数位数很大,比如
3 \times 10^8 时,FFT 乘法会出现误差,进而导致依赖乘法的运算,如牛迭除法直接卡死。 - 偶尔出现的 bug。
性能测试
本机信息
CPU:Intel(R) Core(TM) i7-10750H CPU @ 2.60GHz 2.59 GHz。
内存:32 GB。
系统:Windows 10,64 位。
本机 GCC 编译器,GNU C++14,开 O2。
大概比洛谷机子慢一倍左右。
BigInteger 2.4 及以上
数据规模 | ||||||||
---|---|---|---|---|---|---|---|---|
加法 | 0.002 | 0.010 | 0.022 | 0.100 | 0.201 | 1.020 | 2.065 | 10.183 |
减法 | 0.002 | 0.010 | 0.020 | 0.102 | 0.194 | 0.990 | 1.987 | 9.989 |
乘法 | 0.003 | 0.011 | 0.024 | 0.139 | 0.283 | 1.423 | 2.875 | |
除法 | 0.003 | 0.046 | 0.033 | 0.200 | 0.429 | 3.239 | 7.007 | |
取余 | 0.001 | 0.008 | 0.017 | 0.125 | 0.283 | 3.061 | 5.314 | |
GCD | 0.309 | 7.168 | ||||||
LCM | 0.316 | 7.342 | ||||||
位运算 | 0.333 | 8.206 |
BigInteger 2.3
只对除法、取余有优化,故只测试除法和取余。
数据规模 | ||||||||
---|---|---|---|---|---|---|---|---|
除法 | 0.005 | 0.031 | 0.062 | 0.387 | 0.820 | 4.106 | 8.433 | 43.097 |
取余 | 0.003 | 0.024 | 0.051 | 0.316 | 0.661 | 3.290 | 6.851 | 37.779 |
BigInteger 2.2
数据规模 | ||||||||
---|---|---|---|---|---|---|---|---|
加法 | 0.002 | 0.009 | 0.017 | 0.088 | 0.174 | 0.883 | 1.893 | 8.976 |
减法 | 0.002 | 0.009 | 0.017 | 0.088 | 0.175 | 0.883 | 1.775 | 9.411 |
乘法 | 0.004 | 0.027 | 0.057 | 0.281 | 0.575 | 2.748 | 5.762 | 26.792 |
除法 | 0.004 | 0.056 | 0.209 | 4.562 | 20.290 | |||
取余 | 0.003 | 0.048 | 0.196 | 4.616 | 20.058 | |||
GCD | 0.239 | 5.401 | ||||||
LCM | 0.646 | 5.387 |
BigInteger 2.1
数据规模 | ||||||||
---|---|---|---|---|---|---|---|---|
加法 | 0.002 | 0.009 | 0.017 | 0.096 | 0.176 | 0.887 | 1.762 | 8.792 |
减法 | 0.002 | 0.009 | 0.017 | 0.090 | 0.181 | 0.887 | 1.772 | 9.036 |
乘法 | 0.005 | 0.028 | 0.055 | 0.280 | 0.573 | 2.668 | 5.491 | 26.744 |
除法 | 0.398 | 9.650 | ||||||
取余 | 0.401 | 9.655 | ||||||
GCD | 0.239 | 5.404 | ||||||
LCM | 0.647 | 15.691 |
实现原理
基础四则运算就是压个位,普及组内容。这里说一下如何优化速度。
乘法
乘法用 FFT,参考这篇文章和这篇文章添加了压 long double
。代价是
除法
写过一篇 题解,复述一下:
对于
牛顿迭代的式子:
求解
换个方程
如果直接求解
考虑把小数的那些位保存到整数上,也就是求得
整理得:
为了保证调整次数,这里需要使
取
开平方
《理性愉悦:高精度数值计算》中提出如下方法:
也是牛顿迭代求解
除法不好解决,换用方程
这样我们只要求解
参考资料
- OI-Wiki
- 【C++】【FFT】干货分享!超快的开源FFT高精度、大数乘法(作者:WitH_SkY)
- 高精度乘法从入门到入土(作者:zhangbo1000)
- 题解 P2293 【[HNOI2004]高精度开根】(作者:TBB_Nozomi)
- 题解 P2293 【[HNOI2004]高精度开根】(作者:Elegia 神仙)
- 理性愉悦——高精度数值计算(2012WC)
说明
如果有 bug,欢迎指出,感激不尽!