java大数运算详解【其三】大数乘法之平方算法之按位二次展开式算法
目录
java大数运算详解【其一】大数加减法
java大数运算详解【其二】大数乘法
java大数运算详解【其三】大数乘法之平方算法之按位二次展开式算法
java大数运算详解【其四】大数乘法之平方算法之Karatsuba平方算法
java大数运算详解【其五】大数乘法之平方算法之ToomCook3平方算法
java大数运算详解【其六】大数乘法之单位乘法和经典乘法
java大数运算详解【其七】大数乘法之Karatsuba乘法和ToomCook3乘法
java大数运算详解【其八】大数除法
java大数运算详解【其九】大数除法之试商法(Knuth除法)核心算法
java大数运算详解【其十】大数除法之Burnikel-Ziegler除法算法
所有解释都是最基本的,没有过多赘述,如若不懂静心思考。
1.1、按位二次展开式算法
/**
* 将整型数组x的内容平方,结果放入整型数组z中,x的内容不变。
*/
private static final int[] squareToLen(int[] x, int len, int[] z) {
int zlen = len << 1;
if (z == null || z.length < zlen)
z = new int[zlen];
// 在调用intrinsified(增强)方法之前执行检查。
implSquareToLenChecks(x, len, z, zlen);
return implSquareToLen(x, len, z, zlen);
}
/**
* 参数验证。
*/
private static void implSquareToLenChecks(int[] x, int len, int[] z, int zlen) throws RuntimeException {
if (len < 1) {
throw new IllegalArgumentException("invalid input length: " + len);
}
if (len > x.length) {
throw new IllegalArgumentException("input length out of bound: " +
len + " > " + x.length);
}
if (len * 2 > z.length) {
throw new IllegalArgumentException("input length out of bound: " +
(len * 2) + " > " + z.length);
}
if (zlen < 1) {
throw new IllegalArgumentException("invalid input length: " + zlen);
}
if (zlen > z.length) {
throw new IllegalArgumentException("input length out of bound: " +
len + " > " + z.length);
}
}
/**
* Java运行时可以为该方法使用intrinsic(固有的,增强的)。
*/
@HotSpotIntrinsicCandidate
private static final int[] implSquareToLen(int[] x, int len, int[] z, int zlen) {
/*
* 这里使用的算法来自Colin Plumb的C库。
* 技巧:考虑乘法中的部分乘积
* “abcde”本身:
*
* a b c d e
* * a b c d e
* ==================
* ae be ce de ee
* ad bd cd dd de
* ac bc cc cd ce
* ab bb bc bd be
* aa ab ac ad ae
*
* 注意主对角线以上的所有元素:
* ae be ce de = (abcd) * e
* ad bd cd = (abc) * d
* ac bc = (ab) * c
* ab = (a) * b
*
* 是主对角线以下所有内容的副本:
* de
* cd ce
* bc bd be
* ab ac ad ae
*
* 因此,总和是2 *(对角线上方或下方)+对角线。
*
* 这是从对角线开始累积的(对角线由输入数字的平方组成),
* 然后对角线除以2,非对角线相加,再乘以2。
* 低位只是输入低位的一个副本,因此不需要特别注意。
*/
// 储存平方值,右移一位(即,除以2)。
int lastProductLowWord = 0;
for (int j=0, i=0; j < len; j++) {//计算每一位的平方值并存储在z中且右移一位
long piece = (x[j] & LONG_MASK);
long product = piece * piece;
z[i++] = (lastProductLowWord << 31) | (int)(product >>> 33);
z[i++] = (int)(product >>> 1);
lastProductLowWord = (int)product;
}
// 计算对角线上方或下方的总和
for (int i=len, offset=1; i > 0; i--, offset+=2) {//注意:offset-1=2*(len-i),即:2*len-offset=2*i-1.
int t = x[i-1];
t = mulAdd(z, x, offset, i-1, t);
addOne(z, offset-1, i, t);//t的添加位置为z[z.length-1-(offset-1)-i],即:z[2*len-offset-i].
//故addOne函数最多需进位传播2*len-offset-i=i-1次,为判断运算是否溢出,需传参mlen为i,而不是i-1.
//其实运算一定不会产生溢出(zlen=2*len时),所以传参mlen为i-1也可行(同时传参offset为offset)。
}
// 回移并设置低位
primitiveLeftShift(z, zlen, 1);
z[zlen-1] |= x[len-1] & 1;
return z;
}
/**
* 将数组乘以一个整数k,然后添加到结果中,返回进位。
*/
static int mulAdd(int[] out, int[] in, int offset, int len, int k) {
implMulAddCheck(out, in, offset, len, k);
return implMulAdd(out, in, offset, len, k);
}
/**
* 参数验证。
*/
private static void implMulAddCheck(int[] out, int[] in, int offset, int len, int k) {
if (len > in.length) {
throw new IllegalArgumentException("input length is out of bound: " + len + " > " + in.length);
}
if (offset < 0) {
throw new IllegalArgumentException("input offset is invalid: " + offset);
}
if (offset > (out.length - 1)) {
throw new IllegalArgumentException("input offset is out of bound: " + offset + " > " + (out.length - 1));
}
if (len > (out.length - offset)) {
throw new IllegalArgumentException("input len is out of bound: " + len + " > " + (out.length - offset));
}
}
/**
* Java运行时可以为该方法使用intrinsic(固有的,增强的)。
* 将in数组(长度为len,数据倒序存储)乘以k,再添加到out数组(偏移量为offset,数据倒序存储),
* 添加位置为第offset位,即out[out.length-offset - 1].
* 返回进位。
*/
@HotSpotIntrinsicCandidate
private static int implMulAdd(int[] out, int[] in, int offset, int len, int k) {
long kLong = k & LONG_MASK;
long carry = 0;
offset = out.length-offset - 1;//重计算偏移量
for (int j=len-1; j >= 0; j--) {
long product = (in[j] & LONG_MASK) * kLong +
(out[offset] & LONG_MASK) + carry;
out[offset--] = (int)product;
carry = product >>> 32;
}
return (int)carry;
}
/**
* 在a中加上一个整数,把carry这个整数加到a中。
* 把carry添加到a中,添加位置为第offset+mlen位,即a[a.length-1-mlen-offset].
* 进位最多传播mlen位。
* 返回结果进位。
*/
static int addOne(int[] a, int offset, int mlen, int carry) {
offset = a.length-1-mlen-offset;
long t = (a[offset] & LONG_MASK) + (carry & LONG_MASK);
a[offset] = (int)t;
if ((t >>> 32) == 0)
return 0;
while (--mlen >= 0) {
if (--offset < 0) { // 数据溢出
return 1;
} else {
a[offset]++;
if (a[offset] != 0)
return 0;//进位传播处理完成,返回0
}
}
return 1;//进位传播了mlen次,仍未处理完毕,返回进位1
}
// 将a数组(长度len,数据倒序存储)左移n位,假设没有前导零,0<=n<32.
static void primitiveLeftShift(int[] a, int len, int n) {
if (len == 0 || n == 0)
return;
int n2 = 32 - n;
for (int i=0, c=a[i], m=i+len-1; i < m; i++) {//循环移位
int b = c;
c = a[i+1];
a[i] = (b << n) | (c >>> n2);
}
a[len-1] <<= n;
}
按位二次展开式算法,即将mag数组看作len个项的和,并使用二次展开式进行计算其平方值。
java大数运算详解【其三】大数乘法之平方算法之按位二次展开式算法相关推荐
- java三元运算详解
运算符 2.1 运算符概念 运算符是用来计算数据的指令.数据可以是常量,也可以是变量.被运算符操作的数成为操作数. Int x = 3; Int y = 4; Int z = x + y 2.2 算数 ...
- 大数取余运算(详解)
大数取余运算(详解) //(19^3 mod 23)^2 mod 31=25 //a=19 b=3 c=23 d=2 e=31 #include<stdio.h> long long po ...
- 一篇搞定位运算——java位运算详解
java位运算详解 前言 一.位运算符 &:按位与 |:按位或 ~:按位非 ^:按位异或 <<:左位移运算符 >>:右位移运算符 <<<:无符号右移运 ...
- java拉姆达表达式事例,Java Lambda表达式详解和实例
简介 Lambda表达式是Java SE 8中一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口. lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体( ...
- 5W字高质量java并发系列详解教程(上)-附PDF下载
文章目录 第一章 java.util.concurrent简介 主要的组件 Executor ExecutorService ScheduledExecutorService Future Count ...
- Java 线程池详解及实例代码
转载自 Java 线程池详解及实例代码 这篇文章主要介绍了Java 线程池的相关资料,并符实例代码,帮助大家学习参考,需要的朋友可以参考下 线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时 ...
- python开方运算符_Pytorch Tensor基本数学运算详解
1. 加法运算 示例代码: import torch # 这两个Tensor加减乘除会对b自动进行Broadcasting a = torch.rand(3, 4) b = torch.rand(4) ...
- 取模(余)%运算详解
取模(余)%运算详解 1.JAVA中 对于整型数a,b来说,取模运算是: 1.求 整数商: c = a/b; 2.计算模: a%b = a - ...
- Java 三目运算符细节详解
Java 三目运算符细节详解 @author:Jingdai @date:2020.09.24 看到标题你肯定觉得三目运算符有什么好讲的,不是很简单嘛.我之前也是这么认为的,直到今天刷LeetCode ...
最新文章
- ZJU-java进阶笔记 第四周(继承与多态)
- Laravel 框架安装
- snmpset对象不可写_[Python]可变对象与多进程通信
- luogu P2257 YY的GCD
- java两个数之间质数求法,求任意两个整数之间质数的个数的代码!!!(新手编写)...
- HDOJ 4005-The war解题报告
- 五一假期四天_假期在家上班的12天
- [HNOI2015]开店
- 完美的xslt数值函数与字符串函数
- dev gridcontrol 单选框效果
- python 打包过程
- 9.STC15W408AS单片机EEPROM
- 计量芯片应用心得之软件篇
- 2019NEFU寒假集训新生考试 2020.1.6
- 照片调色系列教程(11):浪漫色调 温情暖暖
- Nginx反向代理服务器及负载均衡服务配置实战
- List.isEmpty()与CollectionUtils.isEmpty的区别
- Android各个版本的区别
- 计算机二级MS-office题目练习
- 谷歌Pixel 4神奇在哪儿? AI黑科技带来四大改变!
热门文章
- [yii]Trying to get property of non-object
- Gartner数据库推荐报告,巨杉数据库入选
- VDP6.1.3部署使用
- 思科华为路由器如何利用route-map配置双wan口策略路由
- C++调用Matlab混合编程未定义函数或变量“javaaddpath“
- C++11 std::tuple
- 【Graphics·二】带反射和折射的Fresnel函数
- 数列的逆序数对(难度系数:2颗星)
- 求数组中数对之差的最大值
- 测量两种充电9V电池