числовые литералы mathpack

10

предисловие

В очень жаркой ситуации вы должны пойти еще дальше с игрой в гольф.
(например, в задании, где ваш ответ имеет длину 100 символов, и это просто смущает, что вы не можете сделать это 99)
В этом случае, теперь вы используете алгоритм победителя этого задания :)

Цель

Вы должны написать программу, которая принимает uint32 и возвращает наиболее сжатую форму.

$ mathpack 147456
9<<14
  • Там будет несколько решений для числа. Выберите самый короткий
  • Если сжатая форма длиннее или равна исходному номеру, вернуть исходный номер

правила

  • писать на любом языке - выводить на любом языке
  • я знаю, что в C 'abc'есть, 6382179и вы можете достичь довольно хороших результатов с этим преобразованием. но языки разделены в этом вызове, так что не унывай
  • запрещено использовать внешние переменные. только операторы и литералы и математические функции!

счет

Вот тестовые примеры: pastebin.com/0bYPzUhX
ваш показатель (в процентах) будет равен соотношению
byte_size_of_your_output / byte_size_of_the_list без разрывов строк .
(Вы должны сделать это самостоятельно, так как я на всякий случай проверим лучшие коды)
Победители будут выбраны по баллам и языку вывода !

Примеры:

$ mathpack 147456 | mathpack 97787584 |  mathpack 387420489
            9<<14 |           9e7^9e6 |            pow(9,9)
Бебе
источник
Прекрасная задача, но вы должны добавить правило против жесткого кодирования.
Julıʇǝɥʇuʎs
у-ты имеешь ввиду хардкод 10к случаев? хотя я был бы рад получить некоторую поддержку о том, как усовершенствовать этот вызов
bebe
отредактировано (снова и снова ...) для ясности. спасибо за советы.
bebe
Разве это не было бы [розетта-камень]? Также: write in any language - output in any language- два языка могут быть разными, верно?
Julıʇǝɥʇuʎs
@ ɐɔıʇǝɥʇuʎs [rosetta-stone] на самом деле о том, что вы решаете его на максимально возможном количестве языков. И да, на ваш последний вопрос - он был отредактирован в ответ на то, что я задавал тот же вопрос.
Мартин Эндер

Ответы:

1

Код: Mathematica, Выход: C, ~ 62.1518% (12674/20392)

Я думал, что тоже попробую С из-за этих забавных литералов персонажей. В настоящее время это единственное, что пытается найти этот ответ, и он работает довольно хорошо.

mathpack[n_] := Module[{versions, charLiteral},
   charLiteral = "'" <> StringReplace[Map[
        Switch[#,
          (*d_ /; d < 32,
          "\\" <> IntegerString[#, 8],*)
          10,
          "\\n",
          13,
          "\\r"
          39,
          "\\'",
          92 ,
          "\\\\",
          _,
          FromCharacterCode@#] &,
        FromDigits[#, 
           2] & /@ (Partition[PadLeft[IntegerDigits[n, 2], 32], 
            8] //. {{0 ..} .., x__} :> {x})
        ] <> "",
      {(*"\\10" -> "\\b",
       "\\11" -> "\\t",
       "\\13" -> "\\v",
       "\\14" -> "\\f",*)
       RegularExpression["(?!<=\?)\?\?(?=[=/()!<>-]|$)"] -> "?\\?"
       }
      ] <> "'";
   versions = {ToString@n, charLiteral};
   SortBy[versions, StringLength][[1]]
 ];

Надеюсь, я ничего не пропустил, но этот ответ поможет избежать обратной косой черты, одинарных кавычек и триграфов. Существует некоторый закомментированный код, который использует восьмеричные или другие escape-последовательности для непечатаемых символов, но я не думаю, что это на самом деле необходимо, потому что C должен иметь возможность обрабатывать любые байты в символьных литералах, afaik (пожалуйста, исправьте меня, если я я не прав)

Как с другим представлением, проверьте это с

input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
Мартин Эндер
источник
(По крайней мере, в моей системе) GCC будет принимать любые байты в одинарных кавычках, кроме 10 ( \n) и 13 ( \r). Нулевой байт будет компилироваться нормально, но с сообщением об ошибке warning: null character(s) preserved in literal.
r3mainer
@squeamishossifrage Спасибо, исправлено!
Мартин Эндер
3

Код: 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 два больших числа в научной нотации (фактически, для всех xor , или и и и ). Обратите внимание, что расширение xormap,ormap и andmapвключить операнды за пределами 2 32 могут помочь найти дополнительные оптимизации, но она не работает для данных тестов и только увеличивает время выполнения что - то вроде в 10 разы .

РЕДАКТИРОВАТЬ: я сбрил еще 16 байтов, проверив все на n-9, n-8, ..., n+8, n+9наличие какого-либо из возможности сокращения них , и в этом случае я представлял число на основе этого, добавляя или вычитая разницу. Есть несколько случаев, когда одно из этих 18 чисел может быть представлено на 3 или более символов меньше его nсамого, и в этом случае я могу сделать дополнительную экономию. Теперь требуется около 30 секунд, чтобы запустить его во всех тестовых случаях, но, конечно, если бы кто-то на самом деле «использовал» эту функцию, он бы запустил ее только для одного числа, так что это все еще намного меньше секунды.

РЕДАКТИРОВАТЬ: один невероятный 4 байта, делая то же самое для умножения и деления. 50 секунд (разделенные не занимают так много времени, потому что я проверяю их, только если число на самом деле делится на интересующий фактор).

РЕДАКТИРОВАТЬ: еще одна оптимизация, которая на самом деле не помогает с данным набором тестов. Этот может сохранить байт для таких вещей, как 2 30 или 2 31 . Если бы вместо этого у нас были uint64s, было бы много чисел, где это могло бы принести огромную экономию (в основном, всякий раз, когда представление битов заканчивалось многими единицами).

РЕДАКТИРОВАТЬ: Убрал XOR , или , и оптимизация в целом. Я только заметил, что они даже не работают в Джулии, потому что (совершенно очевидно) научная запись дает вам плавающее число, где побитовые операторы даже не определены. Интересно, что одна или несколько новых оптимизаций, кажется, охватывают все случаи, которые были сокращены этими оптимизациями, потому что оценка не изменилась вообще.

Мартин Эндер
источник
1

От J до C (не проверено, но работает в большинстве случаев, вид базового ответа.)

    f=:(,~ (($&0) @: (8&-) @: (8&|) @: #)) @: #:
    g=:($~ ((,&8) @: (%&8) @: #))@:f
    toCString=:({&a.)@:#.@:g
    toCString 6382179
abc    

Выводит строковый литерал, который, если он введен в C, представляет число (как упомянуто в OP). Это не серьезное представление, а скорее что-то, чтобы укрепить мои навыки J, которыми я поделился.

Альтернативный однострочный:

toCString=:({&a.) @: #. @: ($~ ((,&8) @: (%&8) @: #))@: (,~ (($&0) @: (8&-) @: (8&|) @: #)) @: #:

Что J пытается сделать из этого, когда вы вводите это:

{&a.@:#.@:($~ ,&8@:(%&8)@:#)@:(,~ $&0@:(8&-)@:(8&|)@:#)@:#:

Большое спасибо, J. Также, для тех, кто «знает» о J, visio качается за создание более сложных функций:

введите описание изображения здесь

ɐɔıʇǝɥʇuʎs
источник
Поскольку я не могу прочитать ничего из этого: что это делает, если символ не может быть напечатан, или если символ есть \ , ?или '?
Мартин Эндер
@ m.buettner Ничего (пока), я все еще должен что-то построить для этого
Julıʇǝɥʇuʎs
Вместо этого m&u@:vиспользуйте m u vдля сохранения ценных символов и повышения читабельности. Применяя это к коду, мы получим f =: [: (,~ 0 $~ 8 - 8 | #) #:и g =: [: ($~ 8 ,~ # % 8:) fнаконец toCString =: a. {~ [: #. g. Все вместе мы получаем a. {~ [: #. [: ($~ 8 ,~ # % 8:) [: (,~ 0 $~ 8 - 8 | #) #:, что действительно легко читать.
FUZxxl