Fatos adicionais!

17

Em matemática, o fatorial, encurtou o "fato" de um número inteiro não negativo n , denotado por n! , é o produto de todos os números inteiros positivos menores ou iguais a n . Por exemplo, 5! é 1 * 2 * 3 * 4 * 5 = 120

O fatorial de 0 é 1 , de acordo com a convenção para um produto vazio.


Esses são os fatos regulares a que estamos acostumados. Vamos adicionar algumas alternativas:

  1. O fatorial (definido acima)
  2. O fatorial duplo: n !! = 1 + 2 + ... + n
  3. O fatorial triplo: n !!! = 1 - (2 - (3 - (... - n))) ...)
  4. O fator quádruplo: n !!!! = 1 / (2 / (3 ... / n))) ...) . Nota: Esta é a divisão de ponto flutuante, não a divisão inteira.

Desafio

Tomar uma entrada de número inteiro não negativo n , directamente seguido por entre 1 e 4 exclamação marcas. A entrada será (exatamente) assim: 0! , 5 !! , 132 !!! ou 4 !!!! . Neste desafio, você não pode assumir um formato de entrada flexível, desculpe.

Resultado

A saída deve ser o resultado, em qualquer formato conveniente. O resultado do fatorial quádruplo deve ter pelo menos 2 dígitos após o ponto decimal, exceto 0 !!!! = 0 .

Casos de teste:

0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
---
0!! = 0
1!! = 1
2!! = 3
3!! = 6
4!! = 10
5!! = 15
6!! = 21
7!! = 28
8!! = 36
9!! = 45
10!! = 55
---
0!!! = 0
1!!! = 1
2!!! = -1
3!!! = 2
4!!! = -2
5!!! = 3
6!!! = -3
7!!! = 4
8!!! = -4
9!!! = 5
10!!! = -5
---
0!!!! = 0
1!!!! = 1
2!!!! = 0.5
3!!!! = 1.5
4!!!! = 0.375
5!!!! = 1.875
6!!!! = 0.3125
7!!!! = 2.1875
8!!!! = 0.27344
9!!!! = 2.4609
10!!!! = 0.24609

A solução mais curta em cada idioma vence.

Stewie Griffin
fonte
2
O fator quádruplo também pode ser uma divisão racional?
Martin Ender
6
"A dupla factorial" definição é um ajuste off ...
Erik o Outgolfer
4
@Erik, é um fato dupla alternativa ;-)
Stewie Griffin
11
@StewieGriffin BTW é um pouco sorrateiro que 0!-> 1.
Erik the Outgolfer
5
O título deve ser Fatos alternativos
Digital Trauma

Respostas:

7

JavaScript (ES6), 88 bytes

s=>eval(([a,b]=s.split(/\b/),g=k=>+a?k-a?k+'_*+-/'[b.length]+`(${g(k+1)})`:k:+!b[1])(1))

Casos de teste

Formatado e comentado

s =>                                // given the input string s,
  eval(                             // evaluate as JS code:
    ( [a, b] = s.split(/\b/),       //   a = integer (as string) / b = '!' string
      g = k =>                      //   g = recursive function taking k as input
        +a ?                        //     if a is not zero:
          k - a ?                   //       if k is not equal to a:
            k + '_*+-/'[b.length] + //         append k and the operation symbol
            `(${g(k + 1)})`         //         append the result of a recursive call
          :                         //       else:
            k                       //         just append k and stop recursion
        :                           //     else:
          +!b[1]                    //       return 1 for multiplication / 0 otherwise
    )(1)                            //   initial call to g() with k = 1
  )                                 // end of eval()
Arnauld
fonte
7

Casca , 15 bytes

§!ëΠΣF-F/#'!oṫi

Experimente online!

Explicação

Indexando em uma lista de funções: as alegrias de usar uma linguagem funcional.

§!ëΠΣF-F/#'!oṫi  Implicit input, say x = "6!!!"
              i  Convert to integer (parses the leading sequence of digits): 6
            oṫ   Descending range to 1: y = [6,5,4,3,2,1]
  ë              Four-element list containing the functions
   Π             product,
    Σ            sum,
     F-          left fold with subtraction (gives 0 for empty list), and
       F/        left fold with division (gives 0 for empty list).
 !               1-based index into this list with
         #'!     count of !-characters in input: gives F-
§                Apply to y and print implicitly: -3

Eu uso um intervalo descendente e dobras à esquerda, desde -e /tomo seus argumentos em ordem inversa no Husk.

Zgarb
fonte
Indexing into a list of functionsé woah ...
Erik the Outgolfer
Eu estava pensando em Haskell, e então eu vejo isso ... Realmente parece ser a ferramenta certa para o trabalho. 1
alleks 4/17/17
Isto é o que Husk foi feito para: D
Leo
6

C # (.NET Core) , 134 130 128 bytes

s=>{double e=s.Split('!').Length,n=int.Parse(s.Trim('!')),i=n,r=n;for(;--i>0;)r=e>4?i/r:e>3?i-r:e>2?i+r:i*r;return n<1&e<3?1:r;}

Experimente online!

A melhor parte do código de golfe são as coisas que você aprende ao tentar resolver os desafios. Neste, aprendi que, em C #, você pode aparar outros caracteres além dos espaços em branco das strings.

  • 4 bytes salvos graças ao LiefdeWen!
  • 2 bytes salvos porque não preciso subtrair 1 para s.Split('!').Length, basta fixar os limites em e>4?i/r:e>3?i-r:e>2?i+r:i*re n<1&e<3?1:r.
Charlie
fonte
11
Você pode criar e ne itambém doubleevitar declará-lo para r salvar 4 bytes.
precisa saber é o seguinte
11
@LiefdeWen Ou floatpara salvar outro byte.
Kevin Cruijssen 3/08
4

Perl 5 , 62 bytes

Código de 61 bytes + 1 para -p.

$_=/^0!$/+eval join(qw{| *( +( -( /(}[s/!//g],1..$_).")"x--$_

Obrigado à @GB por apontar uma falta da minha parte!

Experimente online! (isso usa -lpara facilitar a leitura)

Dom Hastings
fonte
4
0! deve ser 1 e não 0
GB
@ GB Bem, isso não faz sentido ... Corrigido para +5!
Dom Hastings
4

R , 113 111 bytes

function(s){z=strtoi((n=strsplit(s,'!')[[1]])[1])
n=length(n)
`if`(z,Reduce(c('*','+','-','/')[n],1:z,,T),n<2)}

Experimente alguns casos de teste!

ungolfed:

function(s){
  n <- strsplit(s,"!")[[1]]          # split on "!"
  z <- strtoi(n[1])                  # turn to integer
  n <- length(n)                     # count number of "!"
  FUN <- c(`*`,`+`,`-`,`/`)[[n]]     # select a function
  right <- TRUE                      # Reduce (fold) from the right
  if( z > 0)                         # if z > 0
    Reduce(FUN, 1:z,,right)          # return the value
  else    
    (n < 2)                          # 1 if n = 1, 0 if n > 1
}
Giuseppe
fonte
el(strsplit(s,"!")) salva 1 byte
bouncyball
4

Python3, 124 130 121 119 bytes

Neste ponto, acredito que a recursão é a chave para economizar ainda mais bytes.

s=input()
l=s.count('!')
v=int(s[:-l])+1
print(eval((" *+-/"[l]+"(").join(map(str,range(1,v)))+")"*(v-2)or"0")+(l<2>v))

Experimente os casos de teste em Experimente online!

-9 bytes graças a @ Mr.Xcoder !

-2 bytes graças a @Felipe Nardi Batista !

Yytsi
fonte
Falha para 6! . Deveria ser 720.
Sr. Xcoder
Atualizei o conjunto de testes Tio.
Xcoder
-3 bytes .
Xcoder
Ah, sim, claro, não percebi isso.
Sr. Xcoder 03/08/19
2
Behold ES6
Erik the Outgolfer
3

Pitão , 34 30 bytes

+uv++H@"/*+-"/Q\!G_tUK.vQKq"0!

Experimente online!

Explicação

+uv++H@"/*+-"/Q\!G_tUK.vQKq"0!"Q    Implicit: append "Q
                                    Implicit: read input to Q
                      .vQ           Evaluate Q as Pyth code. This evaluates the integer,
                                    any !'s are parsed as unary NOT for the next expression
                                    and discarded.
                     K              Save the result to K.
                    U               Get a list [0, 1, ..., K-1].
                   t                Drop the first item to get [1, 2, ..., K-1].
                  _                 Reverse to get [K-1, K-2, ..., 1].
 u                       K          Starting from G = K, for H in [K-1, K-2, ..., 1] do:
             /Q\!                     Count the !'s in Q.
      @"/*+-"                         Get the correct operator.
    +H                                Prepend the current H.
   +             G                    Append the previous value G.
  v                                   Evaluate as Python code.
                          q"0!"Q    See if Q == "0!".
+                                   If so, add 1.
PurkkaKoodari
fonte
Usar.U salva um byte.
Erik the Outgolfer
2

05AB1E , 27 bytes

þL"/*+-"¹'!¢©è".»"ì.VD_нi®Θ

Experimente online!

Erik, o Outgolfer
fonte
Você sabe por „.»que não funciona?
Riley
O @Riley »faz parte de uma sequência compactada inacabada; portanto, ocorre um erro e, como geralmente em 05AB1E, o erro é ignorado.
Erik the Outgolfer
Eu estava tentando fazer "*+-/"èUisso depois de usar o Lacompanhamento, .»Xmas ele trata Xcomo uma sequência, não como um comando e .»X.Vé ainda mais complicado.
Magic Octopus Urn
@MagicOctopusUrn Xnão avalia . X.Vsão dois comandos.
Erik the Outgolfer
@EriktheOutgolfer, sim, mas eu esperava que fosse avaliada antes de processar a dobra. Na esperança ., Não esperando :( podia jurar que havia um "usar cadeia de caracteres única como comando em cadeia dyadic" ou algo assim.
Magia Octopus Urna
2

Ruby , 83 80 79 bytes

->s{z=s.count ?!;s<?1?1+1<=>z:eval([*1..w=s.to_i]*(".0"+"_*+-/"[z]+?()+?)*~-w)}

Experimente online!

Explicação:

->s{
    # Get number of !
    z=s.count ?!

    # Special case: if the number is 0, then output 0 or 1 depending on z
    s<?1?1+1<=>z:

    # Otherwise build the full expression as a string and then evaluate it
    eval([*1..w=s.to_i]*(".0"+"_*+-/"[z]+?()+?)*~-w)
}
GB
fonte
2

Java 8, 141 136 134 bytes

s->{float q=s.split("!",-1).length,n=new Float(s.split("!")[0]),i=n,r=n;for(;--i>0;r=q<3?i*r:q<4?i+r:q<5?i-r:i/r);return n<1&q<3?1:r;}

-5 bytes (141 → 136) graças a @CarlosAlejo C # de .

Explicação:

Experimente aqui.

s->{                                // Method with String parameter and float return-type
  float q=s.split("!",-1).length,   //  Amount of exclamation marks + 1
        n=new Float(s.split("!")[0]),
                                    //  The number before the exclamation marks
        i=n,                        //  Index (starting at `n`)
        r=n;                        //  Return sum (starting at `n`)
  for(;--i>0;                       //  Loop from `i-1` down to 1
    r=                              //   Change the result (`r`) to:
      q<3?                          //    If `q` is 2:
       i*r                          //     Multiply
      :q<4?                         //    Else if `q` is 3:
       i+r                          //     Addition
      :q<5?                         //    Else if `q` is 4:
       i-r                          //     Subtraction
      :                             //    Else (if `q` is 5):
       i/r                          //     Division
  );                                //  End of loop
  return n<1&q<3?                   //  Edge case if the input is `0!`:
          1                         //   Then return 1
         :                          //  Else:
          r;                        //   Return the result
}                                   // End of method
Kevin Cruijssen
fonte
11
Eu já vi uma resposta semelhante em outro lugar ...: -DI continuo esquecendo que floaté mais curto que double.
Charlie
@CarlosAlejo Sim, eu notei sua resposta depois da minha resposta inicial de 141 bytes. Mudar float q=s.length()-(s=s.replace("!","")).length(),n=new Float(s)para a resposta atual me salvou em 5 bytes. :) Esqueci de adicionar uma parte " bytes salvos graças a " notei agora .. Desculpe por isso.
Kevin Cruijssen
oh, deixa pra lá, fico feliz que você tenha gostado da minha resposta. :-) #
Charlie
2

Jelly ,  24 23 26  25 bytes

+  3  2 bytes corrigidos para correção após má interpretação :(

×
+
_
÷
ṣ”!µḢVRṚȯL©Ị$®ŀ@/

Um programa completo (um link monádico com links auxiliares referenciados pelo local do programa)

Experimente online! ou veja uma suíte de testes .

Quão?

× - Link 1, multiply: number, number

+ - Link 2, add: number, number

_ - Link 1, subtract: number, number

÷ - Link 1, divide: number, number

ṣ”!µḢVRṚȯL©Ị$®ŀ@/ - Main link: list of characters, a
ṣ”!               - split s at '!' characters
   µ              - monadic separation, call that b
    Ḣ             - head - pop and yield the digit list from b, modifying b
     V            - evaluate as Jelly code (get the number, say N)
      R           - range = [1,2,3,...,N]
       Ṛ          - reverse = [N,...,3,2,1]
            $     - last two links as a monad:
         L        -   length of modified b (number of '!' characters)
          ©       -   (copy to register)
           Ị      -   insignificant? (1 when just one '!', 0 when two or more)
        ȯ         - logical or (1 for "0!", 0 for "0!!...", the reversed-range otherwise)
                / - cumulative reduce by:
               @  -  with swapped arguments:
              ŀ   -    dyadic call of link at index:
             ®    -      recall value from register (number of '!' characters)
Jonathan Allan
fonte
Falha em 0!.
Erik the Outgolfer
Ah, haha ​​- eu tinha lido seu comentário errado no OP - eu pensei que eles tinham feito 0! definido como 0, o que estaria errado.
Jonathan Allan
Tudo pronto agora :)
Jonathan Allan
Pena que o TIO está quebrado no momento, para que eu não possa testar se ainda é inválido. :(: P Também muito ruim que você não pode usar /. Em uma lista vazia D: EDIT: Aparentemente válida para 0!, 0!!, 0!!!e 0!!!!+1.
Erik o Outgolfer
2

Código de máquina x86_64 auto-modificável, 123 bytes

0f b6 0f 31 c0 eb 11 0f be c9 8d 04 80 8d 44 41 d0 0f b6 4f 01 48 ff c7 83 f9 21 75 ea b9 21 21 21 a1 33 0f 0f bc c9 81 c1 ff 07 00 00 c1 e9 03 0f b6 c9 89 ca 09 c2 74 35 55 48 89 e5 c7 45 fc 59 58 5c 5e 8a 4c 0d fc 88 0d 15 00 00 00 f3 0f 2a c8 83 f8 02 5d 7c 1f ff c8 0f 57 c0 f3 0f 2a c0 f3 0f 5e c1 83 f8 01 0f 28 c8 7f eb c3 f3 0f 10 05 03 01 00 00 c3 0f 28 c1 c3

Por que linguagens interpretadas seriam capazes de executar código dinamicamente com evals sofisticados , mas não com código de máquina simples?

Experimente com:

#include <stdio.h>
#include <sys/mman.h>
#include <errno.h>

char ff[] = "\x0f\xb6\x0f\x31\xc0\xeb\x11\x0f\xbe\xc9\x8d\x04\x80\x8d\x44\x41\xd0\x0f\xb6\x4f\x01\x48\xff\xc7\x83\xf9\x21\x75\xea\xb9\x21\x21\x21\xa1\x33\x0f\x0f\xbc\xc9\x81\xc1\xff\x07\x00\x00\xc1\xe9\x03\x0f\xb6\xc9\x89\xca\x09\xc2\x74\x35\x55\x48\x89\xe5\xc7\x45\xfc\x59\x58\x5c\x5e\x8a\x4c\x0d\xfc\x88\x0d\x15\x00\x00\x00\xf3\x0f\x2a\xc8\x83\xf8\x02\x5d\x7c\x1f\xff\xc8\x0f\x57\xc0\xf3\x0f\x2a\xc0\xf3\x0f\x5e\xc1\x83\xf8\x01\x0f\x28\xc8\x7f\xeb\xc3\xf3\x0f\x10\x05\x03\x01\x00\x00\xc3\x0f\x28\xc1\xc3";
int main()
{
    char* page = (char*)((unsigned long)((char*)ff) & (~0xfffLL));
    if (mprotect(page, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC) < 0) {
        perror("mprotect");
        return -1;
    }
    float (*f)(char*) = (float (*)(char*))ff;
    char* testcases[] = { "0!","1!","2!","3!","4!","5!","6!","7!","8!","9!","10!",
                          "0!!","1!!","2!!","3!!","4!!","5!!","6!!","7!!","8!!","9!!","10!!",
                          "0!!!","1!!!","2!!!","3!!!","4!!!","5!!!","6!!!","7!!!","8!!!","9!!!","10!!!",
                          "0!!!!","1!!!!","2!!!!","3!!!!","4!!!!","5!!!!","6!!!!","7!!!!","8!!!!","9!!!!","10!!!!",
                        };
    for (int i = 0; i < 44; i++) {
        printf("%s -> %f\n", testcases[i], f(testcases[i]));
    }
}

Montagem:

_f:
100000d4f:  0f b6 0f    movzx   ecx, byte ptr [rdi]
100000d52:  31 c0   xor eax, eax
100000d54:  eb 11   jmp 17 <_f+18>
100000d56:  0f be c9    movsx   ecx, cl
100000d59:  8d 04 80    lea eax, [rax + 4*rax]
100000d5c:  8d 44 41 d0     lea eax, [rcx + 2*rax - 48]
100000d60:  0f b6 4f 01     movzx   ecx, byte ptr [rdi + 1]
100000d64:  48 ff c7    inc rdi
100000d67:  83 f9 21    cmp ecx, 33
100000d6a:  75 ea   jne -22 <_f+7>
100000d6c:  b9 21 21 21 a1  mov ecx, 2703302945
100000d71:  33 0f   xor ecx, dword ptr [rdi]
100000d73:  0f bc c9    bsf ecx, ecx
100000d76:  81 c1 ff 07 00 00   add ecx, 2047
100000d7c:  c1 e9 03    shr ecx, 3
100000d7f:  0f b6 c9    movzx   ecx, cl
100000d82:  89 ca   mov edx, ecx
100000d84:  09 c2   or  edx, eax
100000d86:  74 35   je  53 <_f+6E>
100000d88:  55  push    rbp
100000d89:  48 89 e5    mov rbp, rsp
100000d8c:  c7 45 fc 59 58 5c 5e    mov dword ptr [rbp - 4], 1583110233
100000d93:  8a 4c 0d fc     mov cl, byte ptr [rbp + rcx - 4]
100000d97:  88 0d 15 00 00 00   mov byte ptr [rip + 21], cl
100000d9d:  f3 0f 2a c8     cvtsi2ss    xmm1, eax
100000da1:  83 f8 02    cmp eax, 2
100000da4:  5d  pop rbp
100000da5:  7c 1f   jl  31 <_f+77>
100000da7:  ff c8   dec eax
100000da9:  0f 57 c0    xorps   xmm0, xmm0
100000dac:  f3 0f 2a c0     cvtsi2ss    xmm0, eax
100000db0:  f3 0f 5e c1     divss   xmm0, xmm1
100000db4:  83 f8 01    cmp eax, 1
100000db7:  0f 28 c8    movaps  xmm1, xmm0
100000dba:  7f eb   jg  -21 <_f+58>
100000dbc:  c3  ret
100000dbd:  f3 0f 10 05 03 01 00 00     movss   xmm0, dword ptr [rip + 259]
100000dc5:  c3  ret
100000dc6:  0f 28 c1    movaps  xmm0, xmm1
100000dc9:  c3  ret

As explicações serão adicionadas mais tarde. A idéia básica é a de modificar a divss xmm0, xmm1instrução em 0x100000db0e substituí-lo com um mulss, addss, subssou divssde acordo com o operando fornecido. Um pequeno truque também é usado para analisar a sequência de entrada.

Montagem gerada com:

float f (char* s)
{
    int x;
    for (x=0; *s != '!'; s++) {
        x=10*x + (*s-'0');
    }
    unsigned char op = (__builtin_ctz(*(unsigned int *)s ^ 0xa1212121)-1) >> 3;
    if (x == 0 && op == 0) {
        return 1;
    }
    unsigned int lookup = 0x5e5c5859;
    unsigned char new_code = ((unsigned char*)&lookup)[op];
    asm("movb %0, 0x15(%%rip)" : : "r" (new_code));
    float sum;
    for (sum = x--; x>0; x--) {
        sum = x / sum;
    }
    return sum;
}
yoann
fonte
2

Haskell, 105 102 98 96 bytes

0!3=0
x!y=foldr([(*),(+),(-),(/)]!!y)([1,0,0,1]!!y)[1..x]
f s|[(n,b)]<-lex s=read n!(length b-1)

Economizou 9 bytes graças ao Zgarb e nimi.

Experimente online.

Cristian Lupascu
fonte
@ Zgarb Você está certo. Fixo.
Cristian Lupascu
Eu acho que você também pode ignorar as diferenças read ne f=é desnecessário de acordo com nossas regras .
Zgarb 3/17/17
@ Zgarb Certo novamente :). Obrigado!
Cristian Lupascu
De voltar para uma função chamada e usando lexsalva dois bytes: f s|[(n,b)]<-lex s=read n!(length b-1).
nimi
@nimi Uau, obrigado! Sou tão novo em Haskell que nem conhecia lex. Fantástico! :) Mas não vejo como isso salva bytes - recebo 99 bytes depois disso.
Cristian Lupascu
1

Gaia , 26 25 bytes

ẋ)@d┅v;l“×+⁻÷”=“ₔ⊢”+e¤ḥ!∨

Experimente online!

Explicação

ẋ                          Split the input into runs of the same character.
 )                         Get the last one (the !'s).
  @                        Push an input (since there's none left, use the last one).
   d                       Parse as number (ignores the !'s).
    ┅v                     Get the reverse range: [n .. 1]
      ;                    Copy the ! string
       l“×+⁻÷”=            Get its length and index into this string of operators.
               “ₔ⊢”+       Append 'ₔ⊢' to the operator.
                    e      Eval the resulting string, which is "reduce by <operator> with
                            swapped arguments." Reducing an empty list gives 0.
                     ¤     Bring the !'s back to the top.
                      ḥ!   Remove the first character and check if it's empty.
                        ∨  Logical OR; turns 0 from 0! to 1, doesn't change anything else.
Gato de negócios
fonte
1

Gelatina , 28 bytes

×
+
_
÷
³ċ”!
ḟ”!VRṚ¢ŀ@/¢Ị¤¹?

Experimente online!

Tive a idéia de separar os links em linhas da resposta de Jonathan Allan para -2 bytes.

Erik, o Outgolfer
fonte
1

APL (Dyalog) , 30 bytes

Inspirado na solução da lstefano .

{0::0⋄(⍎'×+-⌹'⊃⍨≢⍵~⎕D)/⍳⍎⍵∩⎕D}

Experimente online!

{} Função anônima em que o argumento é representado por :

0:: se ocorrer algum erro:

  0 retornar zero

 agora tente:

  ⍵∩⎕D a interseção do argumento e o conjunto de D igits (remove pontos de exclamação)

   execute isso (transforma em número)

  índices disso

  ()/ Insira (APL é associativo corretamente, conforme necessário) a seguinte função entre termos:

   ⍵~⎕D argumento sem D igits (deixa pontos de exclamação)

   registro que (ou seja, quantos pontos de exclamação)

  '×+-⌹'⊃⍨ use isso para escolher na lista de símbolos *

   execute (transforma o símbolo em uma função)


(divisão da matriz) é usada em vez de ÷(divisão normal) para causar um erro em uma lista vazia

Adão
fonte
O que ::faz em um dfn?
Zacharý 4/08/2017
É uma proteção contra erros . Se em algum momento após a proteção contra erros for configurada, ::ocorrerá um erro com qualquer um dos números (0 = 1 a 999, 1000 = 1001 ...) à esquerda do resultado , e o valor à direita da ::é retornado imediatamente.
Adám 5/08/17
Bem, eu nunca soube disso, obrigado!
Zacharý 5/08/19
0

Perl 5 , 96 bytes

s/(\d+)//;@a=1..$1;$"=qw|* + -( /(|[$l=-1+length];$_=$1?"@a".($l>1?')'x($1-1):''):$l?0:1;$_=eval

Experimente online!

Xcali
fonte
0

Dyalog APL, pelo menos 29 caracteres

{(⍎i⊃'×+-÷')/⍳⍎⍵↓⍨-i←+/'!'=⍵}

A expressão está QUASE correta. Ele passa em todos os casos de teste, EXCETO 0!!!!para os quais é fornecido, em 1vez do necessário, 0e isso ocorre porque na APL a redução de um vetor vazio deve retornar o elemento neutro para a função usada para reduzir. Para o quociente que é 1. No momento, não tenho tempo para tentar consertá-lo, mas deixarei aqui por um dia chuvoso.

lstefano
fonte
Está chovendo: {0::0⋄(⍎'×+-⌹'⊃⍨≢⍵~⎕D)/⍳⍎⍵∩⎕D} Experimente online!
Adám 03/08/19
Muito legal! Não me importo se você a reivindicar como sua solução, já que as diferenças são mais do que as semelhanças.
Lstefano
Feito.
Adám 04/08/19
0

Mathematica, 152 bytes

(T=ToExpression;If[#=="0!!!!",0,s=T@StringCount[#,"!"];t=T@StringDrop[#,-s];{#!,i~Sum~{i,#},Sum[-i(-1)^i,{i,#}],N@Product[1/i^(-1)^i,{i,#}]}[[s]]&[t]])&
J42161217
fonte
0

Javascript, 111 163 bytes

s=>([a,b]=s.split(/\b/),c=b.length,a==0&c==1||eval((p=[...Array(+a+1).keys()].slice(1).join(c-1?c-2?c-3?'/(':'-(':'+':'*'))+')'.repeat((p.match(/\(/g)||[]).length)))

Versão legível

s=>([a,b]=s.split(/\b/),c=b.length,a==0&c==1||eval((p=
[...Array(+a+1).keys()].slice(1).join(c-1?c-2?c-3?'/(':'-
(':'+':'*'))+')'.repeat((p.match(/\(/g)||[]).length)))
SuperStormer
fonte