Mathpack numerische Literale

10

Vorwort

In einer sehr heißen Situation muss man beim Golfen noch weiter gehen.
(zB bei einer Herausforderung, bei der Ihre Antwort 100 Zeichen lang ist und es nur peinlich ist, dass Sie es nicht geschafft haben 99)
In diesem Fall verwenden Sie von nun an den Algorithmus des Gewinners für diese Herausforderung :)

Tor

Sie müssen ein Programm schreiben, das ein uint32 verwendet und die am meisten komprimierte Form zurückgibt.

$ mathpack 147456
9<<14
  • Es wird mehrere Lösungen für eine Nummer geben. Wählen Sie die kürzeste
  • Wenn das komprimierte Formular länger oder gleich der ursprünglichen Nummer ist, geben Sie die ursprüngliche Nummer zurück

Regeln

  • Schreiben in einer beliebigen Sprache - Ausgabe in einer beliebigen Sprache
  • Ich bin mir dessen bewusst , dass in C 'abc'ist 6382179und Sie recht gute Ergebnisse mit dieser Umwandlung erreichen können. Aber die Sprachen sind bei dieser Herausforderung getrennt, also verlieren Sie nicht den Mut
  • Es ist verboten, externe Variablen zu verwenden. Nur Operatoren und Literale sowie mathematische Funktionen!

Wertung

Hier sind die Testfälle: pastebin.com/0bYPzUhX
Ihre Punktzahl (Prozent) ist das Verhältnis
byte_size_of_your_output / byte_size_of_the_list ohne Zeilenumbrüche .
(Sie müssen dies selbst tun, da ich nur für den Fall die besten Codes überprüfe.) Die
Gewinner werden nach Punktzahl und Sprache der Ausgabe ausgewählt !

Beispiele:

$ mathpack 147456 | mathpack 97787584 |  mathpack 387420489
            9<<14 |           9e7^9e6 |            pow(9,9)
bebe
quelle
Schöne Herausforderung, aber Sie sollten eine Regel gegen harte Codierung hinzufügen.
7ıʇǝɥʇuʎs
y-du meinst 10k Fälle fest zu codieren? obwohl ich mich freuen würde, Unterstützung zu bekommen, wie man diese Herausforderung verfeinert
bebe
bearbeitet (immer wieder ...) zur Klarheit. Danke für die Ratschläge.
Bebe
Wäre das nicht auch [Rosettastein]? Außerdem: write in any language - output in any language- Die beiden Sprachen können unterschiedlich sein, oder?
7ıʇǝɥʇuʎs
Bei @ ɐɔıʇǝɥʇuʎs [Rosetta-Stein] geht es eigentlich darum, dass Sie es in so vielen Sprachen wie möglich lösen. Und ja zu Ihrer letzten Frage - diese wurde bearbeitet, als Antwort darauf, dass ich dieselbe Frage gestellt habe.
Martin Ender

Antworten:

1

Code: Mathematica, Ausgabe: C, ~ 62,1518% (12674/20392)

Ich dachte, ich würde es auch mit C versuchen, wegen dieser lustigen Charakterliterale. Derzeit ist dies das einzige, was diese Antwort versucht, und es funktioniert ziemlich gut.

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

Ich hoffe, ich habe nichts verpasst, aber diese Antwort verhindert Rückschläge, einfache Anführungszeichen und Trigraphen. Es gibt einen auskommentierten Code, der oktale oder andere Escape-Sequenzen für nicht druckbare Zeichen verwendet, aber ich denke nicht, dass dies tatsächlich notwendig ist, da C in der Lage sein sollte, mit Bytes in Zeichenliteralen umzugehen, afaik (bitte korrigieren Sie mich, wenn ich 'Ich liege falsch).

Testen Sie dies wie bei der anderen Einreichung mit

input = StringSplit[Import["path/to/benchmark.txt"]];
numbers = ToExpression /@ input;
output = mathpack /@ numbers;
N[StringLength[output <> ""]/StringLength[input <> ""]]
Martin Ender
quelle
(Zumindest auf meinem System) GCC akzeptiert alle Bytes in einfachen Anführungszeichen außer 10 ( \n) und 13 ( \r). Ein Null-Byte wird OK kompiliert, jedoch mit der Fehlermeldung warning: null character(s) preserved in literal.
r3mainer
@squeamishossifrage Danke, behoben!
Martin Ender
3

Code: Mathematica, Ausgabe: Julia, ~ 98,9457% (20177/20392 Bytes)

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

Die Funktion nimmt eine Zahl und gibt die kürzeste gefundene Zeichenfolge zurück . Derzeit werden vier einfache Optimierungen angewendet (ich könnte morgen weitere hinzufügen).

Sie können es wie folgt auf die gesamte Datei anwenden (um die Punktzahl zu messen):

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

Beachten Sie, dass einige dieser Optimierungen davon ausgehen, dass Sie sich auf einer 64-Bit-Julia befinden, sodass Sie int64durch ganzzahlige Literale standardmäßig eine erhalten. Andernfalls werden Sie bei Ganzzahlen größer als 2 31 ohnehin überlaufen . Unter dieser Annahme können wir einige Optimierungen anwenden, deren Zwischenschritte sogar noch größer als 2 32 sind .

EDIT: Ich habe die Optimierung in den Beispielen des OP vorgeschlagen , um bitweise xor zwei große Zahlen in wissenschaftlicher Notation (eigentlich für alle xor , oder und und ). Beachten Sie, dass die Verlängerung xormap, ormapund andmapdarüber hinaus zwei Operanden umfasst 32 könnte Hilfe bei der Suche zusätzliche Optimierungen, aber es funktioniert nicht für die gegebenen Testfälle und erhöht nur die Laufzeit durch so etwas wie ein Faktor von 10.

EDIT: I off weitere 16 Bytes rasiert, indem alle Überprüfung n-9, n-8, ..., n+8, n+9zum Bestimmen, ob jeder diejenigen kann verkürzt werden, wobei in diesem Fall I dargestellt , die Anzahl auf dem basiert, Addieren oder Subtrahieren der Differenz. Es gibt einige Fälle, in denen eine dieser 18 Zahlen mit 3 oder mehr Zeichen weniger als sich nselbst dargestellt werden kann. In diesem Fall kann ich zusätzliche Einsparungen erzielen. Es dauert jetzt ungefähr 30 Sekunden, um es in allen Testfällen auszuführen, aber wenn jemand diese Funktion tatsächlich "verwendet" hat, würde er sie natürlich nur für eine einzelne Nummer ausführen, sodass sie immer noch weit unter einer Sekunde liegt.

BEARBEITEN: Weitere unglaubliche 4 Bytes, indem Sie dasselbe für die Multiplikation und Division tun. 50 Sekunden jetzt (die geteilten dauern nicht so lange, weil ich diese nur überprüfe, wenn die Zahl tatsächlich durch den interessierenden Faktor teilbar ist).

BEARBEITEN: Eine weitere Optimierung, die mit dem angegebenen Testsatz nicht wirklich hilft. Dieser könnte ein Byte für Dinge wie 2 30 oder 2 31 speichern . Wenn wir stattdessen uint64s hätten, gäbe es viele Zahlen, bei denen dies eine enorme Einsparung bedeuten könnte (im Grunde immer dann, wenn die Bitdarstellung mit vielen 1s endet).

EDIT: Entfernt die xor , oder , und Optimierungen zusammen. Mir ist gerade aufgefallen, dass sie in Julia nicht einmal funktionieren, weil (ganz offensichtlich) die wissenschaftliche Notation Ihnen einen Float gibt, in dem bitweise Operatoren nicht einmal definiert sind. Interessanterweise scheinen eine oder mehrere der neueren Optimierungen alle Fälle zu erfassen, die durch diese Optimierungen verkürzt wurden, da sich die Punktzahl überhaupt nicht geändert hat.

Martin Ender
quelle
1

J bis C (ungetestet, funktioniert aber in den meisten Fällen als Basisantwort.)

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

Gibt ein Zeichenfolgenliteral aus, das, wenn es in C eingegeben wird, die Zahl darstellt (wie im OP erwähnt). Dies ist keine ernsthafte Vorlage, sondern etwas, um meine J-Fähigkeiten zu stärken, von denen ich dachte, ich würde sie teilen.

Alternativer Einzeiler:

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

Was J versucht, daraus zu machen, wenn Sie es eingeben:

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

Vielen Dank, J. Außerdem, für diejenigen, die sich mit J auskennen, rockt visio für die Erstellung komplexerer Funktionen:

Geben Sie hier die Bildbeschreibung ein

ɐɔıʇǝɥʇuʎs
quelle
Da ich nichts davon lesen kann: was tut dies , wenn das Zeichen nicht druckbare, oder wenn der Charakter ist \ , ?oder '?
Martin Ender
@ m.buettner Nichts (noch), ich muss noch etwas dafür bauen
8ıʇǝɥʇuʎs
m&u@:vVerwenden Sie stattdessen , m u vum wertvolle Zeichen zu speichern und die Lesbarkeit zu verbessern. Wenn wir dies auf Ihren Code anwenden, erhalten wir f =: [: (,~ 0 $~ 8 - 8 | #) #:und g =: [: ($~ 8 ,~ # % 8:) fund zuletzt toCString =: a. {~ [: #. g. Alles zusammen bekommen wir a. {~ [: #. [: ($~ 8 ,~ # % 8:) [: (,~ 0 $~ 8 - 8 | #) #:, was wirklich leicht zu lesen ist.
FUZxxl