关于javascript:Math.sqrt()的更快替代品

Faster Alternative to Math.sqrt()

除了使用Math.sqrt()来获得未知值的平方根之外,还有其他选择吗?

例如:

1
2
var random  = (Math.random() * (999 - 1)) + 1;
var sqrt = Math.sqrt(random);

我听说使用Math.sqrt()来获取数字的平方根是一个非常慢的操作,我只是想知道是否有更快的方法可以获取随机数的平方根。 任何帮助,将不胜感激。


您可以确定,如果不是更好的话,Math.sqrt中已经实现了将要编写自己的最快算法。

有一种算法可以遍历数字直到中间(通过一些简单的计算即可):编写自己的平方根函数

但正如我所说,如果不是更好的话,它可能会实施。

您可以尝试寻找一些特定的业务/域逻辑,以减小数字范围。


不知道您的sqrt是如何实现的(不是JavaScript编码器),所以我只能推测是更快的方法,但是对于IEEE 754 float/double格式和integers来说,很少有使用"幻数"的快速方法。例如Quake3。在定义的时间间隔内只有很少的几个操作会或多或少地精确,并且可能比sqrt更快,但仅在特定的时间间隔内可用。

通常的sqrt实现是通过以下方式完成的:

  • 近似多项式

    通常使用泰勒级数,切比雪夫等展开式,并且有效值的数量取决于目标精度。并非所有的数学函数都可以这样计算。

  • 迭代逼近

    牛顿,巴比伦等方法很少会收敛得足够快,因此无需使用过多的热量。我的赌注是您的sqrt使用牛顿近似。

    还有基于二进制搜索的计算

    • 通过平方来求负指数的幂

    二元搜索需要的迭代次数与所使用的结果结果位数相同,通常比上述近似方法中使用的均方根还要大。但是对sqrt进行二进制搜索有一个巨大的优势,那就是无需乘法就可以完成(这对于bignums来说非常重要...)

    • 如何仅在一个时钟周期内获得32位输入的平方根?

    还有其他搜索近似值,例如:

    • 近似搜索的工作原理
  • log2,exp2代数

    您可以直接从log2,exp2sqrt(x)=pow(x,0.5)计算pow

    • Math.Pow(等等)如何实际工作
  • LUT

    您可以对预先计算的查找表使用分段插值。

  • 混合方法

    您可以将更多方法组合在一起,例如使用低精度近似多项式估算结果,然后使用二进制搜索在其周围(仅几位)进行搜索……但这仅对"大"数(以位的方式)有意义。

  • 一些数学运算和常量可以使用PCA计算

    但我认为没有必要在您的情况下使用它...

  • 另外,有关更多信息,请查看相关的质量检查:

    • 平方根函数如何实现?

    不知道您要计算什么,但是最快的sqrt是什么时候根本不计算。可以重写许多计算和算法,因此它们根本不需要使用sqrt或至少不必经常使用sqrt(例如比较distance ^ 2等)。

    例如,如果您想这样做:

    1
    2
    x = Random();
    y = sqrt(x);

    您可以将其重写为:

    1
    2
    y= Random();
    x = y*y;

    但是要注意,随机性属性是不一样的!


    我认为您可以获得比内置预编译代码更快的速度,但是对于下面的信息,您可以找到有关如何使用纯JS获得数字平方根的算法。

    它相当快,但是由于它是递归的,所以它的迭代速度可能会比它的迭代版本慢一些。 迭代实现取决于您。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var sqrt = (n, u = n, d = n-1 ? n/u : 1) => n ? (u === (u+d)/2) && (d === n/u) ? d : sqrt(n,(u+d)/2, n/u) : 0,
           s = 0;
    console.time("sqrt");
    var s = sqrt(9876543210*9876543210);
    console.timeEnd("sqrt");
    console.log(s);

    console.time("sqrt");
    var s = sqrt(98765.4321*98765.4321);
    console.timeEnd("sqrt");
    console.log(s);

    它利用巴比伦方法。


    如果您拥有的代码与您使用的代码相同,则根本不需要平方根

    1
    2
    var random  = (Math.random() * (999 - 1)) + 1;
    var sqrt = Math.sqrt(random);

    可能

    1
    2
    var sqrt  = (Math.random() * ( 31.6069612586)) + 1;
    var random  = sqrt * sqrt ;

    乘法比sqrt快得多,因此代码应该相似

    请注意,可以像上面一样预先计算998的平方根,以使其成为一次运算而不是每次运行


    您看到的与sqrt的分配不相等。为了获得相同的分布,您需要一个因素来改变分布。该因子取决于随机数。没有捷径可走。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function getRandom() {
        return Math.sqrt((Math.random() * (999 - 1)) + 1);
    }

    var i, r,
        o = {};

    for (i = 0; i < 32; i++) {
        o[i] = 0;
    }

    for (i = 0; i < 100000; i++) {
        o[Math.floor(getRandom())]++;
    }

    console.log(o);
    1
    .as-console-wrapper { max-height: 100% !important; top: 0; }


    数学规定:

    1
    var sqrt = Math.sqrt(random);

    等效于:

    1
    var sqrt = random**.5;

    可能不会更快,但绝对会更短。