¡Repetido! Factoriales!


34

¡No debe confundirse con Find the factorial!

Introducción

El factorial de un entero nse puede calcular por

n!=n×(n1)×(n2)×(...)×2×1

Esto es relativamente fácil y nada nuevo. Sin embargo, los factoriales se pueden extender a factores dobles , de modo que para números pares, y para números impares. Pero no estamos limitados a factoriales dobles. Por ejemplo o or dependiendo de valor inicial

n!!=n×(n2)×(n4)×(...)×4×2
n!!=n×(n2)×(n4)×(...)×3×1
n!!!=n×(n3)×(n6)×(...)×6×3
n!!!=n×(n3)×(n6)×(...)×5×2
n!!!=n×(n3)×(n6)×(...)×4×1

En resumen: donde O, en inglés simple: reste el conteo factorial del número base repetidamente y multiplique todos los enteros positivos resultantes.

n!(k)={1if n=0nif 0<nkn((nk)!(k))if n>k
n!(k)=n!!k

El reto

Escriba una función que calcule cualquier tipo de factorial repetido para cualquier número entero no negativo.

Entrada

Ya sea

  • Una cadena que contiene un entero de base diez no negativo, seguido de 1 o más signos de exclamación. Por ejemplo, "6!"or "9!!"o "40!!!!!!!!!!!!!!!!!!!!".

o

  • Los mismos valores representados por dos enteros: un valor base no negativo y un valor positivo que representa el recuento factorial. Esto se puede hacer de acuerdo con cualquier formato de las reglas de E / S predeterminadas.

Salida

El resultado de dicho cálculo.

Observaciones de desafío

  • 0!igual 1por definición. Su código debe dar cuenta de esto.
  • El conteo factorial está limitado por fuera de este rango, usted es libre de generar lo que sea. Aparte de , que es la única excepción a esta regla.
    0<factorial countbase value
    0!

Ejemplos

Input                              Output

3!!!                               3
0!                                 1
6!                                 720
9!!                                945
10!!!!!!!!                         20
40!!!!!!!!!!!!!!!!!!!!             800
420!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!  41697106428257280000000000000000

Pruébelo con una implementación de Python sin golf: ¡ Pruébelo en línea!

Observaciones generales


66
La lista de ejemplos, 0!pero las observaciones del desafío dicen que el recuento factorial será menor o igual que el valor base.
Jonathan Allan

1
No 3! ser cero? n * (n-3) = 3 * (3-3) = 0.
ouflak

2
@ouflak Si funciona como 1 !, en realidad no. ¡Es más como 1! = 1. 2 !! = 2. 3 !!! = 3. No hay cálculo, porque estás al final de la recursividad. No hay 0 en los productos o, de lo contrario, cada factorial descendería a 0 al final.
V. Courtois

44
3!!!!!!!no debe estar indefinido, solo debe dar la respuesta 3. Es lo mismo que 1!!=1(no indefinido). Además, su especificación de entrada dice que siempre habrá al menos uno !, por lo que el primer ejemplo 3no se ajusta a la especificación.
Greg Martin

3
@ FabianRöling: Pero eso no es lo que es. En (3!)!cambio, no está eliminando términos de un factorial. Es un nombre engañoso; Entré suponiendo que iba a aplicar la función Factorial repetidamente en una cadena y tuve que leer cuidadosamente para ver qué era realmente. Afortunadamente, la pregunta lo explica claramente. Un nombre mejor podría ser factorial de paso o factorial de paso o algo así.
Peter Cordes

Respuestas:



13

ArnoldC , 702 698 634 bytes

LISTEN TO ME VERY CAREFULLY f
I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE n
I NEED YOUR CLOTHES YOUR BOOTS AND YOUR MOTORCYCLE p
GIVE THESE PEOPLE AIR
HEY CHRISTMAS TREE r
YOU SET US UP 1
HEY CHRISTMAS TREE c
YOU SET US UP 0
STICK AROUND n
GET TO THE CHOPPER r
HERE IS MY INVITATION r
YOU'RE FIRED n
ENOUGH TALK
GET TO THE CHOPPER n
HERE IS MY INVITATION n
GET DOWN p
ENOUGH TALK
GET TO THE CHOPPER c
HERE IS MY INVITATION 0
LET OFF SOME STEAM BENNET n
ENOUGH TALK
BECAUSE I'M GOING TO SAY PLEASE c
GET TO THE CHOPPER n
HERE IS MY INVITATION 0
ENOUGH TALK
YOU HAVE NO RESPECT FOR LOGIC
CHILL
I'LL BE BACK r
HASTA LA VISTA, BABY

Pruébalo en línea!

Traducido al pseudocódigo:

f(n,p) {
  r=1;
  c=0;
  while (n) {
    r=r*n;
    n=n-p;
    c=n<0;
    if (c) n=0;
  }
  return r;
}

Nota: ArnoldC tiene solo un tipo de datos: entero con signo de 16 bits. Por lo tanto, no puedo probar el 420!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!caso.


Solo curiosidad por tu psuedocode. ¿Para qué es la variable 'c'?
ouflak

@ouflak Edité mi respuesta un par de veces y la olvidé. La cvariable realmente almacena el valor de la comparación entre ny 0.
Charlie

+1 y lo tomé prestado (menos la 'c') para mi respuesta LUA.
ouflak

12

Jalea , 4 bytes

RṚmP

Pruébalo en línea!

¿Cómo? Dado y , primero genera el rango (con ), luego con él mantiene todos los elementos de este rango (entonces ), y finalmente los multiplica usando .nkn,,1k th n , n - k , n - 2 k , , n - n / k kRṚmkthn,nk,n2k,,nn/kkP


Funciona bien, y muy simple al final. No conozco a Jelly en absoluto, pero al menos se ve bien :)
V. Courtois

1
@ V.Courtois Dado y , primero genera el rango (con ), luego con cada elemento de este rango (entonces ), y finalmente los multiplica usando . Solo el enfoque directo. Editar: agregué esta explicación en la respuesta. k n , , 1 k th n , n - k , n - 2 k , , n - n / k knkn,,1RṚmkthn,nk,n2k,,nn/kkP
Sr. Xcoder

Ja muchas gracias. Un día podría querer jugar golf en este idioma, así que tendré que aprender esas mónadas, díadas, etc.
V. Courtois

Alternativas que se parece a Cjam: r1mP.
Erik the Outgolfer

1
@KyeWShi Jelly tiene su propia página de códigos , por lo que cada uno de los 256 caracteres que contiene está codificado como 1 byte.
Sr. Xcoder

8

APL (Dyalog Extended) , SBCS de 7 bytes

Función de prefijo tácito anónimo. Toma [n,b]como argumento.

×/-\…1¨

Pruébalo en línea!

 uno para cada elemento del argumento; [1,1]

-\ diferencia acumulativa; [n,n-b]

 rango usando el segundo elemento del argumento izquierdo como indicador del paso, por ejemplo, [9,7]continúa con5

×/ producto


7

Haskell , 21 bytes

n%a=product[n,n-a..1]

Pruébalo en línea!

La combinación de la función de producto incorporada con la enumeración de rango escalonada supera lo que podría codificar de forma recursiva (incluso con un error al guardar un byte).

22 bytes

n%a|n<1=1|m<-n-a=n*m%a

Pruébalo en línea!

Aquí hay una solución que toma la entrada en formato de cadena como 9!!, que creo que es más interesante.

42 bytes

(\[(n,a)]->product[n,n-length a..1]).reads

Pruébalo en línea!


2
Creo que podría acortar la solución recursiva an%a|n<1=1|m<-n-a=n*m%a
error


5

JavaScript (ES6), 21 bytes

Toma entrada como (k)(n).

k=>g=n=>n<1||n*g(n-k)

Pruébalo en línea!

O 24 bytes para admitir BigInts.


JavaScript (ES6), 55 bytes

Toma la entrada como una cadena, utilizando el formato descrito en el desafío.

s=>(a=s.split`!`,k=a.length-1,g=n=>n<1||n*g(n-k))(a[0])

Pruébalo en línea!


5

Espacio en blanco , 91 bytes

[S S S T    N
Push_1][S N
S _Duplicate_1][S N
S _Duplicate_1][T   N
T   T   _Read_STDIN_as_integer_(base)][T    T   T   _Retrieve_base][S S S N
_Push_0][T  N
T   T   _Read_STDIN_as_integer_(factorial)][N
S S N
_Create_Label_LOOP][S N
S _Duplicate_base][S S S T  N
_Push_1][T  S S T   _Subtract][N
T   T   S N
_If_negative_jump_to_Label_PRINT_RESULT][S N
S _Duplicate_base][S T  S S T   S N
_Copy_0-based_2nd_(result)][T   S S N
_Multiply][S N
T   _Swap_top_two][S S S N
_Push_0][T  T   T   _Retrieve_factorial][T  S S T   _Subtract][N
S N
N
_Jump_to_Label_LOOP][N
S S S N
_Create_Label_PRINT_RESULT][S N
N
_Discard_top][T N
S T _Print_result_as_integer]

Se agregaron letras S(espacio), T(tabulación) y N(nueva línea) solo como resaltado.
[..._some_action]agregado solo como explicación.

Pruébelo en línea (solo con espacios en bruto, pestañas y nuevas líneas).

Explicación en pseudocódigo:

Integer result = 1
Integer base = STDIN as integer
Integer factorial = STDIN as integer
Start LOOP:
  If(base <= 0):
    Call function PRINT_RESULT
  result = result * base
  base = base - factorial
  Go to next iteration of LOOP

function PRINT_RESULT:
  Print result as integer to STDOUT


4

Perl 6 , 22 bytes

{[*] $^a,*-$^b...^1>*}

Pruébalo en línea!

Codeblock anónimo que devuelve el producto del rango a partir de la primera entrada, disminuyendo en el segundo hasta que esté por debajo 1, excluyendo el último número. Esto funciona para 0, ya que el caso base de una reducción por producto es 1, por lo que la salida es 1.


4

05AB1E , 10 8 7 bytes

ݦRIιнP

Entrada como dos entradas separadas: la primera entrada es base; segunda entrada siendo factorial.

Pruébelo en línea o verifique todos los casos de prueba .

-2 bytes gracias a @ Mr.Xcoder .
-1 byte gracias a @JonathanAllan .

Explicación:

Ý        # Create a list in the range [0, (implicit) base-input]
 ¦       # And remove the first item to make it the range [1, base]
         # (NOTE: this is for the edge case 0. For the other test cases simply `L` instead
         #  of `ݦ` is enough.)
  R      # Reverse this list so the range is [base, 1]
   Iι    # Uninterleave with the second input as step-size
         #  i.e. base=3, factorial=7: [[3],[2],[1],[],[],[],[]]
         #  i.e. base=10, factorial=8: [[10,2],[9,1],[8],[7],[6],[5],[4],[3]]
         #  i.e. base=420, factorial=30: [[420,390,360,...,90,60,30],[419,389,359,...],...]
     н   # Only leave the first inner list
      P  # And take the product of its values
         # (which is output implicitly as result)

Respuesta original de 10 bytes :

L0KD¤-IÖÏP

Entrada como dos entradas separadas: la primera entrada es base; segunda entrada siendo factorial.

Pruébelo en línea o verifique todos los casos de prueba .

Explicación:

L           # Create a list in the range [1, (implicit) base-input]
 0K         # Remove all 0s (edge case for input 0, which will become the list [1,0])
   D        # Duplicate this list
    ¤       # Get the last value (without popping)
            # (could also be `Z` or `¹` for max_without_popping / first input respectively)
     -      # Subtract it from each item in the list
      IÖ    # Check for each if they're divisible by the second factorial-input
        Ï   # In the list we copied, only leave the values at the truthy indices
         P  # And take the product of those
            # (which is output implicitly as result)

1
Este 6 bytes: LR²ιнPPruébelo en línea! ) Funciona para todos los casos de prueba, excepto para 0.
Sr. Xcoder

Pero supongo que el caso 0 se puede arreglar en un máximo de 2 bytes. Si encuentra una manera de arreglarlo, puede tomarlo :) EDITAR: ¿ Quizás LR²ιн0KPpara 8 bytes?
Sr. Xcoder

@ Mr.Xcoder Buena respuesta! Nunca usé uninterleave con un paso dado. :)
Kevin Cruijssen

0Kdebería ser innecesario ya que 0!es una entrada no válida por la especificación (a pesar de que se ha incluido en los ejemplos) - He comentado sobre esto.
Jonathan Allan

1
... y si 0! está en el dominio de entrada ݦRXιнPguarda un byte.
Jonathan Allan

4

Código de máquina x86-64, 12 bytes

El mismo código de máquina hace lo mismo en modo de 32 bits, y para enteros de 16 bits en modo de 16 bits.

Se trata de una función, se puede llamar con argumentos n=RCX, k=ESI. Valor de retorno de 32 bits en EAX.

Se puede llamar desde C con la convención de llamadas del sistema V x86-64 con argumentos falsos para obtener los argumentos reales en los registros correctos. uint32_t factk(int, uint32_t k, int, uint64_t n); No podría simplemente usar Windows x64 porque los mulclobbers de 1 operando son RDX, y no queremos que los prefijos REX accedan a R8 / R9. nno debe tener basura en los 32 bits altos para que JRCXZ funcione, pero aparte de eso, todo es de 32 bits.

Listado NASM (dirección relativa, código de máquina, fuente)

 1                         factk:
 2 00000000 6A01             push 1
 3 00000002 58               pop rax             ; retval = 1
 4 00000003 E306             jrcxz  .n_zero      ; if (n==0) return
 5                         .loop:                ; do {
 6 00000005 F7E1              mul   ecx            ; retval *= n  (clobbering RDX)
 7 00000007 29F1              sub   ecx, esi       ; n -= k
 8 00000009 77FA              ja   .loop         ; }while(sub didn't wrap or give zero)
 9                         .n_zero:
10 0000000B C3               ret

0xc = 12 bytes


O 10 bytes si no necesitábamos manejar el n=0caso especial, dejando de lado el jrcxz.

Para el factorial estándar, usaría en looplugar de sub / ja para guardar 2 bytes, pero por lo demás exactamente el mismo código.


Llamada de prueba que pasa argccomo k, con ncodificación fija.

align 16
global _start
_start:
  mov  esi, [rsp]
;main:
  mov  ecx, 9
  call factk

  mov  esi, eax
  mov  edx, eax
  lea  rdi, [rel print_format]
  xor  eax, eax
extern printf
  call printf
extern exit
  call exit

section .rodata
print_format: db `%#x\t%u\n`

```

3

APL (Dyalog Unicode) , SBCS de 11 bytes

Función de infijo tácito anónimo. Toma ncomo argumento correcto y bcomo argumento izquierdo.

×/1⌈⊢,⊢-×∘⍳

Pruébalo en línea!

×∘⍳ se multiplican bpor los Ɩ ntegers 1 a travésn

⊢- restar eso de n

⊢, anteponer n

1⌈ máximo de uno y cada uno de esos

×/ producto



3

Wolfram Language (Mathematica) , 22 21 bytes

1##&@@Range[#,1,-#2]&

Pruébalo en línea!

-1 gracias a attinat: Times --> 1##&

Explicación: se usa Rangepara hacer una lista de los valores {n, n-k, n-2k, n-3k, ...}, deteniéndose antes de ir por debajo de 1 (es decir, deteniéndose justo). Luego, multiplique todos los números en esta lista con Times(o 1##&).


-1 byte con en 1##&lugar deTimes
attinat

3

Java 10, 44 bytes

f->b->{int r=1;for(;b>0;b-=f)r*=b;return r;}

Toma el factorial como primera entrada, la base como segunda.

Pruébalo en línea.

Esto anterior no funciona para el caso de prueba más grande debido al rango entero limitado (32 bits). Para solucionar esto podemos usar BigIntegers, que casualmente es exactamente el doble del tamaño - 88 79 bytes :

f->b->{var r=f.ONE;for(;b.signum()>0;b=b.subtract(f))r=r.multiply(b);return r;}

-9 bytes gracias a @ OlivierGrégoire .

Pruébalo en línea.

Explicación:

f->b->{       // Method with two integer parameters and integer return-type
  int r=1;    //  Result-integer, starting at 1
  for(;b>0;   //  Loop as long as the base is still larger than 0
      b-=f)   //    After every iteration: decrease the base by the factorial
    r*=b;     //   Multiply the result by the base
  return r;}  //  Return the result


@ OlivierGrégoire Np, y gracias! :)
Kevin Cruijssen



2

MathGolf , 7 6 bytes

╙╒x%ε*

Pruébalo en línea!

¡Encontré una manera inteligente de manejar 0! sin cambiar los otros casos de prueba. Toma la entrada como k n(orden inverso), lo que ayuda con el estallido implícito.

Explicación

╙        maximum of two elements (pops largest of k and n,
         which is n for every valid case except 0!, where 1 is pushed)
 ╒       range(1,n+1)
  x      reverse int/array/string
   %     slice every k:th element
    ε*   reduce list with multiplication

2

Agregado , 21 19 bytes

${x<y∨x*$[x-y,y]}

Pruébalo en línea! Implementación recursiva bastante directa. (Nota: truees esencialmente 1, ya que se puede usar en operaciones aritméticas como 1.) Este es uno de los pocos programas que he escrito para este sitio donde usar un operador unicode ahorra bytes (1, para ser precisos).

Alternativas

20 bytes: ${x<y or x*$[x-y,y]}

21 bytes: Prod@${{_%y=x%y}\1:x}

27 bytes: ${x*[`1,$][x>y][x-y,y]∨1}

27 bytes: ${If[x>y,x*$[x-y,y],_or 1]}

27 bytes: ${x*[`1,$][x>y][x-y,y]or 1}

29 bytes: ${If[x>y,x*$[x-y,y],_+not _]}


2

Óxido , 92 73 61 bytes

fn f(n:i128,k:i128)->i128{if n<=0{return 1}return n*f(n-k,k)}

Estoy empezando a aprender el óxido, así que estoy seguro de que esto puede ser más corto. Se actualizará a medida que aprendo. El valor de retorno debe ser i128para calcular la última prueba.

Editar: La recursión es más corta.

Pruébalo en línea!

Puede agregar su propia prueba o editar una de las ya existentes.


2

q , 59 57 55 53 bytes

{prd 2+(&)1_i=last i:("J"$x(&)not[n])#(!)sum n:"!"=x}

explicación:

q)x:"12!!" / let our input be 12!!, assign to x
q)sum n:"!"=x / count "!"s
2i
q)(!)sum n:"!"=x / (!)m -> [0,m)
0 1
q)("J"$x(&)not[n]) / isolate the number in input
12
q)("J"$x(&)not[n])#(!)sum n:"!"=x / x#y means take x items from list y, if x>y, circle around
0 1 0 1 0 1 0 1 0 1 0 1
q)i:("J"$x(&)not[n])#(!)sum n:"!"=x / assign to i
q)i
0 1 0 1 0 1 0 1 0 1 0 1
q)(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / take last elem of i and see which are equal in i
010101010101b
q)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / drop first elem
10101010101b
q)(&)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / indices of 1b (boolean TRUE)
0 2 4 6 8 10
q)2+(&)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / add 2 across array
2 4 6 8 10 12
q)prd 2+(&)1_(last i)=i:("J"$x(&)not[n])#(!)sum n:"!"=x / product across array
46080

aquí también hay una versión en k (misma lógica), 42 41 bytes

{*/2+&1_i=last i:("J"$x@&~:n)#!+/n:"!"=x}

Bienvenido al sitio! Agregué formato de código a su publicación, que se puede hacer con cuatro espacios antes de la línea o encerrándolo con triples tics.
Wheat Wizard

@ SriotchilismO'Zaic gracias :-)
garabato

1
Recomiendo agregar una explicación y tal vez un enlace a un intérprete en línea como TIO . Las respuestas de solo código generalmente se marcan automáticamente como de baja calidad.
mbomb007

@ mbomb007 interesante. ¿hay un bot marcando respuestas? ¿Qué pasa con los envíos de baja calidad? voy a actualizar pronto!
Garabato

Sí, hay un bot. StackExchange utiliza bots para buscar spam potencial y respuestas de baja calidad. Las personas con una reputación lo suficientemente alta pueden ver la Cola de revisión. meta.stackexchange.com/a/161391/285610
mbomb007


1

Retina , 66 bytes

^0
1
\d+
*!,
+`(!+)(!+),\1$
$1$2,$2,$1
!+$
1
+`(!+),(\d+)
$.($2*$1

Pruébalo en línea! El enlace incluye casos de prueba más rápidos. Mauls números sin signos de exclamación. Explicación:

^0
1

Arreglar 0!.

\d+
*!,

Convierte na unario y agrega un separador.

+`(!+)(!+),\1$
$1$2,$2,$1

Restar repetidamente kde nwhile n>ky recopilar los resultados.

!+$
1

Reemplazar kcon 1(en decimal).

+`(!+),(\d+)
$.($2*$1

Multiplica por cada valor intermedio a su vez, convirtiendo a decimal.




1

Adelante (gforth) , 50 bytes

: f 1 1 2over / 1+ 0 do 2over i * - 1 max * loop ;

Pruébalo en línea!

Explicación del código

: f                \ start a new word definition
  1 1              \ add placeholder and accumulator to stack
  2over / 1+       \ get the number of times to run the loop (num/factorial + 1)
  0 do             \ start loop from 0 to num/factorial
    2over          \ copy num and factorial to the top of the stack
    i * -          \ get the current number to multiply by (num - factorial * i)
    1 max          \ make sure it can't be 0 or negative [set to 1 if it is]
    *              \ multiply accumulator by result
  loop             \ end loop
;                  \ end the word definition           



1

Gaia , 6 bytes

…)¦v%Π

Pruébalo en línea!

Toma la entrada como n, kpor lo que la entrada de 3 4sería 3!!!!.

…	 push [0...n-1], or [] if n == 0
 )¦	 increment each value (does nothing if [])
   v	 reverse list
    %	 take every k'th element
     Π	 product; product([]) = 1.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.