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 int64
valor 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
, ormap
y andmap
para 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+9
si 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 n
mismo, 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.