Code: Mathematica, sortie: Julia, ~ 98,9457% (20177/20392 octets)
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 fonction prend un nombre et renvoie la chaîne la plus courte qu'elle trouve. Actuellement, il applique quatre optimisations simples (je pourrais en ajouter plus demain).
Vous pouvez l'appliquer à l'ensemble du fichier (pour mesurer son score) comme suit:
input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
Notez que certaines de ces optimisations supposent que vous utilisez une Julia 64 bits, de sorte que les littéraux entiers vous donnent un int64
par défaut. Sinon, vous déborderez de toute façon pour les entiers supérieurs à 2 31 . En utilisant cette hypothèse, nous pouvons appliquer quelques optimisations dont les étapes intermédiaires sont en fait encore plus grandes que 2 32 .
EDIT: J'ai ajouté l'optimisation suggérée dans les exemples de l'OP pour xor bit à bit deux grands nombres en notation scientifique (en fait, pour tout xor , ou et et ). Notez que l' extension de la xormap
, ormap
et andmap
d'inclure opérandes au - delà de 2 32 pourrait aider à trouver d' autres optimisations, mais il ne fonctionne pas pour les par quelque chose comme un facteur de 10 cas de test donnés et ne fait qu'augmenter le temps de fonctionner.
EDIT: J'ai rasé 16 autres octets, en vérifiant tous n-9, n-8, ..., n+8, n+9
si certains d'entre eux peuvent être raccourcis, auquel cas j'ai représenté le nombre en fonction de cela, en ajoutant ou en soustrayant la différence. Il y a quelques cas, où l'un de ces 18 nombres peut être représenté avec 3 caractères ou plus de moins que n
lui-même, auquel cas je peux faire des économies supplémentaires. Cela prend environ 30 secondes maintenant pour l'exécuter sur tous les cas de test, mais bien sûr, si quelqu'un "utilise" réellement cette fonction, il ne l'exécutera que sur un seul numéro, donc c'est encore bien moins d'une seconde.
EDIT: Un autre incroyable 4 octets en faisant de même pour la multiplication et la division. 50 secondes maintenant (celles divisées ne prennent pas autant de temps, car je ne vérifie celles-ci que si le nombre est réellement divisible par le facteur d'intérêt).
EDIT: Une autre optimisation qui n'aide pas vraiment avec l'ensemble de test donné. Celui-ci pourrait enregistrer un octet pour des choses comme 2 30 ou 2 31 . Si nous avions des uint64 à la place, il y aurait beaucoup de nombres où cela pourrait être une énorme économie (en gros, chaque fois que la représentation des bits se termine par beaucoup de 1).
EDIT: Suppression du XOR , ou , et Optimisations tout à fait. Je viens de remarquer qu'ils ne fonctionnent même pas dans Julia, car (bien évidemment) la notation scientifique vous donne un flottant où les opérateurs bit par bit ne sont même pas définis. Fait intéressant, une ou plusieurs des nouvelles optimisations semblent intercepter tous les cas qui ont été raccourcis par ces optimisations, car le score n'a pas changé du tout.