Tengo una función JS, con entradas de matriz.
Por ejemplo:
x=[ 239709880, 250229420, 109667654, 196414465, 13098 ]
y=[78135241, 54642792, 249]
O:
x=[ 0, 0, 0, 0, 0, 0, 1 ]
y=[78135241, 54642792, 249]
O:
x=[ 49 ]
y=[ 33 ]
function bdiv(x,y) { var n=x.length-1, t=y.length-1, nmt=nt, 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=it-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; }
Lo que he hecho en menos de 5 días hasta ahora en PHP:
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]; }Entonces, como marqué en el código PHP, tengo un problema con array_push($x,$x) , parece que este no es el equivalente de x=x.concat() . Array_push agrega todos los valores $x actuales como un nuevo elemento a la matriz $x existente:
$x=[ 1, 2, 3 ];
array_push($x,$x);
entonces $x será [ 1, 2, 3, [ 1, 2, 3 ] ]
Si intento aplanar la matriz ( $x=array_merge(...$x); ), aparece un nuevo error de PHP: array_merge(): el argumento n.º 1 no es una matriz
Realmente agradecería si alguien tiene alguna idea de cómo convertir correctamente esta función JS a una versión de PHP. Gracias por adelantado.
==========================> ACTUALIZAR I
Idea de @Kiran Shakya para reemplazar x=x.concat() con $x=array_merge(array(),$x); está funcionando o al menos no recibo ningún error o advertencia de PHP al respecto, pero inicio un bucle infinito, que tengo que cerrar manualmente. El script que llama a la función toppart, que opera con números de precisión arbitraria (multiplicar y sumar):
function toppart(x,start,len) { var n=0 while(start >= 0 && len > 0){ n=n*bx2+x[start--] len-- } return n } La parte interesante es que JS devolvió un ejemplo 70144566321522750 pero PHP devolvió 70144566321522751. En el ciclo posterior, las diferencias son mucho mayores.
Revisé todos los números en ambas versiones y todas las mismas entradas: x, inicio, len, bx2. Esto puede ser un error o uno de ellos no puede manejar números enteros grandes o ¿cuál puede ser el motivo?
==========================> ACTUALIZACIÓN II
Apliqué la solución Booboo, simplemente omití por completo las partes concat ()
Entonces las entradas son:
$x=[ 210763776, 109357119, 261308872];
$inicio=2;
$largo=2;
$bx2=268435456;
... y devuelve 70144566321522751 en PHP y 70144566321522750 en JS. Yo uso bcadd() y bcmul() pero el resultado es el mismo si estoy usando signos de operadores matemáticos.
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; }reemplace array_push con array_merge.
Esto devolverá la matriz fusionada y luego almacenará el resultado en $x;
array_merge está destinado a matrices. tomará los valores de una matriz y los agregará a la otra. al igual que lo hace concat en JS.
... divide la matriz ($x) en varios valores, esta no es la entrada correcta. es el equivalente de array_merge(1,2,3) (es decir, no se están ingresando matrices)
$x = array(1,2,3); $x = array_merge($x,$x); var_dump($x); //output: [1,2,3,1,2,3] echo $x[4]; // output: 2si he entendido mal la pregunta por favor hágamelo saber.
Use array_merge en lugar de array_push, es decir
$x = array(1, 2, 3); print_r(array_merge($x,$x));Estoy confundido por qué su código JavaScript incluso tiene:
x=x.concat() y=y.concat()No sirven para ningún otro propósito que no sea asignarse una nueva copia de la misma matriz. Si tenía la intención de evitar la modificación en la matriz original, simplemente puede reemplazar esas dos líneas de código con:
$x = array_merge(array(), $x); $y = array_merge(array(), $y);Ambos sirven exactamente para el mismo propósito.
En este punto, no estoy seguro sobre el resto del código php que escribiste hasta ahora, pero si te ayuda de alguna manera, está bien.
Si lo que está haciendo con x = x.concat() es intentar asegurarse de que su función no modifique la matriz pasada original, no tiene que hacer nada para asegurarse de que en su versión PHP de esta función porque por defecto los argumentos se copiarán en lugar de pasarse por referencia . Para forzar que una matriz se pase por referencia en PHP, debe preceder el nombre del argumento con un ampersand ( & ). Esto se puede demostrar con el siguiente programa donde hemos definido dos funciones, cada una de las cuales modifica el primer elemento de la matriz pasada. En la primera función, test1 , el argumento de la matriz se copia para que la matriz pasada original no se modifique. Pero en la segunda función, test2 , el argumento de la matriz se pasa por referencia y cuando la función regresa, la matriz original pasada habrá sido modificada. La única diferencia entre las dos funciones es que en test1 los argumentos se definen como $x y en test2 como &$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);Huellas dactilares:
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 )Actualizar
Tienes varios problemas. Primero, describe que toppart devuelve diferentes valores en las versiones de JavaScript y PHP y nos pide que le expliquemos la discrepancia, pero nunca especifica cuáles fueron las entradas reales de los valores start , len y bx2 para las funciones y nos deja que lo averigüemos por nosotros mismos. ¿Y publicaste la versión PHP de toppart porque no la veo?
En segundo lugar, permítanme ampliar mi respuesta anterior. Debería haber dicho que las matrices se copiarán de forma predeterminada en lugar de pasarse por referencia (los objetos de clase se pasarán por referencia, pero eso no se aplica aquí). Pero eso no es solo para pasar argumentos a funciones. Considera lo siguiente:
$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] Entonces, si tiene una matriz de JavaScript a y la asignación b = a , que es una copia de referencia tal que si modifica b está modificando la matriz a la que hace referencia b también está modificando la matriz a la que hace referencia a , el equivalente semántico en PHP es $b = @$a; . Esto asegura que $b y $a no solo se refieran a la misma matriz, sino que si modifica la matriz a la que hace referencia $b , estará modificando la misma matriz a la que hace referencia $a .
Entonces, si tiene una función de JavaScript definida de la siguiente manera:
function bdiv(x, y) { etc. donde $x y $y son matrices, teóricamente bdiv podría modificar las matrices reales que se pasan y se les asignan alias como x e y y, por lo tanto, el equivalente semántico en PHP sería definir esta función de la siguiente manera:
function bdiv(@$x, @$y) { etc.Pero aquí está el problema. Más adelante en el código JavaScript tenemos:
x=x.concat()En JavaScript, no tiene más remedio que pasar argumentos de matriz por referencia. Anteriormente en el código JavaScript hay:
for(;;) { xx=bsub(x,y) if(xx.length==0) break x=xx; q++ } La asignación a x se ejecuta condicionalmente, pero ciertamente modificaría el argumento x pasado. Entonces, más adelante, cuando se ejecute el código x=x.concat() para asignar una copia del valor actual de x a x , esto ciertamente evitaría una mayor modificación posterior de la matriz pasada, pero ¿qué más logra? Antes de la copia de x hay asignaciones como arr['mod'] = x y después de hacer la copia de x tenemos asignaciones a x[0] . Sin la copia de x , esa asignación a x[0] también estaría actualizando la matriz almacenada en arr['mod'] . Entonces, la copia de la matriz se está realizando para evitar eso.
Hay varios modismos de PHP para hacer una copia de una matriz, como ya se señaló, por ejemplo, $x = array_merge([], $x) . Pero incluso si ejecuta esta instrucción en PHP, una vez que haya definido el argumento para bdiv como @$x , es decir, pase por referencia, seguirá modificando posteriormente la matriz pasada a medida que realiza las asignaciones a la matriz a la que hace referencia x . Por lo tanto, no puede haber un equivalente PHP exacto del resultado de JavaScript en cuanto a lo que la matriz JavaScript x pasada terminará siendo cuando la función regrese. El siguiente programa PHP demostró que incluso después de que se asigna una copia de x a x y luego se realiza una asignación a la nueva matriz a la que hace referencia x , actualiza la matriz pasada:
<?php function test(&$x) { $x = array_merge(array(), $x); $x[0] = 9; print_r($x); } $arr = [0, 1, 2]; test($arr); print_r($arr);Huellas dactilares:
Array ( [0] => 9 [1] => 1 [2] => 2 ) Array ( [0] => 9 [1] => 1 [2] => 2 ) Por lo tanto, esta copia de matriz no tendrá el otro efecto de evitar más modificaciones en la matriz pasada. Por lo que puedo decir, el programa JavaScript original en realidad deja la matriz pasada original en un estado indefinido. También puede dejar la función de PHP definida como bdiv($x, $y) para que las matrices originales no se modifiquen.
Pero la discusión anterior sugiere que puede tener un problema en otro lugar. Cuando tiene una asignación de JavaScript de la forma a = b donde b es una matriz y hay una modificación posterior a a , por ejemplo a[i] = some_value , el código PHP equivalente debe ser $a = @$b; etc, es decir, una asignación de referencia.
Y como se menciona en un comentario de @AKX, debe consultar las funciones de BC Math si tiene problemas con toppart .