将 JavaScript 函数转换为 PHP

Posted

技术标签:

【中文标题】将 JavaScript 函数转换为 PHP【英文标题】:Convert JavaScript function to PHP 【发布时间】:2022-01-04 02:06:25 【问题描述】:

我有一个 JS 函数,带有数组输入。例如:

x=[ 239709880, 250229420, 109667654, 196414465, 13098 ] y=[ 78135241, 54642792, 249]

或者:

x=[ 0, 0, 0, 0, 0, 0, 1 ] y=[ 78135241, 54642792, 249]

或者:

x=[49] y=[33]

function bdiv(x,y) 
    var n=x.length-1, t=y.length-1, nmt=n-t, arr = []
    if(n < t || n==t && (x[n]<y[n] || n>0 && x[n]==y[n] && x[n-1]<y[n-1])) 
        arr['q']=[0]
        arr['mod']=x
        return arr
    
    if(n==t && toppart(x,t,2)/toppart(y,t,2) <4) 
        var q=0, xx
        for(;;) 
            xx=bsub(x,y)
            if(xx.length==0) break
            x=xx; q++
        
        arr['q']=[q]
        arr['mod']=x
        return arr
    
    var shift, shift2
    shift2=Math.floor(Math.log(y[t])/log2)+1
    shift=bs-shift2

    if(shift) 
        x=x.concat()
        y=y.concat()
        for(i=t; i>0; i--) y[i]=((y[i]<<shift) & bm) | (y[i-1] >> shift2); y[0]=(y[0]<<shift) & bm
        if(x[n] & ((bm <<shift2) & bm))  x[++n]=0; nmt++; 
        for(i=n; i>0; i--) x[i]=((x[i]<<shift) & bm) | (x[i-1] >> shift2); x[0]=(x[0]<<shift) & bm
    
    var i, j, x2, y2,q=zeros(nmt+1)

    y2=zeros(nmt).concat(y)

    for(;;) 
        x2=bsub(x,y2)
        if(x2.length==0) break
        q[nmt]++
        x=x2
    
    var yt=y[t], top=toppart(y,t,2)
    for(i=n; i>t; i--) 
        m=i-t-1
        if(i >= x.length)
            q[m]=1
        else if(x[i] == yt)
            q[m]=bm
        else
            q[m]=Math.floor(toppart(x,i,2)/yt)
        topx=toppart(x,i,3)
        while(q[m] * top > topx)
            q[m]--
        y2=y2.slice(1)
        x2=bsub(x,bmul([q[m]],y2))
        if(x2.length==0) 
            q[m]--
            x2=bsub(x,bmul([q[m]],y2))
        
        x=x2
    
    if(shift)
        for(i=0; i<x.length-1; i++)
            x[i]=(x[i]>>shift) | ((x[i+1] << shift2) & bm);
        x[x.length-1]>>=shift
    
    while(q.length > 1 && q[q.length-1]==0)
        q=q.slice(0,q.length-1)
    while(x.length > 1 && x[x.length-1]==0)
        x=x.slice(0,x.length-1)
    arr['q']=q
    arr['mod']=x
    return arr;

到目前为止,我在 php 中不到 5 天的时间里做了什么:

function bdiv($x,$y)
    global $bs, $bm, $bx2, $bx, $bd, $bdm, $log2;
    $arr=[];
    $n=count($x)-1;
    $t=count($y)-1;
    $nmt=$n-$t;

    if($n < $t || $n==$t && ($x[$n]<$y[$n] || $n>0 && $x[$n]==$y[$n] && $x[$n-1]<$y[$n-1]))
        return ['q'=>[0], 'mod'=>$x];

    if($n==$t && toppart($x,$t,2)/toppart($y,$t,2) <4)
        $q=0;
        for(;;)
            $xx=bsub($x,$y);
            if(count($xx)==0)
                break;
            $x=$xx;
            $q++;
        
        return ['q'=>[$q], 'mod'=>$x];
    

    $shift2=floor(log($y[$t])/$log2)+1;
    $shift=$bs-$shift2;
    if($shift)

/////////////////////////////////////////////// Booboo
        //$x = array_merge(array(),$x);
        //$y = array_merge(array(),$y);

        for($i=$t; $i>0; $i--)
            $y[$i]=(($y[$i] << $shift) & $bm) | ($y[$i-1] >> $shift2);
        $y[0]=($y[0] << $shift) & $bm;
        if($x[$n] & (($bm << $shift2) & $bm))
            $x[++$n]=0;
            $nmt++;
        
        for($i=$n; $i > 0; $i--)
            $x[$i]=(($x[$i] << $shift) & $bm) | ($x[$i-1] >> $shift2);
        $x[0]=($x[0] << $shift) & $bm;
    
    $q=zeros($nmt+1);

    //array_push($arr, zeros($nmt));
    //array_push($arr, $y);
    //$y2=array_merge(...$arr);
    //////////////////////////////////// use array_merge straight away
    $y2=array_merge(zeros($nmt),$y);

    for(;;)
        $x2=bsub($x,$y2);
        if(count($x2)==0)
            break;
        $q[$nmt]++;
        $x=$x2;
    

    $yt=$y[$t];
    $top=toppart($y,$t,2);

    for($i=$n; $i>$t; $i--)
        $m=$i-$t-1;
        if($i >= count($x))
            $q[$m]=1;
        else if($x[$i] == $yt)
            $q[$m]=$bm;
        else
            $q[$m]=floor(toppart($x,$i,2)/$yt);

        $topx=toppart($x,$i,3);
        while($q[$m] * $top > $topx)
            $q[$m]--;

        $y2=array_slice($y2,1);
        $x2=bsub($x,bmul([$q[$m]],$y2));

        if(count($x2)==0)
            $q[$m]--;
            $x2=bsub($x,bmul([$q[$m]],$y2));
        
        $x=$x2;
    

    if($shift)
        for($i=0; $i<count($x)-1; $i++)
            $x[$i]=($x[$i] >> $shift) | (($x[$i+1] << $shift2) & $bm);
        $x[count($x)-1] >>= $shift;
    

    while(count($q) > 1 && $q[count($q)-1]==0)
        $q=array_slice($q, 0, count($q)-1);
    while(count($x) > 1 && $x[count($x)-1]==0)
        $x=array_slice($x, 0, count($x)-1);

    return ['q'=>$q, 'mod'=>$x];

因此,正如我在 PHP 代码中标记的那样,array_push($x,$x) 有问题,似乎这不等同于 x=x.concat( )。 Array_push 将整个当前的 $x 值作为新元素添加到现有的 $x 数组中:

$x=[ 1, 2, 3 ]; array_push($x,$x); 那么 $x 将是 [ 1, 2, 3, [ 1, 2, 3 ] ]

如果我尝试展平数组 ($x=array_merge(...$x);) 则会出现一个新的 PHP 错误:array_merge(): Argument #1 is不是数组

如果有人知道如何将此 JS 函数正确转换为 PHP 版本,我将不胜感激。 提前致谢。

===========================> 更新我

@Kiran Shakya 想法将 x=x.concat() 替换为 $x=array_merge(array(),$x);实际上正在工作,或者至少我没有收到任何 PHP 错误或警告,但启动了一个无限循环,我必须手动关闭它。调用 toppart 函数的脚本,该函数使用任意精度数(乘法和加法):

    function toppart(x,start,len) 
        var n=0
        while(start >= 0 && len > 0)
            n=n*bx2+x[start--]
            len--
        
        return n
    

有趣的是,JS 为示例返回 70144566321522750,但 PHP 返回 70144566321522751。在后面的循环中差异更大。我检查了两个版本中的所有数字和所有相同的输入:x,开始,长度,bx2。这可能是一个错误,或者其中一个无法处理大整数,或者可能是什么原因?

===========================> 更新二

我应用了 Booboo 解决方案,我只是完全跳过了 concat() 部分

所以输入是:

$x=[210763776, 109357119, 261308872]; $开始=2; $len=2; $bx2=268435456;

...并在 PHP 中返回 70144566321522751,在 JS 中返回 70144566321522750。我使用 bcadd() 和 bcmul() 但如果我使用数学运算符符号,结果是相同的。

function toppart($x,$start,$len)
    global $bs, $bm, $bx2, $bx, $bd, $bdm, $log2;
    $n=0;
    while($start >= 0 && $len > 0)
        $n= bcadd(bcmul($n, $bx2),$x[$start--]);
        $len--;
    

    return $n;

【问题讨论】:

谷歌搜索代码,它看起来像是an arbitrary-precision division function。如果是这样,你为什么不直接使用bcmath's bcdiv() @AKX 这正是我的版本!不幸的是,我对这个函数并不熟悉,当我读了一点,输入是字符串,而不是数组。 x=x.concat()在js中的意思是从x中克隆一个新数组并返回给x。这样做的原因不是改变原始输入。在 php 中,您可以使用 array_slice($x, 0) 从它返回一个新数组,而不是 array_push($x,$x); 您的 javascript 函数不可运行,在第 21 行它引用了一个不存在的 bs 变量。 bs 应该在第 21 行的shift=bs-shift2 上是什么? 还引用了一个不存在的函数,函数zeros应该做什么? 【参考方案1】:

如果您对x = x.concat() 所做的操作是试图确保原始传递的数组没有被您的函数修改,您不必做任何事情来确保在您的 PHP 版本中这个函数,因为默认情况下,参数将被复制而不是通过引用传递。要在 PHP 中强制通过引用传递数组,您必须在参数名称前加上一个 & 符号 (&amp;)。这可以通过以下程序进行演示,其中我们定义了两个函数,每个函数都修改传递数组的第一个元素。在第一个函数test1 中,数组参数被复制,因此原始传递的数组保持不变。但是在第二个函数test2 中,数组参数是通过引用传递的,当函数返回时,原始传递的数组将被修改。这两个函数之间的唯一区别是,在test1 中,参数被定义为$x,而在test2 中,参数被定义为&$x

<?php

// $x is passed by value:
function test1($x)

    $x[0] = 9;
    print_r($x);


// $x is passed by reference:
function test2(&$x)

    $x[0] = 9;
    print_r($x);


$my_array = [0, 1, 2];
echo "Pass by value:\n";
test1($my_array); //$my_array remains unmodified
print_r($my_array);

echo "\n\nPass by reference:\n";
test2($my_array); //$my_array is modified
print_r($my_array);

打印:

Pass by value:
Array
(
    [0] => 9
    [1] => 1
    [2] => 2
)
Array
(
    [0] => 0
    [1] => 1
    [2] => 2
)


Pass by reference:
Array
(
    [0] => 9
    [1] => 1
    [2] => 2
)
Array
(
    [0] => 9
    [1] => 1
    [2] => 2
)

更新

您有几个问题。首先,您描述 toppart 在 JavaScript 和 PHP 版本中返回不同的值,并要求我们解释差异,但您从未指定实际的 startlenbx2 值输入到函数并离开我们自己弄清楚。并且你发布了toppart 的PHP 版本,因为我没有看到它。

其次,让我详细说明一下我之前的回答。我应该说 arrays 默认会被复制而不是通过引用传递(类对象 will 通过引用传递,但这在这里不适用)。但这不仅仅是为了将参数传递给函数。考虑以下几点:

$a = [0, 1, 2];
$b = $a; // copy-on-write
$b[0] = 9; // $b is [9, 1, 2]
echo $a; // $a is still [0, 1, 2]

因此,如果您有一个 JavaScript 数组 a 和赋值 b = a,这是一个引用副本,因此如果您修改 b,您正在修改 b 引用的数组,您也正在修改引用的数组通过a,PHP 中的语义等价物是$b = @$a;。这确保$b$a 不仅引用同一个数组,而且如果您修改$b 引用的数组,您将修改$a 引用的同一个数组。

所以如果你有一个 JavaScript 函数定义如下:

function bdiv(x, y)

etc.

其中 $x 和 $y 是数组,理论上 bdiv 可以修改传递的实际数组并别名为 xy,因此 PHP 中的语义等价物将定义此函数如下:

function bdiv(@$x, @$y)

etc.

但这就是问题所在。稍后在我们的 JavaScript 代码中:

x=x.concat()

在 JavaScript 中,您别无选择,只能通过引用传递数组参数。 JavaScript 代码中的早期有:

        for(;;) 
            xx=bsub(x,y)
            if(xx.length==0) break
            x=xx; q++
        

x 的赋值是有条件地执行的,但肯定会修改传递的x 参数。所以稍后当执行代码x=x.concat()x 的当前值的副本分配给x 时,这肯定会阻止对传递的数组进行进一步的修改,但它还能完成什么? x 的副本之前arr['mod'] = x 之类的分配,而在x 的副本之后我们有x[0] 的分配。如果没有x 的副本,分配给x[0] 也将更新存储在arr['mod'] 的数组。因此,正在执行数组复制以防止这种情况发生。

正如已经指出的那样,有几个 PHP 习惯用法可以用来制作数组的副本,例如 $x = array_merge([], $x)。但是即使您在 PHP 中执行此语句,一旦您将 bdiv 的参数定义为 @$x,即按引用传递,您仍然会随后修改传递的数组 当您对x 引用的数组进行分配时。因此,就传递的 JavaScript x 数组将在函数返回时结束的内容而言,不存在与 JavaScript 结果完全相同的 PHP 等价物。下面的 PHP 程序演示了即使将 x 的副本分配给 x,然后对 x 引用的新数组进行分配,它也会更新传递的数组:

<?php

function test(&$x)

    $x = array_merge(array(), $x);
    $x[0] = 9;
    print_r($x);


$arr = [0, 1, 2];
test($arr);
print_r($arr);

打印:

Array
(
    [0] => 9
    [1] => 1
    [2] => 2
)
Array
(
    [0] => 9
    [1] => 1
    [2] => 2
)

因此,此数组复制不会产生阻止对传递的数组进行进一步修改的其他效果。据我所知,原始 JavaScript 程序实际上将原始传递的数组置于未定义状态。您不妨将 PHP 函数定义为 bdiv($x, $y),这样原始数组就不会被修改。

但上述讨论表明您可能在其他地方遇到了问题。如果您有 a = b 形式的 JavaScript 赋值,其中 b 是一个数组,并且对 a 进行了后续修改,例如 a[i] = some_value,则等效的 PHP 代码必须是 $a = @$b; etc,,即参考分配。

正如@AKX 的评论中所述,如果您遇到toppart 的问题,您应该查看 BC 数学函数。

【讨论】:

为了更清楚,php中的数组是通过引用传递的,但是当数组发生突变时它会复制数组。对此有一个答案。 ***.com/a/9740541/14032355 @ikhvjs 谢谢 - 这是一个有趣的观点!所以这实际上是一种写​​时复制的情况。但它也是出于所有意图和目的(可能依赖于版本)的实现细节。 感谢您的回复。你认为在 PHP 中我可以跳过 JS 部分吗?不需要 $x=array_merge(array(),$x);如果我删除它,脚本的行为会有所不同。我更新了顶部的问题。 我重新评估了代码并更新了答案。我最初的回答是短视的,只解决了修改原始传递数组的问题。但是看看程序逻辑,我看到了制作这个副本的必要性。但是我的冗长更新中还有更多内容,所以请仔细阅读。【参考方案2】:

我很困惑为什么你的 JavaScript 代码甚至有:

x=x.concat()
y=y.concat()

除了将同一数组的新副本分配给自身之外,它们没有任何用途。如果是为了避免修改原始数组,那么您可以简单地将这两行代码替换为:

$x = array_merge(array(), $x);
$y = array_merge(array(), $y);

它们的用途完全相同。

在这一点上,我不确定你到目前为止编写的其余 php 代码,但如果它对你有帮助,那很好。

【讨论】:

到目前为止,这是最有效的解决方案: $x = array_merge(array(), $x); array_merge($x, $x) 为 $x 创建了错误的数组。【参考方案3】:

使用 array_merge 而不是 array_push 即

  $x = array(1, 2, 3);
       print_r(array_merge($x,$x));

【讨论】:

感谢您的回复。看起来array_merge比array_push好,但是第一个输入必须是一个空数组,而不是$x本身=> $x=array_merge(array(),$x);现在脚本只是开始一个无限循环。我更新了顶部的问题。【参考方案4】:

将 array_push 替换为 array_merge。

这将返回合并后的数组,然后将结果存储在 $x;

array_merge 用于数组。它将从一个数组中获取值并将其附加到另一个数组。就像 JS 中的 concat 一样。

... 将数组 ($x) 拆分为多个值,这不是正确的输入。它相当于 array_merge(1,2,3) (即没有输入数组)

$x = array(1,2,3);
$x = array_merge($x,$x);
var_dump($x); //output: [1,2,3,1,2,3]

echo $x[4]; // output: 2

如果我误解了这个问题,请告诉我。

【讨论】:

感谢您的回复。看起来array_merge比array_push好,但是第一个输入必须是一个空数组,而不是$x本身=> $x=array_merge(array(),$x);现在脚本只是开始一个无限循环。我更新了顶部的问题。

以上是关于将 JavaScript 函数转换为 PHP的主要内容,如果未能解决你的问题,请参考以下文章

如何将 JavaScript forEach 循环/函数转换为 CoffeeScript

将 JavaScript 函数转换为 PHP

将 Javascript Reduce 函数转换为 C#

将数组转换为“2元组”数组的Javascript函数[重复]

如何将字符串转换为 JavaScript 函数调用? [复制]

能否像在 Javascript 中将函数转换为字符串一样,将方法转换为 Java 中的字符串?