literais numéricos do mathpack

10

prefácio

Em uma situação muito quente, você tem que ir ainda mais longe com o golfe.
(por exemplo, em um desafio em que sua resposta tem 100 caracteres e é embaraçoso que você não consiga fazê-lo 99)
Nesse caso, a partir de agora você usa o algoritmo do vencedor desse desafio :)

objetivo

Você precisa escrever um programa que use um uint32 e retorne a forma mais compactada.

$ mathpack 147456
9<<14
  • Haverá várias soluções para um número. Escolha o menor
  • Se o formato compactado for maior ou igual ao número original, retorne o número original

regras

  • escrever em qualquer idioma - saída em qualquer idioma
  • Estou ciente de que em C 'abc'é 6382179e você pode conseguir bons resultados bonitas com esta conversão. mas os idiomas estão separados nesse desafio, então não desanime
  • é proibido usar variáveis ​​externas. somente operadores e literais e funções matemáticas!

pontuação

aqui estão os casos de teste: pastebin.com/0bYPzUhX
sua pontuação (por cento) será a proporção
byte_size_of_your_output / byte_size_of_the_list sem quebras de linha .
(você tem que fazer isso sozinho, pois apenas verificarei os melhores códigos). Os
vencedores serão escolhidos por pontuação e idioma de saída !

exemplos:

$ mathpack 147456 | mathpack 97787584 |  mathpack 387420489
            9<<14 |           9e7^9e6 |            pow(9,9)
bebe
fonte
Desafio adorável, mas você deve adicionar uma regra contra a codificação rígida.
ɐɔıʇǝɥʇuʎs
Você quer dizer casos codificados de 10k? embora eu ficaria feliz em conseguir algum apoio sobre como refinar este desafio
bebe
editado (várias vezes ...) para maior clareza. obrigado pelos conselhos.
07714 bebe
Isso também não seria [pedra de roseta]? Além disso: write in any language - output in any language- os dois idiomas podem ser diferentes, certo?
ɐɔıʇǝɥʇuʎs
@ [ıʇǝɥʇuʎs [pedra de roseta] é sobre você resolvê-lo no maior número possível de idiomas. E sim à sua última pergunta - que foi editada em resposta a mim, fazendo a mesma pergunta.
Martin Ender

Respostas:

1

Código: Mathematica, Saída: C, ~ 62.1518% (12674/20392)

Eu pensei em dar uma chance a C por causa desses literais engraçados. Atualmente, esta é a única coisa que esta resposta está tentando e está funcionando muito bem.

mathpack[n_] := Module[{versions, charLiteral},
   charLiteral = "'" <> StringReplace[Map[
        Switch[#,
          (*d_ /; d < 32,
          "\\" <> IntegerString[#, 8],*)
          10,
          "\\n",
          13,
          "\\r"
          39,
          "\\'",
          92 ,
          "\\\\",
          _,
          FromCharacterCode@#] &,
        FromDigits[#, 
           2] & /@ (Partition[PadLeft[IntegerDigits[n, 2], 32], 
            8] //. {{0 ..} .., x__} :> {x})
        ] <> "",
      {(*"\\10" -> "\\b",
       "\\11" -> "\\t",
       "\\13" -> "\\v",
       "\\14" -> "\\f",*)
       RegularExpression["(?!<=\?)\?\?(?=[=/()!<>-]|$)"] -> "?\\?"
       }
      ] <> "'";
   versions = {ToString@n, charLiteral};
   SortBy[versions, StringLength][[1]]
 ];

Espero não ter perdido nada, mas essa resposta evita barras invertidas, aspas simples e trigramas. Existe algum código comentado que usa sequências de octal ou outras seqüências de escape para caracteres não imprimíveis, mas não acho que seja realmente necessário, porque C deve ser capaz de lidar com quaisquer bytes nos literais de caracteres, afaik (corrija-me se eu 'Estou errado).

Como na outra submissão, teste isso com

input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
Martin Ender
fonte
(Pelo menos no meu sistema), o GCC aceitará qualquer byte entre aspas simples, exceto 10 ( \n) e 13 ( \r). Um byte zero compilará OK, mas com a mensagem de erro warning: null character(s) preserved in literal.
R3mainer
@squeamishossifrage Obrigado, corrigido!
Martin Ender
3

Código: Mathematica, Saída: Julia, ~ 98.9457% (20177/20392 bytes)

optimise[n_] := 
  Module[{bits, trimmedBits, shift, unshifted, nString, versions, 
    inverted, factorised, digits, trimmedDigits, exponent, base, 
    xored, ored, anded},
   nString = ToString@n;
   versions = {nString};

   (* Try bitshifting *)
   bits = IntegerDigits[n, 2];
   trimmedBits = bits /. {x___, 1, 0 ..} :> {x, 1};
   shift = ToString[Length[bits] - Length[trimmedBits]];
   unshifted = ToString@FromDigits[trimmedBits, 2];
   AppendTo[versions, unshifted <> "<<" <> shift];

   (* Try inverting *)
   inverted = ToString@FromDigits[1 - PadLeft[bits, 32], 2];
   AppendTo[versions, "~" <> inverted];

   (* Try invert/shift/invert *)
   trimmedBits = bits /. {x___, 0, 1 ..} :> {x, 1};
   shift = ToString[Length[bits] - Length[trimmedBits]];
   unshifted = ToString@FromDigits[trimmedBits, 2];
   AppendTo[versions, "~(~" <> unshifted <> "<<" <> shift <> ")"];

   (* Try factoring *)
   factorised = Riffle[
      FactorInteger[n]
        /. {a_, 1} :> ToString@a
       /. {a_Integer, b_Integer} :> ToString[a] <> "^" <> ToString[b]
      , "+"] <> "";
   AppendTo[versions, factorised];

   (* Try scientific notation *)
   digits = IntegerDigits[n, 10];
   trimmedDigits = digits /. {x___, d_ /; d > 0, 0 ..} :> {x, d};
   exponent = ToString[Length[digits] - Length[trimmedDigits]];
   base = ToString@FromDigits[trimmedDigits, 10];
   AppendTo[versions, base <> "e" <> exponent];

   (* Don't try hexadecimal notation. It's never shorter for 32-bit uints. *)
   (* Don't try base-36 or base-62, because parsing those requires 12 characters for
      parseint("...") *)

   SortBy[versions, StringLength][[1]]
  ];

mathpack[n_] := 
 Module[{versions, increments},
  increments = Range@9;
  versions = Join[
    optimise[#2] <> "+" <> ToString@# & @@@ ({#, n - #} &) /@ 
      Reverse@increments,
    {optimise@n},
    optimise[#2] <> "-" <> ToString@# & @@@ ({#, n + #} &) /@ 
      increments,
    optimise[#2] <> "*" <> ToString@# & @@@ 
      Cases[({#, n / #} &) /@ increments, {_, _Integer}],
    optimise[#2] <> "/" <> ToString@# & @@@ ({#, n * #} &) /@ 
      increments
    ];
  SortBy[versions, StringLength][[1]]
 ];

A função pega um número e retorna a menor string que encontra. Atualmente, ele aplica quatro otimizações simples (devo acrescentar mais amanhã).

Você pode aplicá-lo ao arquivo inteiro (para medir sua pontuação) da seguinte maneira:

input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]

Observe que algumas dessas otimizações pressupõem que você esteja em uma Julia de 64 bits, de modo que literais inteiros fornecem um int64por padrão. Caso contrário, você estará transbordando de qualquer maneira para números inteiros maiores que 2 31 . Usando essa suposição, podemos aplicar algumas otimizações cujas etapas intermediárias são realmente ainda maiores que 2 32 .

EDIT: Eu adicionei a otimização sugerida nos exemplos do OP para x ou dois grandes números em notação científica (na verdade, para todos os xor , ou e e ). Nota que o alargamento do xormap, ormape andmappara incluir operando além do 2 32 poderia ajudar a encontrar otimizações adicionais, mas ele não funciona para os casos de teste dadas e só aumenta o tempo de execução por algo como um fator de 10.

EDIT: eu raspei fora outros 16 bytes, verificando tudo n-9, n-8, ..., n+8, n+9para se qualquer um daqueles pode ser reduzido, caso em que eu representava o número com base nisso, adicionando ou subtraindo a diferença. Existem alguns casos em que um desses 18 números pode ser representado com 3 ou mais caracteres a menos que nele próprio; nesse caso, posso fazer uma economia extra. Agora são necessários cerca de 30 segundos para executá-lo em todos os casos de teste, mas é claro que, se alguém realmente "utilizasse" essa função, ele a executaria apenas em um único número, por isso ainda está bem em menos de um segundo.

EDIT: Outros incríveis 4 bytes, fazendo o mesmo para multiplicação e divisão. Agora estão 50 segundos (os divididos não demoram tanto, porque só estou verificando se o número é realmente divisível pelo fator de interesse).

EDIT: Outra otimização que realmente não ajuda com o conjunto de testes fornecido. Este poderia salvar um byte para coisas como 2 30 ou 2 31 . Se tivéssemos uint64s, haveria muitos números em que isso seria uma grande economia (basicamente, sempre que a representação de bits terminar em 1s).

EDIT: Removido o xor , ou , e otimizações por completo. Acabei de notar que eles nem sequer funcionam em Julia, porque (obviamente) a notação científica oferece uma flutuação em que os operadores pouco inteligentes nem são definidos. Curiosamente, uma ou mais das otimizações mais recentes parecem capturar todos os casos que foram encurtados por essas otimizações, porque a pontuação não mudou.

Martin Ender
fonte
1

J a C (não testado, mas funciona na maioria dos casos, tipo de resposta de linha de base).

    f=:(,~ (($&0) @: (8&-) @: (8&|) @: #)) @: #:
    g=:($~ ((,&8) @: (%&8) @: #))@:f
    toCString=:({&a.)@:#.@:g
    toCString 6382179
abc    

Produz uma string literal que, se inserida em C, representa o número (conforme mencionado no OP). Esta não é uma submissão séria, mas algo para fortalecer minhas habilidades em J, que pensei em compartilhar.

Linha única alternativa:

toCString=:({&a.) @: #. @: ($~ ((,&8) @: (%&8) @: #))@: (,~ (($&0) @: (8&-) @: (8&|) @: #)) @: #:

O que J tenta fazer disso quando você o insere:

{&a.@:#.@:($~ ,&8@:(%&8)@:#)@:(,~ $&0@:(8&-)@:(8&|)@:#)@:#:

Muito obrigado, J. Além disso, para aqueles que conhecem o J, o visio é ótimo por criar funções mais complexas:

insira a descrição da imagem aqui

ɐɔıʇǝɥʇuʎs
fonte
Como não consigo ler nada: o que isso faz se o caractere não for imprimível, ou se for \ , ?ou '?
Martin Ender
@ m.buettner Nada (ainda), eu ainda tenho que construir algo para que
ɐɔıʇǝɥʇuʎs
Em vez de m&u@:v, use m u vpara salvar caracteres preciosos e melhorar a legibilidade. Aplicando isso ao seu código, temos f =: [: (,~ 0 $~ 8 - 8 | #) #:e g =: [: ($~ 8 ,~ # % 8:) fpor último toCString =: a. {~ [: #. g. Tudo combinado a. {~ [: #. [: ($~ 8 ,~ # % 8:) [: (,~ 0 $~ 8 - 8 | #) #:, o que é realmente fácil de ler.
FUZxxl 14/03/2015