You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用BigInt求解Sam Loyd黑斯廷斯谜题的性能优化问题

优化BigInt完全平方检查及佩尔方程最优解法

一、针对暴力遍历的BigInt代码优化

如果需要保留暴力遍历思路,可从以下方向降低BigInt计算开销:

1. 递推计算目标值,减少BigInt乘法

每次计算 (13n^2 +1) 时,无需重复计算 (n^2),利用前一次结果递推:
(13(n+1)^2 +1 = 13n^2 +1 +13*(2n+1))
将BigInt乘法次数从O(n)压缩到近似O(1)每次:

const limit = 7_000_000;
var a = [];

console.time('big int optimized');

let current = 14n; // 13*1²+1=14
if (perfectSquare(current)) a.push(1n);

for (let n = 2n; n < limit; n++) {
  current += 13n * (2n - 1n);
  if (perfectSquare(current)) {
    a.push(n);
  }
}
console.log(a.join(', '));
console.timeEnd('big int optimized');

2. 优化完全平方数检查逻辑

(1)增加多模预过滤

在进入开方计算前,用更多模值快速排除非平方数,减少开方调用次数:

function perfectSquare(n) {
    // 末位过滤:平方数末位只能是0/1/4/5/6/9
    const lastDigit = n % 10n;
    if (![0n,1n,4n,5n,6n,9n].includes(lastDigit)) return false;
    
    // 模9过滤:平方数模9只能是0/1/4/7
    const mod9 = n % 9n;
    if (![0n,1n,4n,7n].includes(mod9)) return false;

    // 原有模4/模8过滤
    while ((n & 3n) === 0n && n !== 0n) {
        n >>= 2n;
    }
    if ((n & 7n) !== 1n) return false;
    
    const sqrtVal = integerSQRT(n);
    return n === sqrtVal * sqrtVal;
}

(2)优化整数开方的初始值

避免BigInt转字符串的耗时操作,改用二进制位长度计算初始近似值:

var integerSQRT = function(value) {
    if (value < 2n) return value;
    if (value < 16n) return BigInt(Math.sqrt(Number(value)) | 0);
    
    let x1;
    if (value < 4503599627370496n) {
        x1 = BigInt(Math.sqrt(Number(value))|0) - 3n;
    } else {
        // 用二进制位长度生成初始值,比转字符串快数倍
        const bitLength = value.toString(2).length;
        x1 = 1n << ((BigInt(bitLength) - 1n) >> 1n);
    }
   
    let x0;
    do {
        x0 = x1;
        x1 = ((value / x0) + x0) >> 1n;
    } while (x0 !== x1 && x0 !== x1 - 1n);
    return x0;
}

(3)循环变量用Number(上限在安全整数范围时)

若limit未超出Number.MAX_SAFE_INTEGER,循环变量用Number类型,计算时再转BigInt,比BigInt循环更快:

for (let n = 2; n < limit; n++) {
  const nBig = BigInt(n);
  current += 13n * (2nBig - 1n);
  if (perfectSquare(current)) {
    a.push(nBig);
  }
}

二、最优解法:利用佩尔方程递推生成解

你的问题本质是求解佩尔方程 (y^2 - 13n^2 = 1),这类方程无需暴力遍历,所有解可通过最小解递推生成,性能提升几个数量级:

  1. 方程的最小解为:(y=649, n=180)(验证:(649^2 -13×180^2=421201-421200=1))
  2. 后续解通过以下公式递推:
    [
    \begin{cases}
    y_{k+1} = 649×y_k + 13×180×n_k \
    n_{k+1} = 649×n_k + 180×y_k
    \end{cases}
    ]

实现代码

function generatePellSolutions(count) {
    const solutions = [];
    let y = 649n;
    let n = 180n;
    solutions.push(n);
    
    for (let i = 1; i < count; i++) {
        const nextY = 649n * y + 13n * 180n * n;
        const nextN = 649n * n + 180n * y;
        solutions.push(nextN);
        y = nextY;
        n = nextN;
    }
    return solutions;
}

// 生成前13个解
console.time('pell equation');
const solutions = generatePellSolutions(13);
console.log(solutions.join(', '));
console.timeEnd('pell equation');

这段代码生成前13个解仅需数毫秒,无论n多大都能瞬间生成,完全无需遍历。


内容的提问来源于stack exchange,提问作者Edge

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 08:55:12