Kod: Mathematica, Wyjście: Julia, ~ 98,9457% (20177/20392 bajtów)
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]]
];
Funkcja przyjmuje liczbę i zwraca najkrótszy znaleziony ciąg . Obecnie stosuje cztery proste optymalizacje (mogę dodać więcej jutro).
Możesz zastosować go do całego pliku (aby zmierzyć jego wynik) w następujący sposób:
input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
Zauważ, że niektóre z tych optymalizacji zakładają, że korzystasz z 64-bitowej Julii, tak że literały całkowite int64domyślnie dają ci . W przeciwnym razie przepełnisz się i tak dla liczb całkowitych większych niż 2 31 . Korzystając z tego założenia, możemy zastosować kilka optymalizacji, których kroki pośrednie są nawet większe niż 2 32 .
EDIT: dodałem optymalizacji sugerowanego w przykładach PO do bitowe xor dwie duże liczby w notacji naukowej (faktycznie, dla wszystkich xor , lub i i ). Zauważ, że przedłużające xormap, ormapi andmapzawierać argumenty poza 2 32 może pomóc w znalezieniu dodatkowe optymalizacje, ale to nie działa dla podanych przypadków testowych, a tylko zwiększa czas pracy przez coś w rodzaju 10-krotnie.
EDYCJA: Ogoliłem kolejne 16 bajtów, sprawdzając wszystkie, n-9, n-8, ..., n+8, n+9czy którekolwiek z nich można skrócić, w którym to przypadku przedstawiłem liczbę na podstawie tej wartości, dodając lub odejmując różnicę. Istnieje kilka przypadków, w których jedną z tych 18 liczb można przedstawić za pomocą 3 lub więcej znaków mniej niż ona nsama, w którym to przypadku mogę uzyskać dodatkowe oszczędności. Teraz zajmuje około 30 sekund, aby uruchomić go na wszystkich przypadkach testowych, ale oczywiście, jeśli ktoś faktycznie „użył” tej funkcji, uruchomiłby ją tylko na jednym numerze, więc jest to znacznie poniżej sekundy.
EDYCJA: Kolejne niesamowite 4 bajty, robiąc to samo dla mnożenia i dzielenia. Teraz 50 sekund (podzielone nie trwają tak długo, ponieważ sprawdzam je tylko wtedy, gdy liczba jest podzielna przez czynnik zainteresowania).
EDYCJA: Kolejna optymalizacja, która tak naprawdę nie pomaga w danym zestawie testowym. Ten może zaoszczędzić bajt na rzeczy takie jak 2 30 lub 2 31 . Gdybyśmy mieli uint64s, byłoby wiele liczb, w których może to być ogromna oszczędność (w zasadzie za każdym razem, gdy reprezentacja bitowa kończy się na 1).
EDIT: Usunięto xor , lub , i optymalizacje w ogóle. Zauważyłem, że nawet nie działają w Julii, ponieważ (całkiem oczywiste) notacja naukowa daje swobodę, w której operatory bitowe nie są nawet zdefiniowane. Co ciekawe, jedna lub więcej nowszych optymalizacji wydaje się wychwytywać wszystkie przypadki, które zostały skrócone przez te optymalizacje, ponieważ wynik wcale się nie zmienił.