Inspirado por un comentario en una publicación de
Fibonacci para una entrevista . El usuario
pavellyzhin mencionó la siguiente tarea de entrevista (
comentario ):
Hace más de un año, "php-programmer" respondió a la vacante, enviaron TK y hubo una tarea de Fibonacci: seleccionar todos los números de Fibonacci incluso en el rango de 1 a 10000 . Decidió usar un bucle (for). Allí, también era necesario hacer una consulta SQL para seleccionar los cumpleaños más cercanos de los usuarios, para inventar algo, simplemente no recuerdo y escribo algún tipo de función. Hice todo, lo envié. Enviaron una respuesta: "de acuerdo con los resultados de la tarea de prueba, usted no es aceptado". Lo que no les gustó exactamente no fue escrito. Ahora estoy sentado y pensando, probablemente después de todo por Fibonacci volé ... :)
En esta publicación voy a mostrar cómo fue posible resolver este problema de manera efectiva, y tal vez incluso de manera eficiente, pero esto no es exacto. Al mismo tiempo, demostraré un par de miles de hechos probados sobre los números de Fibonacci.
Teorizando
La mejor manera de comenzar es mirar a través de los ojos de los primeros números de N Fibonacci e intentar encontrar un patrón en la disposición de los números pares.
1.1, bf2,3.5, bf8,13.21, bf34,55.89, bf144, ldots
Los números pares están marcados en la secuencia, como puede ver, cada tercer número de Fibonacci es par y, probablemente, todos los números pares están en posiciones de múltiplos de 3. Esta será nuestra suposición, ahora debemos confirmarlo y desarrollar un algoritmo de cálculo.
La mejor prueba es simple, así que gracias a
AllexIn por la idea simple que inicialmente me perdí. Cada número subsiguiente de Fibonacci es la suma de los dos anteriores, si los dos números anteriores son impares, el siguiente será par, si en los dos números anteriores uno es impar y el otro es par, entonces el siguiente será impar. En principio, esta idea por sí sola ya es suficiente para "palpar intuitivamente" el hecho comprobado. La prueba por inducción es obvia, pero no puedo resistirme, para no traerla.
Probamos que "cada tercer número de Fibonacci es par, y los dos que preceden a cada número son impares".
- Base de inducción . Los dos primeros números de Fibonacci 1.1 - impar, tercer número 2 - incluso
- Hipótesis Suponga que hasta un número de Fibonacci múltiplo de 3 es cierto que cada tercio es par, y los dos anteriores son impares.
- Paso de inducción . El número que sigue al último par de la hipótesis es impar, porque se obtiene de la suma de lo impar con lo par, después de ese número ya también es impar, porque se obtiene de la suma de los pares con los impares, y el siguiente después de que es par, porque los dos anteriores que acaba de recibir son impares, por construcción su número es múltiplo de 3, es par, y los dos anteriores son impares.
Así es como podemos probar nuestras suposiciones sin siquiera recurrir a cálculos matemáticos. Puede formalizar esta idea, al mismo tiempo que obtiene una fórmula para calcular cada tercer número de Fibonacci
Fn+3 de
Fn y
Fn+1 . Usando la relación recursiva
Fn+2=Fn+1+Fn obtenemos:
Fn+3=Fn+2+Fn+1=2Fn+1+Fn
Entonces si
Fn - incluso entonces
Fn+3 También incluso en virtud de esta fórmula. Dado que
F3=2 , entonces cada tercer número de Fibonacci es realmente par, lo que confirma parte de nuestra suposición. Aquí debe asegurarse de no perder otros números pares, es decir, que todos tienen múltiplos de 3. Gracias a
janatem por su idea simple, porque de la fórmula anterior para
Fn+3 También se deduce que si
Fn - extraño entonces
Fn+3 también extraño, así que obtenemos esos números con números
3k−2,3k−1,k in mathbbN - impar (por inducción, comience con
F1=F2=1 - impar), y
3k,k in mathbbN - par, que cubre todos los números de Fibonacci, lo que significa que realmente cubrimos todos los números pares.
Hay otra forma, ya que sería posible demostrar que no hay otros números pares. Supongamos que existe un número
Fm - incluso y
0 not equivm mod3 entonces
m=3k−1 o
m=3k+1 donde
k - Algún tipo de natural.
Pasemos a la representación matricial de los números de Fibonacci de la publicación original
\ begin {pmatrix} 0 & 1 \\ 1 & 1 \ end {pmatrix} ^ n = \ begin {pmatrix} F_ {n-1} & F_n \\ F_n & F_ {n + 1} \ end {pmatrix}
\ begin {pmatrix} 0 & 1 \\ 1 & 1 \ end {pmatrix} ^ n = \ begin {pmatrix} F_ {n-1} & F_n \\ F_n & F_ {n + 1} \ end {pmatrix}
Calculando el determinante de ambas partes, obtenemos
(−1)n=Fn+1Fn−1−F2n
Se deduce que los divisores de números
Fn+1,Fn y
Fn−1,Fn divisores de partido
(−1)n es decir los números vecinos de Fibonacci son mutuamente simples. Esto también significa que la simplicidad mutua y los números
F3k,F3k−1 y
F3k,F3k+1 es decir
F3k y
Fm . Pero por suposición
Fm - incluso, y
F3k - incluso como se probó previamente. Así que otros números pares que
F3k donde
k in mathbbN en la secuencia de Fibonacci no existe. Y también establecimos un hecho interesante de que los números vecinos de Fibonacci son mutuos simples.
Finalmente, mostramos al menos una forma más de demostrar nuestra suposición: usar el teorema de Luke.
El teorema de Luke . El entero divide
Fm y
Fn , si y solo si es un divisor
Fd donde
d= mcd(m,n) en particular
gcd(Fm,Fn)=F gcd(m,n)
Aqui
gcd Es el mayor factor común. Si poner
m=3 entonces
gcd(2,Fn)=F gcd(3,n) . Si
Fn - incluso, entonces el lado izquierdo es 2, de modo que el lado derecho también es igual a 2, es necesario que
n dividido por 3 y al mismo tiempo lo contrario es cierto. Por lo tanto, obtenemos exactamente lo que queríamos probar.
Entonces, cada tercer número de Fibonacci es par, y cada par tiene un múltiplo de tres. Hemos probado esto cuidadosamente y nadie se atreve a dudarlo ahora.
Algoritmo
Y ahora queda por encontrar un algoritmo. Por supuesto, puede hacer lo que originalmente hizo
pavellyzhin , pero en lugar de verificar
0 equivFn mod2 podemos verificar
0 equivn mod3 , esto es un giro! Es cierto que esto no afecta el número de iteraciones del algoritmo, porque acabamos de cambiar el filtro de secuencia. Es mejor generar inmediatamente una subsecuencia de números de Fibonacci con la propiedad que necesitamos (paridad), por lo que otra forma obvia es usar la fórmula de Binet
F_n = \ left \ lfloor \ frac {\ varphi ^ n} {\ sqrt {5}} \ right \ rceil, \ qquad n \ in \ {3,6, \ ldots, 3k \ ldots \}
F_n = \ left \ lfloor \ frac {\ varphi ^ n} {\ sqrt {5}} \ right \ rceil, \ qquad n \ in \ {3,6, \ ldots, 3k \ ldots \}
Hay dificultades con la eficiencia de los cálculos, más sobre esto en la publicación original. Por lo tanto, propongo el mejor método, en mi opinión, cálculo iterativo
Fn+3 , esto se puede hacer, como mostramos anteriormente, mediante la fórmula
Fn+3=2Fn+1+Fn . Para construir una transición iterativa en el algoritmo, necesitamos calcular
Fn+4 , todo es igual de simple
Fn+4=Fn+3+Fn+2=2Fn+1+Fn+Fn+1+Fn=3Fn+1+2Fn
Por cierto, en general, es fácil demostrar que
Fn+m=FmFn+1+Fm−1Fn
Luego, formalmente, el algoritmo se escribe de la siguiente manera (el número actual actual de Fibonacci
Fn seguido por el número de Fibonacci
Fn+1 ,
M Es el límite superior para los números dados en la condición del problema):
- Fn leftarrowF3=2, quadFn+1 leftarrowF4=3
- Si Fn>M , luego termine, de lo contrario agregue al resultado Fn
- (Fn,Fn+1) leftarrow(2Fn+1+Fn,3Fn+1+2Fn) vaya al paso 2.
El algoritmo es bastante trivial: simplemente saltamos a cada tercer número de Fibonacci e imprimimos (si no es más
M ) La complejidad del algoritmo sigue siendo lineal, pero el número de repeticiones del paso 2 es exactamente igual al número de números pares de Fibonacci en el rango
1 ldotsM , para comparar, un algoritmo simple con filtrado requiere 3 veces más iteraciones (por cada encontrado, habrá 2 descartados).
El algoritmo existe en papel, ¿cuál fue la entrevista, PHP? Bueno, finalmente descubrir PHP significa
function evenfibs($ubound) { $result = []; [$evenf, $nextf] = [2, 3]; while($evenf <= $ubound) { array_push($result, $evenf); [$nextf, $evenf] = [ 3 * $nextf + 2 * $evenf, 2 * $nextf + $evenf]; } return $result; }
Nota : Este método siempre se puede mejorar, como, por ejemplo, mostró el usuario
hunroll . La idea es que para los cálculos no necesitamos nada superfluo, excepto el resultado parcialmente obtenido, es decir. podemos calcular números pares usando solo los números anteriores de Fibonacci pares.
Fn+3=2Fn+1+Fn=3Fn+2Fn−1=3Fn+Fn−1+Fn−1=3Fn+(Fn−1+Fn−2)+Fn−3=4Fn+Fn−3
function evenfibs($ubound) { if($ubound < 2) return []; $evens = [2]; $next = 8; for($i = 1; $next <= $ubound; $i++) { $evens[$i] = $next; $next = $evens[$i]*4 + $evens[$i-1]; } return $evens; }
Generalización
Mencionamos aquí el teorema de Luke, que establece que
gcd(Fm,Fn)=F gcd(m,n) . Como consecuencia de ello, podemos obtener que el número de Fibonacci
Fn múltiplo de
Fm , si y solo si su número
n múltiplo a número
m . Es decir cada 4to número de Fibonacci se divide por 3, cada 5to por 5, cada 6to por 8, etc.
Luego, de manera simple, obtenemos un algoritmo para calcular la subsecuencia de Fibonacci, en el que los elementos son múltiplos de un número dado
Fm . Usando el hecho de que
Fn+m=FmFn+1+Fm−1FnFn+m+1=Fm+1Fn+1+FmFn
El algoritmo anterior se convierte en
- Fn leftarrowFm, quadFn+1 leftarrowFm+1
- Si Fn>M , luego termine, de lo contrario agregue al resultado Fn
- (Fn,Fn+1) leftarrow(FmFn+1+Fm−1Fn,Fm+1Fn+1+FmFn) vaya al paso 2.
Donde
Fm−1,Fm,Fm+1 se puede establecer como constantes.
Resumen de notas . Como la
ignorancia del usuario señaló correctamente, en el caso generalizado, también es posible construir un algoritmo que use solo números de un resultado parcial.
Fn+1=Fn+Fn−1Fn+2=3Fn−Fn−2Fn+3=4Fn+Fn−3Fn+4=7Fn−Fn−4Fn+5=11Fn+Fn−5 cdotsFn+t=(Ft+2Ft−1)Fn+(−1)t−1Fnt
Probemos esto por el método de inducción matemática, para t = 1 yt = 2, el cumplimiento es obvio. Supongamos que soporta algo de t; entonces
Fn+t+1=Fn+t+Fn+t−1=(Ft+2Ft−1)Fn+(−1)t−1Fnt+(Ft−1+2Ft−2)Fn+(−1)t−2Fn−t+1=(Ft+Ft−1+2(Ft−1+Ft−2))Fn+(−1)t−1(Fnt−Fn−t+1)=(Ft+1+2Ft)Fn+(−1)t−1(Fnt−Fnt−Fnt−1)=(Ft+1+2Ft)Fn+(−1)tFnt−1
Algo como un total
La tarea, por supuesto, es completamente sintética, el número de iteraciones es muy pequeño (para
M=$10,00 la respuesta contiene solo 6 números, es decir Se habrían completado 6 iteraciones, y el algoritmo original "de frente" habría requerido 18), pero de esta manera un usuario que descubrió algo nuevo aquí ahora puede mostrar un poco más de conocimiento matemático en los números de Fibonacci en la entrevista.
Editar: Gracias a los
usuarios de
janatem y
AllexIn por las pruebas simples, las incluí en "Teoremización", así como
también por el algoritmo usando solo los números pares ya obtenidos en los cálculos y la
ignorancia del usuario por generalizarlo.