Ausgeglichener ternärer Konverter


32

Credits für die Challenge-Idee gehen an @AndrewPiliser. Sein ursprünglicher Vorschlag im Sandkasten wurde aufgegeben und da er hier seit mehreren Monaten nicht mehr aktiv ist, habe ich die Herausforderung übernommen.

Ausgeglichener Ternär System ist ein nicht standardmäßiges Zahlensystem. Es ist insofern ternär, als der Wert der Ziffern um den Faktor 3 zunimmt, wenn Sie weiter nach links gehen - also 100ist 9und 1001ist 28.

Anstelle der Werte 0, 1 und 2 haben die Ziffern jedoch die Werte -1, 0 und 1 . (Sie können dies weiterhin verwenden, um eine beliebige Ganzzahl auszudrücken.)

Für diese Herausforderung wird die Ziffernbedeutung +1geschrieben als +, -1geschrieben als -und 0ist gerecht0 . Balanced Ternary verwendet das -Symbol vor Zahlen nicht, um sie zu negieren, wie dies bei anderen Zahlensystemen der Fall ist - siehe Beispiele.

Ihre Aufgabe ist es, ein komplettes Programm zu schreiben, das eine 32-Bit-Ganzzahl mit Dezimalzeichen als Eingabe verwendet und in ein ausgeglichenes ternäres Programm konvertiert. Eingebaute Basisumwandlungsfunktionen jeglicher Art sind nicht erlaubt (Mathematica hat wahrscheinlich eine ...). Die Eingabe kann über Standardeingabe, Befehlszeilenargumente usw. erfolgen.

Führende Nullen dürfen in der Eingabe vorhanden sein, aber nicht in der Ausgabe, es sei denn, die Eingabe ist 0. In diesem Fall sollte die Ausgabe auch vorhanden sein0 .

Beispiele

Dies sind Umrechnungen von Ternär nach Dezimal; Sie müssen in die andere Richtung konvertieren.

+0- = 1*3^2 + 0*3^1 + -1*3^0 = 9 + 0 + -1 = 8
+-0+ = 1*3^3 + -1*3^2 + 0*3^1 + 1*3^0 = 27 + -9 + 0 + 1 = 19
-+++ = -1*3^3 + 1*3^2 + 1*3^1 + 1*3^0 = -27 + 9 + 3 + 1 = -14

Oh, warte, ich habe gerade bemerkt, dass es eine Frage zum ausgewogenen Dutzend gibt - ist das ein Duplikat?

Wie ich bereits in der Sandbox erwähnt habe, ist es meiner Meinung nach näher an der Herausforderung, Standarddarstellungen zu erstellen . Aber es ist wahrscheinlich auch kein Duplikat.
Martin Ender

Antworten:


22

Python 2: 58 Zeichen

n=input()
s=""
while n:s="0+-"[n%3]+s;n=-~n/3
print s or 0

Erzeugt die ausgeglichene ternäre Ziffer für Ziffer vom Ende. Die letzte Ziffer wird durch den Rest gegeben n%3wird -1, 0oder+1 . Wir entfernen dann die letzte Ziffer und dividieren durch 3 unter Verwendung von Pythons Floor Divide n=(n+1)/3. Dann fahren wir rekursiv mit der neuen letzten Ziffer fort, bis die Zahl 0 ist.

Ein Sonderfall ist erforderlich für die Eingabe 0zu geben , 0anstatt die leere Zeichenkette.


Die Spezifikationen erlauben dies nicht, aber wenn man anstelle eines Programms eine Funktion schreiben und den leeren String für 0 ausgeben könnte, wäre eine Lösung mit 40 Zeichen möglich.

g=lambda n:n and g(-~n/3)+"0+-"[n%3]or""

Besser n*"."andim Funktionsfall zu verwenden . Funktioniert auch print s or 0besser: P
Nabb

@Nabb Guter Anruf auf s or 0. Ich hatte es versucht n*"."and, aber es schlägt fehl, wenn n<0.
22.

@ MartinBüttner Pyths längere Antwort war nur auf die Verwendung eines nicht optimalen Algorithmus zurückzuführen.
Optimierer

@Optimizer Nun, offensichtlich, und deshalb habe ich die Python-Antwort, die zuerst den besseren Algorithmus bekam, hochgestuft. : P
Martin Ender

6

CJam, 24 Bytes

Das habe ich mir selbst ausgedacht und ich denke, das ist höchstwahrscheinlich die einzige Möglichkeit, damit umzugehen.

li{_3%"0+-"=\_g+3/}h;]W%

Algorithmisch ist es der Antwort von xnor ähnlich.

Probieren Sie es hier online aus

Wie es funktioniert :

li{               }h                 "Read input, convert to integer and run the code block"
                                     "until stack has 0 on top";
   _3%                               "Copy and get modulus 3";
      "0+-"=                         "Take the correct character based on the above modulus";
            \_g+                     "Swap, copy and take signum of the number and add"
                                     "that to it, incrementing the number if positive,"
                                     "decrementing otherwise";
                3/                   "Integer divide by 3 and continue until 0";
                    ;]               "Pop the residual 0 and wrap everything in array";
                      W%             "Reverse to get in binary format (right handed)";

Ist das Bit "Inkrementieren, wenn positiv, Dekrementieren, wenn negativ" erforderlich? warum nicht einfach inkrementieren?
Isaacg

@isaacg Probieren Sie es aus;)
Optimierer

Unterscheidet sich die Rundung von CJams Division?
isaacg

@isaacg - Rundung - nein. CJam Integer Division rundet nicht. Es Böden
Optimierer

Aber Boden gegen Null oder -inf?
isaacg

6

JavaScript (E6) 68

Ein vollständiges Programm, wie gewünscht, mit E / A über Popup. Der Kern ist die R-Funktion, 49 Bytes.

Ich schätze, das unterscheidet sich nicht so sehr von den anderen rekursiven Lösungen. Nutzen Sie die automatische Konvertierung zwischen String und Zahl, um einen Sonderfall für "0" zu vermeiden

 alert((R=(n,d=(n%3+3)%3)=>n?R((n-d)/3+(d>1))+'0+-'[d]:'')(prompt()))

Testen Sie in der FireFox / FireBug-Konsole nur mit der R-Funktion

['0','8','19','-14','414'].map(x =>x +': '+R(x))

Ausgabe

["0: 0", "8: +0-", "19: +-0+", "-14: -+++", "414: +--0+00"]

Vermisse ich etwas? Was ist der Sinn , d=(n%3+3)%3wenn d=n%3liefert den gleichen Wert für d?
RLH

@RLH nicht für negative Werte (nicht in JavaScript). -20% 3 === -2% 3 === -2. Stattdessen sollte -20 mod 3 1 sein und (-20% 3 + 3)% 3 ist tatsächlich 1
edc65

6

Pyth, 71 24 23

L?+y/hb3@"0+-"%b3bk|yQ0

Dies ist eine rekursive Lösung, die auf der 40-stelligen rekursiven Funktion von @ xnor basiert. yKonstruiert den ausgeglichenen Ternärwert der Eingabe, indem die letzte Ziffer unter Verwendung des Mod-3-Index ermittelt wird, und verwendet dann die Tatsache, dass die restlichen Ziffern dem ausgeglichenen Ternärwert für (n + 1) / 3 entsprechen, wobei die Floored Division verwendet wird. Dann ruft es die Funktion auf und gibt das Ergebnis zurück oder 0, wenn die Eingabe 0 ist.

Probieren Sie es hier aus.


Gibt es einen Online-Pyth-Interpreter?

Dort werde ich es dem Beitrag hinzufügen.
Isaacg

Dein Link ist kaputt. Ich empfehle Probieren Sie es online! , den Sie von nun an immer dann verwenden, wenn Sie einen Dolmetscher für irgendetwas benötigen. Dein Code scheint übrigens nicht zu funktionieren, bei mir gibt er nur die Eingabe zurück.
Pavel

@Pavel Es hat vor zwei Jahren funktioniert, als ich es geschrieben habe. Der aktuelle Online-Pyth-Interpreter ist pyth.herokuapp.com. Wenn Sie den obigen Code ausführen möchten, können Sie den Interpreter von damals unter github.com/isaacg1/pyth auschecken , der einen vollständigen, versionskontrollierten Verlauf der Sprache aufweist.
Isaacg

3

Mathematica - 157 154 146 128

Die Golfversion:

f=(s="";n=#;i=Ceiling@Log[3,Abs@#]~Max~0;While[i>=0,s=s<>Which[n>=(1+3^i)/2,n-=3^i;"+",n>-(1+3^i)/2,"0",1>0,n+=3^i;"-"];i--];s)&

Und mit Einzug für die Lesbarkeit:

f = (s = ""; n = #; i = Ceiling@Log[3, Abs@#]~Max~0;
 While[i >= 0, 
  s = s<>Which[
   n >= (1 + 3^i)/2, n -= 3^i; "+",
   n > -(1 + 3^i)/2, "0", 
   1 > 0, n += 3^i; "-"
  ];
 i--];
s)&

Verwendung:

f[414]

Ausgabe:

+--0+00

Vielen Dank an Martin Büttner für die Reduzierung der Zeichenanzahl.


3

Mathematica, 54 Zeichen

Ähnlich wie die Rekursion von xnor

Unicode - Symbole verwendet zu ersetzen Floor, Part,!=

If[(t=⌊(#+1)/3⌋)≠0,#0@t,""]<>{"0","+","-"}〚#~Mod~3+1〛&

Ausgabe

Aus fGründen der Kürze gespeichert und ohne Unicode geschrieben, können Sie nicht anzeigen

f=If[(t=Floor[(#+1)/3])!=0,#0@t,""]<>{"0","+","-"}[[#~Mod~3+1]]&
f /@ {8, 19, -14, 414} // Column

+0-
+-0+
-+++
+--0+00

3

GNU sed, 236 Bytes

/^0/bV
:
s/\b9/;8/
s/\b8/;7/
s/\b7/;6/
s/\b6/;5/
s/\b5/;4/
s/\b4/;3/
s/\b3/;2/
s/\b2/;1/
s/\b1/;0/
s/\b0//
/[^;-]/s/;/&&&&&&&&&&/g
t
y/;/1/
:V
s/111/3/g
s/3\b/3:/
s/311/33!/
s/31/3+/
y/3/1/
tV
s/1/+/
y/1:/!0/
/-/{s/-//
y/+!/!+/
}
y/!/-/

Probieren Sie es online!

Erläuterung

Die erste Hälfte des Codes (abzüglich der ersten Zeile) wird dezimal in unär übersetzt und stammt direkt aus " Tipps zum Golfen in sed ". Dann wird eins nach dem anderen in ein ausgewogenes ternäres Trit übersetzt, was ich anhand eines Beispiels von Hand demonstrieren werde.

Vor der endgültigen Ausgabe, die ternären Ziffern -, 0und +durch dargestellt werden !, :und+ jeweils.

Für ein interessantes Ergebnis beginnen wir mit -48, das auf unary (mit dem -intakten) konvertiert wurde . Um den ersten (am weitesten rechts stehenden) Trit zu berechnen, müssen wir den Rest von 48 ÷ 3 berechnen. Wir können dies tun, indem wir das 111s durch 3s ersetzen :

-111111111111111111111111111111111111111111111111 │ s/111/3/g
# => -3333333333333333

48 ÷ 3 hat keinen Rest, also 1bleiben keine s übrig, und wir wissen, dass unser erster Trit :(für 0) ist, also ersetzen wir ihn:

-3333333333333333 │ s/3\b/3:/
# => -3333333333333333:

Jetzt haben wir unseren "einen Platz", also wissen wir, dass die verbleibenden 3s den Platz drei repräsentieren. Um die Mathematik am Laufen zu halten, müssen wir sie durch 3 teilen, dh durch 1s ersetzen :

-3333333333333333: │ y/3/1/
# => -1111111111111111:

Lassen Sie uns unsere Mathematik noch einmal überprüfen: Wir haben 16 (unär 1111111111111111) an der dreifachen Stelle und Null (: ) an der Stelle eins. Das sind 3✕16 + 1✕0 = 48. So weit so gut.

Jetzt fangen wir wieder an. Ersetze 111s durch 3s:

-1111111111111111: │ s/111/3/g
# => -333331:

Diesmal ist unser Rest 1, also setzen wir +den Platz drei ein und ersetzen das verbleibende 3s durch 1s:

-333331: │ s/31/3+/; y/3/1/
# => -11111+:

Sanity Check Time: Wir haben eine 5 (unär 11111) in den Neunern, 1 ( +) in den :Dreien und 0 ( ) in den Einern: 9✕5 + 3✕1 + 1✕0 = 48. Großartig! Wieder ersetzen wir das 111s durch 3s:

-11111+: │ s/111/3/g
# => -311+:

Diesmal ist unser Rest 2 ( 11). Das braucht zwei Trits ( +!), was bedeutet, dass wir einen Carry haben. Genau wie in der Dezimalarithmetik bedeutet dies, dass wir die am weitesten rechts stehende Ziffer nehmen und den Rest der linken Spalte hinzufügen. In unserem System bedeutet dies, dass wir !die Neun einsetzen und links davon drei weitere hinzufügen und dann alle ersetzen3 s durch 1s , um die 27er-Stelle darzustellen:

-311+: │ s/311/33!/; y/3/1/
# => -11!+:

Jetzt haben wir keine 3en mehr, sodass wir alle verbleibenden unären Ziffern durch die entsprechenden Trits ersetzen können. Zwei ( 11) ist+! :

-11!+: │ s/11/+!/
# => -+!!+:

Im eigentlichen Code erfolgt dies in zwei Schritten s/1/+/und y/1:/!0/, um Bytes zu sparen. Der zweite Schritt ersetzt auch :s durch 0s, also macht er das tatsächlich:

-11!+: │ s/1/+/; y/1:/+0/
# => -+!!+0

Jetzt prüfen wir, ob wir eine negative Zahl haben. Wir müssen also das Zeichen entfernen und dann jeden Trit umkehren:

-+!!+0 │ /-/ { s/-//; y/+!/!+/; }
# => !++!0

Schließlich ersetzen wir !s durch -s:

!++!0 │ y/!/-/
# => -++-0

Das ist es!



1

JavaScript 108 102 (ES6, keine rekursiven Aufrufe)

t=a=>{v="";if(0==a)v="0";else for(a=(N=0>a)?-a:a;a;)v="0+-"[r=(a%3+3)%3]+v,2==r&&++a,a=a/3|0;return v}

Ursprünglicher Eintrag bei 108

t=a=>{v="";if(0==a)v="0";else for(a=(N=0>a)?-a:a;a;)v=(N?"0-+":"0+-")[r=a%3]+v,2==r&&++a,a/=3,a|=0;return v}

Nicht so ausgefallen wie die Antwort von @ edc65 ... Ich würde mich über jede Hilfe bei der weiteren Reduzierung freuen ...


1

Clojure, 242 Bytes

#(clojure.string/join""(map{1"+"0"0"-1"-"}(loop[x(vec(map read-string(clojure.string/split(Integer/toString % 3)#"")))](let[y(.indexOf x 2)](if(< y 0)x(let[z(assoc x y -1)](recur(if(= y 0)(vec(cons 1 z))(assoc z(dec y)(inc(x(dec y))))))))))))

Ist dies die längste Antwort von Clojure?

Ungolfed (mit Kommentaren):

(use '[clojure.string :only (split join)]);' (Stupid highlighter)
; Import functions

(defn ternary [n]
  (join ""
  ; Joins it all together
    (map {1 "+" 0 "0" -1 "-"}
    ; Converts 1 to +, 0 to 0, -1 to -
      (loop [x (vec (map read-string (split (Integer/toString n 3) #"")))]
      ; The above line converts a base 10 number into base 3,
      ; and splits the digits into a list (8 -> [2 2])
        (let [y (.indexOf x 2)]
        ; The first occurrence of 2 in the list, if there is no 2,
        ; the .indexOf function returns -1
          (if (< y 0) x
          ; Is there a 2? If not, then output the list to
          ; the map and join functions above.
            (let [z (assoc x y -1)]
            ; Converts where the 2 is to a -1 ([2 2] -> [-1 2])
              (recur
                (if (= y 0) (vec (cons 1 z))
                  ; If 2 is at the 0th place (e.g. [2 2]),
                  ; prepend a 1 (e.g. [-1 2] -> [1 -1 2])
                  (assoc z (dec y) (inc (x (dec y)))))))))))))
                  ; Else increment the previous index
                  ; (e.g. [1 -1 2] -> [1 0 -1])

1

8. , 179 171 167 Zeichen

Hier handelt es sich um ein vollständiges Programm in 8th, das eine dezimal vorzeichenbehaftete Ganzzahl als Eingabe verwendet und in ein ausgeglichenes ternäres Programm konvertiert

 
: f "" swap repeat dup 3 n:mod ["0","+","-"] swap caseof rot swap s:+ swap dup n:sgn n:+ 3 n:/mod nip while drop s:rev ;
"? " con:print 16 null con:accept >n
f cr . cr
 

Prüfung

 
? 414
+--0+00
 

Beim ersten Mal fragt das Programm nach einer zu konvertierenden Zahl (nach Bedarf). Dann ist es möglich, das Wort aufzurufen f, um weitere Zahlen wie in der folgenden Zeile umzuwandeln:

 
[ 8 , 19 , -14 , ] ( nip dup . space f . cr ) a:each drop 
 

Ausgabe

 
8 +0-
19 +-0+
-14 -+++
 

Code Erklärung

 
"? " con:print 16 null con:accept >n
 

Dies ist der Code für die Eingabebehandlung. Der Kern des Codes liegt im Wort f. Abseits des Golfplatzes hätte ich >btstattdessen das Wort gebraucht f. Hier ist es eine ungolfed Version von f(mit Kommentaren):

 
: f \ n -- s
    ""   \ used for the first symbol concatenation
    swap \ put number on TOS to be used by loop
    repeat
        dup 
        3 n:mod      \ return the remainder of the division by 3
        [ "0" , "+" , "-" , ] 
        swap caseof  \ use remainder to take proper symbol
        rot          \ put previous symbol on TOS 
        swap         \ this is required because "" should come first
        s:+          \ concatenate symbols
        swap         \ put number on TOS 
        dup
        n:sgn n:+    \ add 1 if positive or add -1 if negative
        3 n:/mod nip \ put quotient only on TOS
    while drop
    s:rev            \ reverse the result on TOS
;
 

0

Java, 327 269 ​​Zeichen

Mein erster Versuch im Code-Golf. Ich kenne keine dieser wirklich kurzen Sprachen, deshalb hier eine Lösung in Java. Ich würde mich über Ratschläge zur weiteren Verkürzung freuen.

import java.util.*;class a{public static void main(String[] h){int i=Integer.parseInt(new Scanner(System.in).nextLine());String r="";while(i!=0){if(i%3==2||i%3==-1){r="-"+r;}else if(i%3==1||i%3==-2){r="+"+r;}else{r="0"+r;}i=i<0?(i-1)/3:(i+1)/3;}System.out.println(r);}}

Versuchen Sie es hier: http://ideone.com/fxlBBb

BEARBEITEN

Ersetzt BufferedReaderdurch Scanner, sodass ich die throwsKlausel entfernen konnte , aber den Import ändern musste (+2 Zeichen). Ersetzt Integerdurch int. Leider kann das Programm nicht kompiliert werden, wenn es nicht String[] hin ist main.


1
Möglicherweise können Sie ein paar Bytes sparen, indem Sie Scanneranstelle von "a" verwenden BufferedReader. Auch String[] hund throws java.lang.Exceptionwahrscheinlich nicht notwendig, und Sie könnten ein paar weitere Bytes sparen, indem Sie intanstelle von verwenden Integer.

0

JavaScript (ES6), 51 Byte

v=>[...v].map(x=>t=3*t+((+x!=+x)?(x+1)-0:0),t=0)&&t

Durchlaufe die Charaktere. Multiplizieren Sie zuerst die vorherige Summe mit 3, und konvertieren Sie dann, wenn isNaN (Zeichen) wahr ist, die Zeichenfolge (Zeichen + "1") in eine Zahl, und addieren Sie sie, andernfalls Null.




0

APL (NARS), 26 Zeichen, 52 Byte

{+/(3*¯1+⍳≢⍵)ׯ2+⌽'-0+'⍳⍵}

Prüfung:

  h←{+/(3*¯1+⍳≢⍵)ׯ2+⌽'-0+'⍳⍵}
  h '+0-'
8
  h '+-0+'
19
  h '-+++'
¯14
  h ,'-'
¯1
  h ,'0'
0
  h ,'+'
1

Möglicherweise könnte es weniger sein, wenn ⊥ verwendet wird, aber es ist verboten ...

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.