literales numéricos de mathpack

10

prefacio

En una situación muy calurosa, tienes que ir aún más lejos con el golf.
(por ejemplo, en un desafío en el que su respuesta tiene 100 caracteres de longitud y es vergonzoso que no haya podido hacerlo 99)
En ese caso, a partir de ahora utilizará el algoritmo del ganador de este desafío :)

objetivo

Debe escribir un programa que tome un uint32 y devuelva la forma más comprimida.

$ mathpack 147456
9<<14
  • Habrá múltiples soluciones para un número. Elige el más corto
  • Si la forma comprimida es más larga o igual al número original, devuelva el número original

reglas

  • escribir en cualquier idioma - salida en cualquier idioma
  • Soy consciente de que en C 'abc'está 6382179y puede lograr resultados bastante buenos con esta conversión. pero los idiomas están separados en este desafío, así que no se desanime
  • Está prohibido utilizar variables externas. solo operadores y literales y funciones relacionadas con las matemáticas!

puntuación

Estos son los casos de prueba: pastebin.com/0bYPzUhX
su puntaje (porcentaje) será la proporción de
byte_size_of_your_output / byte_size_of_the_list sin saltos de línea .
(debe hacerlo usted mismo, ya que verifico los mejores códigos por si acaso) ¡los
ganadores serán elegidos por puntaje e idioma de salida !

ejemplos:

$ mathpack 147456 | mathpack 97787584 |  mathpack 387420489
            9<<14 |           9e7^9e6 |            pow(9,9)
bebe
fuente
Hermoso desafío, pero debes agregar una regla contra la codificación rígida.
7ıʇǝɥʇuʎs
¿Te refieres a codificar cajas de 10k? aunque yo estaría encantado de conseguir un poco de ayuda sobre cómo perfeccionar este desafío
bebe
editado (una y otra vez ...) para mayor claridad. Gracias por los consejos.
bebe
¿No sería esto también [rosetta-stone]? Además: write in any language - output in any language- los dos idiomas pueden ser diferentes, ¿verdad?
Julıʇǝɥʇuʎs
@ ɐɔıʇǝɥʇuʎs [Rosetta piedra] es realmente acerca de que resolverlo en tantos idiomas como sea posible. Y sí a su última pregunta, que ha sido editada en respuesta a mí haciendo esa misma pregunta.
Martin Ender

Respuestas:

1

Código: Mathematica, Salida: C, ~ 62.1518% (12674/20392)

Pensé que también le daría una oportunidad a C debido a esos divertidos literales de personajes. Actualmente, esto es lo único que intenta esta respuesta, y está funcionando bastante bien.

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 no haberme perdido nada, pero esta respuesta se asegura de evitar las barras diagonales inversas, las comillas simples y los trigrafos. Hay un código comentado que utiliza secuencias de escape octales u otras para caracteres no imprimibles, pero no creo que sea realmente necesario, porque C debería ser capaz de manejar cualquier byte en literales de caracteres, afaik (corríjame si yo 'Estoy mal).

Al igual que con la otra presentación, pruebe esto con

input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
Martin Ender
fuente
(Al menos en mi sistema) GCC aceptará cualquier byte entre comillas simples, excepto 10 ( \n) y 13 ( \r). Un byte cero compilará bien, pero con el mensaje de error warning: null character(s) preserved in literal.
r3mainer
@squeamishossifrage Gracias, arreglado!
Martin Ender
3

Código: Mathematica, Salida: 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]]
 ];

La función toma un número y devuelve la cadena más corta que encuentra. Actualmente aplica cuatro optimizaciones simples (podría agregar más mañana).

Puede aplicarlo a todo el archivo (para medir su puntaje) de la siguiente manera:

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

Tenga en cuenta que algunas de estas optimizaciones suponen que está en una Julia de 64 bits, de modo que los literales enteros le dan un int64valor predeterminado. De lo contrario, se desbordará de todos modos para enteros mayores que 2 31 . Usando esa suposición, podemos aplicar algunas optimizaciones cuyos pasos intermedios son incluso mayores que 2 32 .

EDITAR: agregué la optimización sugerida en los ejemplos de OP para bit xor dos grandes números en notación científica (en realidad, para todos xor , o y y ). Tenga en cuenta que la ampliación de la xormap, ormapy andmappara incluir más allá de operandos 2 32 podría ayudar a encontrar optimizaciones adicionales, pero no funciona para los casos de prueba dado y sólo aumenta el tiempo de funcionamiento por algo así como un factor de 10.

EDITAR: eliminé otros 16 bytes, comprobando n-9, n-8, ..., n+8, n+9si alguno de ellos se puede acortar, en cuyo caso representé el número basado en eso, sumando o restando la diferencia. Hay algunos casos en los que uno de esos 18 números se puede representar con 3 o más caracteres menos que él nmismo, en cuyo caso puedo hacer algunos ahorros adicionales. Tarda unos 30 segundos en ejecutarse en todos los casos de prueba, pero, por supuesto, si alguien realmente "utilizara" esta función, solo la ejecutaría en un solo número, por lo que aún está por debajo de un segundo.

EDITAR: Otros 4 bytes increíbles haciendo lo mismo para multiplicación y división. 50 segundos ahora (los divididos no tardan tanto, porque solo los estoy verificando si el número es realmente divisible por el factor de interés).

EDITAR: Otra optimización que en realidad no ayuda con el conjunto de pruebas dado. Este podría ahorrar un byte para cosas como 2 30 o 2 31 . Si tuviéramos uint64s en su lugar, habría muchos números en los que esto podría ser un gran ahorro (básicamente, cada vez que la representación de bits termina en muchos 1s).

EDITAR: Se eliminó el xor , o , y las optimizaciones por completo. Acabo de darme cuenta de que ni siquiera funcionan en Julia, porque (obviamente) la notación científica le da un flotante donde los operadores de bits no están definidos. Curiosamente, una o más de las optimizaciones más nuevas parecen captar todos los casos que fueron acortados por estas optimizaciones, porque el puntaje no cambió en absoluto.

Martin Ender
fuente
1

J a C (no probado, pero funciona en la mayoría de los casos, una especie de respuesta de referencia).

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

Emite un literal de cadena que, si se ingresa en C, representa el número (como se menciona en el OP). Esta no es una presentación seria, sino algo para fortalecer mis habilidades de J, que pensé que compartiría.

Una línea alternativa:

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

Lo que J intenta hacer con esto cuando lo ingresas:

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

Muchas gracias, J. Además, para los que están en 'el saber' sobre J, visio rocas para crear funciones más complejas:

ingrese la descripción de la imagen aquí

ɐɔıʇǝɥʇuʎs
fuente
Ya que no puedo leer nada de eso: ¿qué hace esto si el personaje es no imprimible, o si el personaje es \ , ?o '?
Martin Ender
@ m.buettner Nada (todavía), todavía tengo que construir algo para eso
8ıʇǝɥʇuʎs
En lugar de m&u@:v, úsalo m u vpara guardar personajes preciosos y mejorar la legibilidad. Aplicando esto a su código, obtenemos f =: [: (,~ 0 $~ 8 - 8 | #) #:y g =: [: ($~ 8 ,~ # % 8:) fpor último toCString =: a. {~ [: #. g. Todos combinados obtenemos a. {~ [: #. [: ($~ 8 ,~ # % 8:) [: (,~ 0 $~ 8 - 8 | #) #:, lo cual es realmente fácil de leer.
FUZxxl