コード:Mathematica、出力:Julia、〜98.9457%(20177/20392バイト)
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]]
];
この関数は数値を受け取り、見つかった最も短い文字列を返します。現在、4つの単純な最適化が適用されています(明日はさらに追加する可能性があります)。
次のように、それをファイル全体に適用して(スコアを測定するため)できます。
input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
これらの最適化の一部は、64ビットのジュリアを使用していることを前提としているため、整数リテラルint64
がデフォルトでを与えることに注意してください。それ以外の場合は、2 31より大きい整数がとにかくオーバーフローします。その仮定を使用して、中間ステップが実際には2 32よりもさらに大きいいくつかの最適化を適用できます。
編集:私はOPの例で提案されている最適化をビット表記のxorに 2つの大きな数値の科学的表記法で追加しました(実際には、すべてのxor、または and および)。を拡張しxormap
、2 32を超えるオペランドを含めるormap
とandmap
、追加の最適化を見つけるのに役立つ場合がありますが、特定のテストケースでは機能せず、実行時間を10倍程度増やすだけです。
編集:私はすべてをチェックすることにより、別の16バイト削り取らn-9, n-8, ..., n+8, n+9
のいずれかどうかのためにそれらを短くすることができ、その場合、私が追加または差を減算、それに基づいて数値を表しました。それらの18の数値の1 n
つがそれ自体よりも3文字以上少ない文字で表すことができる場合がいくつかあります。その場合、さらに節約できます。すべてのテストケースで実行するのに約30秒かかりますが、もちろん、誰かがこの関数を実際に「使用」した場合、1つの数値でのみ実行するので、1秒もかかりません。
編集:乗算と除算について同じことを行うことによる別の信じられないほどの4バイト。今50秒(分割されたものはそれほど長くはかかりません。なぜなら、数が実際に関心のある因子で割り切れる場合にのみこれらをチェックしているためです)。
編集:与えられたテストセットを実際に支援しない別の最適化。これは2 30や2 31のようなもののためにバイトを節約できます。代わりにuint64を使用した場合、これにより大幅な節約ができる数が多くなります(基本的に、ビット表現が1で終了するときはいつでも)。
編集:xor、or、および最適化を完全に削除しました。ジュリアでは動作しないことにも気づきました。(明らかに)科学的記法を使用すると、ビット単位の演算子が定義されていない浮動小数点数が得られるためです。興味深いことに、スコアがまったく変化しなかったため、新しい最適化の1つ以上がこれらの最適化によって短縮されたすべてのケースをキャッチしているようです。