mathpack literal literal

10

kata pengantar

Dalam situasi yang sangat panas Anda harus melangkah lebih jauh dengan bermain golf.
(mis. dalam tantangan di mana jawaban Anda adalah 100 karakter dan itu memalukan bahwa Anda tidak dapat membuatnya 99).
Dalam hal ini, mulai sekarang Anda menggunakan algoritma pemenang dari tantangan ini :)

tujuan

Anda harus menulis program yang menggunakan uint32 dan mengembalikan formulir yang paling padat.

$ mathpack 147456
9<<14
  • Akan ada beberapa solusi untuk suatu nomor. Pilih yang terpendek
  • Jika bentuk terkompresi lebih panjang atau sama dengan nomor aslinya, kembalikan nomor aslinya

aturan

  • tulis dalam bahasa apa pun - output dalam bahasa apa pun
  • Aku menyadari bahwa dalam C 'abc'adalah 6382179dan Anda dapat mencapai hasil yang cukup baik dengan konversi ini. tetapi bahasa dipisahkan dalam tantangan ini jadi jangan berkecil hati
  • dilarang menggunakan variabel eksternal. hanya operator dan fungsi terkait literal dan matematika!

mencetak gol

di sini adalah kasus uji: pastebin.com/0bYPzUhX
skor Anda (persen) akan menjadi rasio
byte_size_of_your_output / byte_size_of_the_list tanpa jeda baris .
(Anda harus melakukan ini sendiri karena saya hanya akan memverifikasi kode terbaik untuk berjaga-jaga)
pemenang akan dipilih berdasarkan skor dan bahasa output !

contoh:

$ mathpack 147456 | mathpack 97787584 |  mathpack 387420489
            9<<14 |           9e7^9e6 |            pow(9,9)
bebe
sumber
Tantangan yang indah, tetapi Anda harus menambahkan aturan terhadap hard coding.
ɐɔıʇǝɥʇuʎ
y-maksudmu 10k hardcoding? walaupun saya akan senang mendapatkan dukungan tentang cara memperbaiki tantangan ini
bebe
diedit (lagi dan lagi ...) untuk kejelasan. terima kasih atas sarannya.
bebe
Bukankah ini juga [batu rosetta]? Juga: write in any language - output in any language- dua bahasa bisa berbeda, bukan?
ɐɔıʇǝɥʇuʎ
@ ɐɔıʇǝɥʇuʎs [rosetta-stone] sebenarnya tentang Anda menyelesaikannya dalam bahasa sebanyak mungkin. Dan ya untuk pertanyaan terakhir Anda - yang telah diedit sebagai tanggapan terhadap saya menanyakan pertanyaan yang sama.
Martin Ender

Jawaban:

1

Kode: Mathematica, Output: C, ~ 62.1518% (12674/20392)

Saya pikir saya juga akan mencoba C karena literal karakter lucu itu. Saat ini, inilah satu-satunya jawaban yang coba dicoba, dan ini berfungsi dengan baik.

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]]
 ];

Saya harap saya tidak melewatkan apa pun, tetapi jawaban ini memastikan untuk lolos dari garis miring terbalik, tanda kutip tunggal dan juga trigraph. Ada beberapa kode yang dikomentari yang menggunakan sekuens oktal atau lainnya untuk karakter yang tidak dapat dicetak, tapi saya rasa itu tidak perlu, karena C harus bisa berurusan dengan byte dalam literal karakter, afaik (tolong perbaiki saya jika saya salah).

Seperti kiriman lainnya, uji ini dengan

input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
Martin Ender
sumber
(Setidaknya pada sistem saya) GCC akan menerima byte dalam tanda kutip tunggal kecuali 10 ( \n) dan 13 ( \r). Byte nol akan mengkompilasi OK, tetapi dengan pesan kesalahan warning: null character(s) preserved in literal.
r3mainer
@squeamishossifrage Terima kasih, sudah diperbaiki!
Martin Ender
3

Kode: Mathematica, Output: Julia, ~ 98.9457% (20177/20392 byte)

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]]
 ];

Fungsi mengambil nomor dan mengembalikan string terpendek yang ditemukannya. Saat ini ia menerapkan empat optimisasi sederhana (saya mungkin menambahkan lebih banyak besok).

Anda dapat menerapkannya ke seluruh file (untuk mengukur nilainya) sebagai berikut:

input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]

Perhatikan bahwa beberapa optimisasi ini mengasumsikan bahwa Anda menggunakan Julia 64-bit, sehingga literal integer memberi Anda int64default. Jika tidak, Anda tetap akan kelebihan untuk bilangan bulat lebih besar dari 2 31 . Dengan menggunakan asumsi itu, kita dapat menerapkan beberapa optimasi yang langkah-langkah peralihannya sebenarnya bahkan lebih besar dari 32 .

EDIT: Saya menambahkan optimasi yang disarankan dalam contoh OP untuk bitwise xor dua angka besar dalam notasi ilmiah (sebenarnya, untuk semua xor , atau dan dan ). Perhatikan bahwa memperluas xormap, ormapdan andmapuntuk menyertakan operan di luar 2 32 dapat membantu menemukan optimisasi tambahan, tetapi tidak berfungsi untuk kasus uji yang diberikan dan hanya menambah waktu berjalan dengan sesuatu seperti faktor 10.

EDIT: Saya mencukur 16 byte lagi, dengan memeriksa semua n-9, n-8, ..., n+8, n+9apakah ada yang bisa dipersingkat, dalam hal ini saya mewakili angka berdasarkan itu, menambah atau mengurangi perbedaan. Ada beberapa kasus, di mana salah satu dari 18 angka dapat diwakili dengan 3 atau lebih karakter kurang dari nitu sendiri, dalam hal ini saya dapat melakukan penghematan tambahan. Dibutuhkan sekitar 30 detik sekarang untuk menjalankannya pada semua kasus uji, tetapi tentu saja, jika seseorang benar-benar "menggunakan" fungsi ini, ia hanya akan menjalankannya pada satu nomor, jadi masih di bawah satu detik.

EDIT: Lain 4 byte luar biasa dengan melakukan hal yang sama untuk perkalian dan pembagian. 50 detik sekarang (yang dibagi tidak butuh waktu lama, karena saya hanya memeriksa ini jika jumlahnya benar-benar dapat dibagi oleh faktor yang menarik).

EDIT: Optimalisasi lain yang sebenarnya tidak membantu set tes yang diberikan. Yang ini bisa menghemat satu byte untuk hal-hal seperti 2 30 atau 2 31 . Jika kita memiliki uint64 saja, akan ada banyak angka di mana ini bisa menjadi penghematan besar (pada dasarnya, setiap kali representasi bit berakhir dengan banyak 1s).

EDIT: Menghapus xor , atau , dan optimisasi sama sekali. Saya hanya memperhatikan mereka bahkan tidak bekerja di Julia, karena (sangat jelas) notasi ilmiah memberi Anda pelampung di mana operator bit-bijaksana bahkan tidak didefinisikan. Yang menarik, satu atau lebih optimisasi yang lebih baru nampaknya menangkap semua kasus yang dipersingkat oleh optimisasi ini, karena skornya tidak berubah sama sekali.

Martin Ender
sumber
1

J to C (belum diuji, tetapi berfungsi dalam kebanyakan kasus, semacam jawaban dasar.)

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

Menghasilkan string literal yang, jika dimasukkan dalam C, mewakili angka (sebagaimana disebutkan dalam OP). Ini bukan penyerahan yang serius, melainkan sesuatu untuk memperkuat keterampilan J saya, yang saya pikir saya akan bagikan.

Alternatif satu-liner:

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

Apa yang J coba lakukan ketika Anda memasukkannya:

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

Terima kasih banyak, J. Juga, bagi mereka yang 'tahu' tentang J, batu visio untuk membuat fungsi yang lebih kompleks:

masukkan deskripsi gambar di sini

ɐɔıʇǝɥʇu
sumber
Karena saya tidak bisa membacanya, apa yang dilakukan jika karakternya tidak dapat dicetak, atau jika karakternya \ , ?atau '?
Martin Ender
@ m.buettner Tidak (belum), saya masih harus membangun sesuatu untuk itu
Julıʇǝɥʇuʎs
Alih-alih m&u@:v, gunakan m u vuntuk menyimpan karakter berharga dan untuk meningkatkan keterbacaan. Menerapkan ini ke kode Anda, kami mendapatkan f =: [: (,~ 0 $~ 8 - 8 | #) #:dan g =: [: ($~ 8 ,~ # % 8:) fdan terakhir toCString =: a. {~ [: #. g. Semua gabungan kita dapatkan a. {~ [: #. [: ($~ 8 ,~ # % 8:) [: (,~ 0 $~ 8 - 8 | #) #:, yang sangat mudah dibaca.
FUZxxl