【发布时间】:2020-08-22 21:40:23
【问题描述】:
在二次筛算法中,在使用对数近似找到 bSmooth 值后,您需要对数字进行因式分解,我们称之为 B,以构造 bSmooth 向量。
一种常见的解决方案是使用因子基中的素数进行试除法。与随机数不同,在这种情况下,试除法非常有效,因为大多数因子都在质数基中。我说“大多数”是因为一个常见的优化将允许一个小的阈值包含 1-3 个 prims,其乘积最多为 2^30 左右,这称为偏关系。
在我的current implementation 中,这个向量提取阶段花费了大部分时间。我一直在尝试做的另一个解决方案是接收,再次越过素数基础,并将向量记录在已知为 b 平滑的索引中。但结果变得更慢了。
下面是我目前的代码,我为试用部门添加了4个优化,请告诉我是否有更好的解决方案。
- 对于素数 2,我检查
B的最后一组位并右移以提取它。 - 我正在使用 BigInteger
divideAndRemainder,它通过将除法和 mod 操作合并为 1 来优化内存和性能 - 如果
B小于因子基中的最大素数,那么它一定在因子基中,所以我使用哈希映射来定位它的索引 - 如果
B.bitLenght() / 2之前没有素数除以B,那么它一定是偏关系,只有当它是素数时我才会包含它。
private VectorData extractVector(BigInteger value) {
BitSet vector = new BitSet(PrimeBase.instance.primeBase.size());
if(value.compareTo(BigInteger.ZERO) < 0){
vector.set(0);
value = value.abs();
}
value = extractPower2(value, vector);
for (int i = 2; i < PrimeBase.instance.primeBase.size(); i++) {
BigInteger p = PrimeBase.instance.primeBaseBigInteger.get(i);
int count = 1;
BigInteger[] results = value.divideAndRemainder(p);
if (results[1].equals(BigInteger.ZERO)) {
value = results[0];
while (true) {
results = value.divideAndRemainder(p);
if(!results[1].equals(BigInteger.ZERO)){
break;
}
value = results[0];
count++;
}
if(count % 2 == 1) {
vector.set(i);
}
if (value.equals(BigInteger.ONE)) {
bSmoothVectorData.vector = vector;
return bSmoothVectorData;
} else if (value.compareTo(PrimeBase.instance.maxPrimeBigInteger) <= 0) {
int index = PrimeBase.instance.primeBaseMap.get(value);
vector.set(index);
bSmoothVectorData.vector = vector;
return bSmoothVectorData;
} else if (value.bitLength() / 2 < p.bitLength()) {
if (isPrime(value.longValue())) {
return new VectorData(vector, value);
}
return null;
}
}
}
return null;
}
bSmoothVectorData 用于区分完全和部分关系。最后一个调用isPrime 的else-if 情况很少见,占用该方法不到0.001% 的整体性能,瓶颈在于对divideAndRemainder 的调用,占用了大约72% 的性能。
【问题讨论】:
-
维基百科建议使用另一种分解算法,一旦最小素数被试除法消除后,该算法在平滑数上效果很好:en.wikipedia.org/wiki/…
-
@DavidEisenstat 这将是我的最后一个 else-if 案例,这非常罕见。我认为 wiki 只提供了一个高级概述,他们并没有过多地谈论优化。
-
我们的想法是在达到与 Pollard 的 rho 之类的平滑度相关的平滑度之前从试用分区中切出。
-
我不确定
java中有什么可用的,但是我知道通常精确除法可能很昂贵。例如,在C库gmp中,有一个名为mpz_divisible_ui_p的函数正是为您的任务而构建的。来自gmp手册:“他们使用的算法比 mpz_tdiv_ui 更快,但它没有提供有关实际余数的有用信息,只提供它是否为零(或特定值)。” -
还建议在该语句的正下方是这样的:“但是,当测试几个小整数的整除性时,最好取一个余数模它们的乘积,以节省多精度运算。例如测试一个数字是否可以被 23、29 或 31 中的任何一个整除,取余数模 23 × 29 × 31 = 20677,然后对其进行测试。”... 这看起来很有希望,因为一般来说,在你的素数基数中,你有很多小素数你需要测试。
标签: java algorithm factorization