ตัวอักษรตัวเลข 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

y-you หมายถึง hardcoding 10k cases หรือเปล่า แม้ว่าฉันจะยินดีที่จะได้รับการสนับสนุนบางอย่างเกี่ยวกับวิธีการปรับแต่งความท้าทายนี้
bebe

แก้ไข (อีกครั้งและอีกครั้ง ... ) เพื่อความชัดเจน ขอบคุณสำหรับคำแนะนำ
bebe

นี่จะเป็น [rosetta-stone] ด้วยหรือไม่ นอกจากนี้: write in any language - output in any language- สองภาษาสามารถแตกต่างกันใช่มั้ย
Julıʇǝɥʇuʎs

@ ɐɔıʇǝɥʇuʎs [rosetta-stone] นั้นเกี่ยวกับคุณที่แก้มันในภาษาต่างๆให้ได้มากที่สุด และใช่สำหรับคำถามหลังของคุณ - ที่ได้รับการแก้ไขเพื่อตอบฉันถามคำถามเดียวกัน
Martin Ender

คำตอบ:


1

รหัส: Mathematica, เอาต์พุต: C, ~ 62.1518% (12674/20392)

ฉันคิดว่าฉันต้องลอง C เพราะตัวอักษรตัวตลกเหล่านั้น ปัจจุบันนี้เป็นสิ่งเดียวที่คำตอบนี้พยายามและมันทำงานได้ค่อนข้างดี

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

ฉันหวังว่าฉันจะไม่พลาดอะไรเลย แต่คำตอบนี้ทำให้แน่ใจว่าได้หลบหลีกแบ็กสแลชเครื่องหมายคำพูดเดี่ยวและตรีโกณมิติ มีโค้ดที่ใส่เครื่องหมายคอมเม้นท์ที่ใช้ octal หรือ 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 ขอบคุณคงแล้ว!
Martin Ender

3

รหัส: Mathematica, เอาต์พุต: 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]]
 ];

ฟังก์ชันใช้ตัวเลขและส่งคืนสตริงที่สั้นที่สุดที่พบ ขณะนี้มันใช้การเพิ่มประสิทธิภาพง่าย ๆ สี่แบบ (ฉันอาจเพิ่มอีกในวันพรุ่งนี้)

คุณสามารถนำไปใช้กับไฟล์ทั้งหมด (เพื่อวัดคะแนน) ดังนี้:

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

โปรดทราบว่าการเพิ่มประสิทธิภาพเหล่านี้บางอย่างสมมติว่าคุณอยู่ใน Julia 64 บิตเช่นนั้นตัวอักษรจำนวนเต็มจะให้คุณเป็นint64ค่าเริ่มต้น มิฉะนั้นคุณจะล้นอยู่แล้วสำหรับจำนวนเต็มมากกว่า 2 วันที่ 31 โดยใช้สมมติฐานที่ว่าเราสามารถใช้ optimisations ไม่กี่ที่มีขั้นตอนกลางเป็นจริงแม้จะมีขนาดใหญ่กว่า 2 32

แก้ไข:ฉันเพิ่มการเพิ่มประสิทธิภาพที่แนะนำในตัวอย่างของ OP เพื่อ bitwise xorตัวเลขสองขนาดใหญ่ในทางวิทยาศาสตร์ (ที่จริงสำหรับทุกxor , หรือและและ ) โปรดทราบว่าการขยายxormap, ormapและandmapจะรวมตัวถูกดำเนินการเกิน 2 32อาจช่วยให้การหา optimisations เพิ่มเติม แต่มันไม่ทำงานสำหรับกรณีทดสอบที่กำหนดและเพียง แต่เพิ่มเวลาทำงานโดยสิ่งที่ต้องการปัจจัยที่ 10

แก้ไข:ฉันโกนออกไปอีก 16 ไบต์โดยตรวจสอบทั้งหมดn-9, n-8, ..., n+8, n+9ว่ามีส่วนใดที่สั้นลงได้ซึ่งในกรณีนี้ฉันแทนตัวเลขตามนั้นโดยเพิ่มหรือลบความแตกต่าง มีบางกรณีที่หนึ่งใน 18 หมายเลขเหล่านี้สามารถแสดงด้วยอักขระ 3 ตัวหรือน้อยกว่าnนั้นในกรณีนี้ฉันสามารถประหยัดเพิ่มได้ ใช้เวลาประมาณ 30 วินาทีในการรันในทุกกรณีทดสอบ แต่แน่นอนว่าถ้ามีคน "ใช้" ฟังก์ชั่นนี้จริง ๆ เขาจะเรียกใช้เฉพาะหมายเลขเดียวเท่านั้น

แก้ไข:อีกอย่างไม่น่าเชื่อ 4 ไบต์โดยทำเช่นเดียวกันสำหรับการคูณและการหาร 50 วินาทีในขณะนี้ (ตัวหารจะใช้เวลาไม่นานเพราะฉันแค่ตรวจสอบสิ่งเหล่านี้ถ้าจำนวนหารด้วยปัจจัยที่น่าสนใจจริง ๆ )

แก้ไข:การเพิ่มประสิทธิภาพอื่นที่ไม่ได้ช่วยจริงกับชุดทดสอบที่กำหนด หนึ่งนี้จะสามารถประหยัดไบต์สำหรับสิ่งที่เหมือน 2 วันที่ 30หรือ 2 วันที่ 31 หากเรามี uint64 แทนจะมีตัวเลขมากมายที่สิ่งนี้อาจเป็นการประหยัดขนาดใหญ่ (โดยทั่วไปเมื่อใดก็ตามที่การแสดงบิตสิ้นสุดใน 1 วินาที)

แก้ไข:ถอดxor , หรือ ,และ optimisations โดยสิ้นเชิง ฉันเพิ่งสังเกตเห็นว่าพวกเขาไม่ได้ทำงานในจูเลียเพราะสัญกรณ์ทางวิทยาศาสตร์ (ค่อนข้างชัดเจน) ให้คุณลอยในที่ที่ผู้ประกอบการบิตที่ชาญฉลาดไม่ได้กำหนดไว้ น่าสนใจว่าการเพิ่มประสิทธิภาพที่ใหม่กว่านี้อย่างใดอย่างหนึ่งดูเหมือนจะจับทุกกรณีที่ถูกทำให้สั้นลงโดยการเพิ่มประสิทธิภาพเหล่านี้เนื่องจากคะแนนไม่เปลี่ยนแปลงเลย


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 หินสำหรับการสร้างฟังก์ชั่นที่ซับซ้อนมากขึ้น:

ป้อนคำอธิบายรูปภาพที่นี่


ตั้งแต่ฉันไม่สามารถอ่านใด ๆ ของมัน: สิ่งนี้จะทำอย่างไรถ้าตัวอักษรเป็นที่ไม่สามารถพิมพ์หรือถ้าตัวอักษรเป็น\ , ?หรือ'?
Martin Ender

@ 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.