Math 还是大整数的乘法
两个n位数字A和B的相乘可以理解为移位之和:Math 还是大整数的乘法,math,biginteger,Math,Biginteger,两个n位数字A和B的相乘可以理解为移位之和: (A << i1) + (A << i2) + ... (A有类似的算法吗?我想可能没有 有没有办法加快O(n 2)以外的事情?可能。如果你认为A是A(x)=yxn的类似物,阿纳尔的二进制数字是A,那么你就用bitwise ORs(我们称之为A)进行运算。⊕ B)可表示如下,其中“⇔" 表示“模拟” A⇔ A(x)=∑anxn B⇔ B(x)=∑bnxn C=A⊕ B⇔ C(x)=f(A(x)B(x))=f(V(x)),
(A << i1) + (A << i2) + ...
(A有类似的算法吗?我想可能没有
有没有办法加快O(n 2)以外的事情?可能。如果你认为A是A(x)=yxn的类似物,阿纳尔的二进制数字是A,那么你就用bitwise ORs(我们称之为A)进行运算。⊕ B)可表示如下,其中“⇔" 表示“模拟”
A⇔ A(x)=∑anxn
B⇔ B(x)=∑bnxn
C=A⊕ B⇔ C(x)=f(A(x)B(x))=f(V(x)),其中f(V(x))=f(∑vnxn)=∑u(vn)xn其中,如果vn=0,则u(vn)=0,否则u(vn)=1
基本上,你要做的是将两个多项式相乘,然后识别所有的非零项。从位字符串的角度来看,这意味着将位字符串视为一个由0或1组成的样本数组,这两个数组,并折叠得到的非零样本。有快速卷积算法例如,使用FFT,这里的“折叠”步骤是O(n)…但不知何故,我想知道快速卷积的O(n logn)计算是否将某些东西(如大整数的乘法)视为O(1)所以你实际上不会得到一个更快的算法。或者说,或者增长阶的常数太大,你必须有数千位才能获得速度优势。ORing是如此简单
编辑:这里似乎有一种叫做“二进制卷积”(参见示例)的东西听起来非常相关,但我找不到它背后的理论以及是否有快速算法的良好链接
编辑2:可能术语是“逻辑卷积”或“位卷积”…这里有一个(bleah!)和沃尔什变换和阿达玛变换一起讨论一下,这两种变换在某种程度上等同于傅里叶变换……嗯,不,这似乎是对异或的模拟,而不是对或的模拟。我想,您是在问您所给出的加法技术的名称
当你写“我在这里介绍的运算有类似的算法吗?”
你看过这项技术了吗?
如果本例中没有第三列,请阅读维基百科的描述
B X A
27 X 15 : 1
13 30 : 1
6 60 : 0
3 120 : 1
1 240 : 1
B is 27 == binary form 11011b
27x15 = 15 + 30 + 120 + 240
= 15<<0 + 15<<1 + 15<<3 + 15<<4
= 405
两个数字中1
s的数量将决定对一个设置了所有位的数字的模糊程度。
想知道你想用它做什么
Update2这是具有两个6000位数字的shift+或运算的性质
结果当然是12000位
- 该操作可以用两个比特流来完成;但是,不需要全部完成
- 12000位流的“中间”部分几乎肯定都是1(前提是两个数字都不是零)
- 问题在于确定我们需要处理该操作以获得12000位流两端的深度
- 流两端的模式取决于两个数字中出现的最大连续1
我还没有找到一个干净的算法。我已经为其他想要重新检查或进一步检查的人更新了。此外,描述这种操作的需要可能会激发更多的兴趣:-)你可以这样做O(#a中的1位*#B中的1位)
a-bitnums=set(x:((1我能想到的最好方法是在循环逻辑上使用快速输出。结合使用themis所述的非零方法的可能性,您可以通过检查不到2%的N^2问题来回答您的问题
下面是一些代码,给出了介于80%和99%零之间的数字的计时。
当数字在88%左右为零时,使用themis的方法会变得更好(尽管下面的示例中没有编码)
这不是一个高度理论化的解决方案,但它是实用的
好的,这里有一些关于问题空间的“理论”:
基本上,X(输出)的每个位都是网格对角线上的位的或和,网格是由a的位沿顶部(MSB到LSB从左到右)和B的位沿侧面(MSB到LSB从上到下)构成的。由于X的位为1(如果对角线上的任何位为1),因此您可以在单元遍历中执行早期输出
下面的代码说明了这一点,即使对于约87%为零的数字,您也只需检查约2%的单元格。对于密度更高(1更多)的数字,该百分比的下降幅度更大
换句话说,我不会担心复杂的算法,只需要做一些有效的逻辑检查。我认为诀窍是将输出的位看作网格的对角线,而不是移位的位或B的位。最棘手的事情是跟踪A和B中的位,以及如何正确地进行无损检测
希望这是有意义的。如果需要进一步解释,请告诉我(或者如果您发现这种方法有任何问题)
注意:如果我们更了解您的问题空间,我们可以相应地优化算法。如果您的数字大部分不为零,那么这种方法比themis更好,因为他的结果是需要更多的计算和存储空间(sizeof(int)*NNZ)
注2:这假设数据基本上是位,我使用.NET的位数组来存储和访问数据。我认为这在翻译成其他语言时不会引起任何大的麻烦。基本思想仍然适用
using System;
using System.Collections;
namespace BigIntegerOr
{
class Program
{
private static Random r = new Random();
private static BitArray WeightedToZeroes(int size, double pctZero, out int nnz)
{
nnz = 0;
BitArray ba = new BitArray(size);
for (int i = 0; i < size; i++)
{
ba[i] = (r.NextDouble() < pctZero) ? false : true;
if (ba[i]) nnz++;
}
return ba;
}
static void Main(string[] args)
{
// make sure there are enough bytes to hold the 6000 bits
int size = (6000 + 7) / 8;
int bits = size * 8;
Console.WriteLine("PCT ZERO\tSECONDS\t\tPCT CELLS\tTOTAL CELLS\tNNZ APPROACH");
for (double pctZero = 0.8; pctZero < 1.0; pctZero += 0.01)
{
// fill the "BigInts"
int nnzA, nnzB;
BitArray a = WeightedToZeroes(bits, pctZero, out nnzA);
BitArray b = WeightedToZeroes(bits, pctZero, out nnzB);
// this is the answer "BigInt" that is at most twice the size minus 1
int xSize = bits * 2 - 1;
BitArray x = new BitArray(xSize);
int LSB, MSB;
LSB = MSB = bits - 1;
// stats
long cells = 0;
DateTime start = DateTime.Now;
for (int i = 0; i < xSize; i++)
{
// compare using the diagonals
for (int bit = LSB; bit < MSB; bit++)
{
cells++;
x[i] |= (b[MSB - bit] && a[bit]);
if (x[i]) break;
}
// update the window over the bits
if (LSB == 0)
{
MSB--;
}
else
{
LSB--;
}
//Console.Write(".");
}
// stats
TimeSpan elapsed = DateTime.Now.Subtract(start);
double pctCells = (cells * 100.0) / (bits * bits);
Console.WriteLine(pctZero.ToString("p") + "\t\t" +elapsed.TotalSeconds.ToString("00.000") + "\t\t" +
pctCells.ToString("00.00") + "\t\t" + cells.ToString("00000000") + "\t" + (nnzA * nnzB).ToString("00000000"));
}
Console.ReadLine();
}
}
}
使用系统;
使用系统集合;
名称空间大整数
{
班级计划
{
私有静态随机r=新随机();
专用静态位数组加权子线程(整数大小,双pctZero,输出整数nnz)
{
nnz=0;
BitArray ba=新的BitArray(大小);
对于(int i=0;i110000011 X 1010101 would look like
110000011
110000011
110000011
110000011
---------------
111111111111111
a-bitnums = set(x : ((1<<x) & A) != 0)
b-bitnums = set(x : ((1<<x) & B) != 0)
c-set = 0
for a-bit in a-bitnums:
for b-bit in b-bitnums:
c-set |= 1 << (a-bit + b-bit)
using System;
using System.Collections;
namespace BigIntegerOr
{
class Program
{
private static Random r = new Random();
private static BitArray WeightedToZeroes(int size, double pctZero, out int nnz)
{
nnz = 0;
BitArray ba = new BitArray(size);
for (int i = 0; i < size; i++)
{
ba[i] = (r.NextDouble() < pctZero) ? false : true;
if (ba[i]) nnz++;
}
return ba;
}
static void Main(string[] args)
{
// make sure there are enough bytes to hold the 6000 bits
int size = (6000 + 7) / 8;
int bits = size * 8;
Console.WriteLine("PCT ZERO\tSECONDS\t\tPCT CELLS\tTOTAL CELLS\tNNZ APPROACH");
for (double pctZero = 0.8; pctZero < 1.0; pctZero += 0.01)
{
// fill the "BigInts"
int nnzA, nnzB;
BitArray a = WeightedToZeroes(bits, pctZero, out nnzA);
BitArray b = WeightedToZeroes(bits, pctZero, out nnzB);
// this is the answer "BigInt" that is at most twice the size minus 1
int xSize = bits * 2 - 1;
BitArray x = new BitArray(xSize);
int LSB, MSB;
LSB = MSB = bits - 1;
// stats
long cells = 0;
DateTime start = DateTime.Now;
for (int i = 0; i < xSize; i++)
{
// compare using the diagonals
for (int bit = LSB; bit < MSB; bit++)
{
cells++;
x[i] |= (b[MSB - bit] && a[bit]);
if (x[i]) break;
}
// update the window over the bits
if (LSB == 0)
{
MSB--;
}
else
{
LSB--;
}
//Console.Write(".");
}
// stats
TimeSpan elapsed = DateTime.Now.Subtract(start);
double pctCells = (cells * 100.0) / (bits * bits);
Console.WriteLine(pctZero.ToString("p") + "\t\t" +elapsed.TotalSeconds.ToString("00.000") + "\t\t" +
pctCells.ToString("00.00") + "\t\t" + cells.ToString("00000000") + "\t" + (nnzA * nnzB).ToString("00000000"));
}
Console.ReadLine();
}
}
}
10011 * 10001
[1 x^4 + 0 x^3 + 0 x^2 + 1 x^1 + 1 x^0] * [1 x^4 + 0 x^3 + 0 x^2 + 0 x^1 + 1 x^0]
== [1 x^8 + 0 x^7 + 0 x^6 + 1 x^5 + 2 x^4 + 0 x^3 + 0 x^2 + 1 x^1 + 1 x^0]
-> [1 x^8 + 0 x^7 + 0 x^6 + 1 x^5 + 1 x^4 + 0 x^3 + 0 x^2 + 1 x^1 + 1 x^0]
-> 100110011