代码:Mathematica,输出:朱莉娅,〜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]]
];
该函数接受一个数字并返回找到的最短字符串。当前它应用了四个简单的优化(我明天可能会添加更多)。
您可以将其应用到整个文件(以衡量其分数),如下所示:
input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
请注意,其中的一些优化假定您使用的是64位Julia,因此int64
默认情况下,整数文字会为您提供一个。否则,无论如何您都会溢出大于2 31的整数。使用该假设,我们可以应用一些优化,其中间步骤实际上甚至大于2 32。
编辑:我添加了OP的示例中建议的优化,以科学计数形式对两个大数进行按位异或(实际上,对于所有xor,or和and)。需要注意的是扩展xormap
,ormap
并andmap
包括超过2个操作数32可能有助于找到额外的优化,但它不会工作,为给定的测试用例,并只能通过类似的10倍运行时间的增加。
编辑:通过检查所有这些n-9, n-8, ..., n+8, n+9
是否可以缩短,我又减少了16个字节,在这种情况下,我基于此表示了数字,加上或减去了差值。在某些情况下,这18个数字之一可以用比其本身少3个或更多字符来表示,在这种情况下,我可以节省一些额外的费用。现在,在所有测试用例上运行它大约需要30秒钟,但是,当然,如果有人实际上“使用”了此功能,则他只会在单个数字上运行它,因此距离一秒钟还不错。n
编辑:另一个令人难以置信的4字节,用于乘法和除法。现在是50秒(分开的时间不需要那么长,因为我只检查这些数字是否实际上可以被感兴趣的因子整除)。
编辑:另一个实际上对给定测试集没有帮助的优化。这个可以为诸如2 30或2 31之类的内容节省一个字节。如果我们使用uint64s,那么会有很多数字可以节省很多钱(基本上,每当比特表示以1结束时)。
编辑:删除了XOR,或者,和最佳化完全。我只是注意到它们甚至在Julia中也不起作用,因为(很明显)科学计数法为您提供了一个甚至未定义按位运算符的浮点数。有趣的是,一个或多个较新的优化似乎可以涵盖所有因这些优化而缩短的情况,因为分数完全没有变化。