Convertitore ternario bilanciato


32

I crediti per l'idea della sfida vanno a @AndrewPiliser. La sua proposta originale nella sandbox è stata abbandonata e poiché non è attivo qui da diversi mesi, ho accettato la sfida.

Il ternario bilanciato è un sistema numerico non standard. È come ternario in quanto le cifre aumentano di valore di un fattore 3 man mano che si procede più a sinistra - così100è9ed1001è 28.

Tuttavia, anziché avere valori di 0, 1 e 2, le cifre hanno valori di -1, 0 e 1 . (Puoi ancora usarlo per esprimere qualsiasi numero intero.)

Per questa sfida, il significato della cifra +1sarà scritto come +, -1sarà scritto come -ed 0è giusto 0. Il ternario bilanciato non usa il -simbolo davanti ai numeri per negarli come fanno altri sistemi numerici - vedi esempi.

Il tuo compito è scrivere un programma completo che accetta come input un intero con segno decimale a 32 bit e lo converte in ternario bilanciato. Non sono consentite funzioni di conversione di base integrate di alcun tipo (probabilmente Mathematica ne ha una ...). L'input può essere su input standard, argomenti della riga di comando, ecc.

Gli zeri iniziali possono essere presenti nell'input ma non nell'output, a meno che non sia l'input 0, nel qual caso dovrebbe essere anche l'output 0.

Esempi

Queste sono conversioni da ternario bilanciato a decimale; dovrai convertire in altro modo.

+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 aspetta, ho appena notato che c'è una domanda sull'equilibrata dozzina - è un duplicato?

Come ho detto nella sandbox, penso che sia più vicino alla sfida delle rappresentazioni phinary standard . Ma probabilmente non è nemmeno un duplicato.
Martin Ender,

Risposte:


22

Python 2: 58 caratteri

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

Genera il ternario bilanciato cifra per cifra dalla fine. L'ultima cifra è dato dal residuo n%3essere -1, 0o +1. Quindi rimuoviamo l'ultima cifra e dividiamo per 3 usando la divisione del pavimento di Python n=(n+1)/3. Quindi, procediamo in modo ricorsivo con la nuova ultima cifra fino a quando il numero è 0.

È necessario un caso speciale per l'input 0da dare 0piuttosto che la stringa vuota.


Le specifiche non lo consentono, ma se si potesse scrivere una funzione anziché un programma e produrre la stringa vuota per 0, sarebbe possibile una soluzione da 40 caratteri.

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

Meglio usare n*"."andnel caso solo funzione. print s or 0Funziona anche meglio: P
Nabb,

@Nabb Buona chiamata s or 0. Ci avevo provato n*"."and, ma quando fallisce n<0.
xnor

@ MartinBüttner La risposta più lunga di Pyth era dovuta solo all'uso di un algoritmo non ottimale.
Ottimizzatore

@Optimizer Bene, ovviamente, ed è per questo che ho votato a fondo la risposta di Python che ha ottenuto l'algoritmo migliore per primo. : P
Martin Ender,

6

CJam, 24 byte

Ho escogitato questo in modo indipendente e penso che questo sia, probabilmente, l'unico modo per gestirlo.

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

Algoritmicamente, è simile alla risposta di xnor.

Provalo online qui

Come funziona :

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)";

È necessario il bit "Incremento se positivo, decremento se negativo"? perché non solo incrementare?
isaacg,

@isaacg Provalo;)
Ottimizzatore

L'arrotondamento della divisione di CJam è diverso?
isaacg,

@isaacg - Arrotondamento - no. La divisione intera CJam non arrotonda. Pavimenti
Ottimizzatore

Ma piano verso zero o -inf?
isaacg,

6

JavaScript (E6) 68

Un programma completo, come richiesto, con I / O tramite popup. Il nucleo è la funzione R, 49 byte.

Non così diverso dalle altre soluzioni ricorsive, immagino. Sfruttando la conversione automatica tra stringa e numero per evitare un caso speciale per "0"

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

Test nella console FireFox / FireBug, usando solo la funzione R.

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

Produzione

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

Mi sto perdendo qualcosa? A cosa serve d=(n%3+3)%3quando si d=n%3ottiene lo stesso valore d?
RLH,

@RLH non per valori negativi (non in JavaScript). -20% 3 === -2% 3 === -2. Invece -20 mod 3 dovrebbe essere 1, e (-20% 3 + 3)% 3 è effettivamente 1
edc65

6

Pyth, 71 24 23

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

Questa è una soluzione ricorsiva, basata sulla funzione ricorsiva di 40 caratteri di @xnor. ycostruisce il ternario bilanciato dell'input, trovando l'ultima cifra usando l'indice mod 3, quindi usa il fatto che il resto delle cifre sono uguali al ternario bilanciato per (n + 1) / 3, usando la divisione floored. Quindi chiama la funzione, restituendo il risultato o 0 se l'ingresso è 0.

Provalo qui.


Esiste un interprete Pyth online?

Ecco, lo aggiungerò al post.
isaacg,

Il tuo link è rotto. Lo consiglio Provalo online! , che utilizzerai d'ora in poi ogni volta che avrai bisogno di un interprete per qualsiasi cosa. A proposito, il tuo codice sembra non funzionare, per me restituisce solo l'input.
Pavel,

@Pavel Ha funzionato due anni fa, quando l'ho scritto. L'attuale interprete Pyth online è pyth.herokuapp.com Se vuoi eseguire il codice sopra, puoi leggere l'interprete da allora in poi da github.com/isaacg1/pyth , che ha una cronologia completa della lingua controllata dalla versione.
Isaacg,

3

Mathematica - 157 154 146 128

La versione golfizzata:

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)&

E con rientro per leggibilità:

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)&

Uso:

f[414]

Produzione:

+--0+00

Mille grazie a Martin Büttner per la riduzione del numero di personaggi.


3

Mathematica, 54 personaggi

Simile alla ricorsione di xnor

Simboli Unicode vengono utilizzati per sostituire Floor, Part,!=

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

Produzione

Memorizzato fper brevità e scritto senza Unicode, non è possibile visualizzarlo

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 byte

/^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/!/-/

Provalo online!

Spiegazione

La prima metà del codice (meno la prima riga) traduce i decimali in unari e deriva direttamente da " Suggerimenti per giocare a golf in sed ". Quindi traduce unario in ternario bilanciato un trit alla volta, che dimostrerò lavorando manualmente un esempio.

Prima l'output finale, le cifre ternarie -, 0e +sono rappresentati da !, :e +, rispettivamente.

Per un risultato interessante, iniziamo con -48, che è stato convertito in unario (con -intatto). Per calcolare il primo tratto (quello più a destra), dobbiamo calcolare il resto di 48 ÷ 3. Possiamo farlo sostituendo la 111s con 3s:

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

48 ÷ 3 non ha resto, quindi non 1rimangono s e sappiamo che il nostro primo trit è :(per 0), quindi lo sostituiamo:

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

Ora abbiamo i nostri "un posto", quindi sappiamo che i rimanenti 3rappresentano il terzo posto. Per far funzionare la matematica dobbiamo dividerli per 3, cioè sostituirli con 1s:

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

Ricontrolliamo la nostra matematica: ne abbiamo 16 (unari 1111111111111111) al terzo posto e zero ( :) al primo posto. È 3✕16 + 1✕0 = 48. Finora tutto bene.

Ora ricominciamo. Sostituisci 111s con 3s:

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

Questa volta il resto è 1, quindi inseriamo +i tre e sostituiamo le rimanenti 3s con 1s:

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

Tempo di controllo della sanità mentale: abbiamo un 5 (unario 11111) al posto dei nove, 1 ( +) al posto dei tre e 0 ( :) al posto dei: 9✕5 + 3✕1 + 1✕0 = 48. Fantastico! Sostituiamo di nuovo la 111s con 3s:

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

Questa volta il resto è 2 ( 11). Questo occupa due trits ( +!), il che significa che abbiamo un carry. Proprio come nell'aritmetica decimale ciò significa che prendiamo la cifra più a destra e aggiungiamo il resto alla colonna a sinistra. Nel nostro sistema, ciò significa che mettiamo !il posto dei nove e ne aggiungiamo altri tre alla sua sinistra, quindi sostituiamo tutte le 3s con 1s per rappresentare il posto dei 27:

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

Ora non ci sono ancora 3 secondi, quindi possiamo sostituire le cifre unarie rimanenti con i rispettivi tratti corrispondenti. Due ( 11) è +!:

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

Nel codice effettivo questo viene fatto in due passaggi s/1/+/e y/1:/!0/, per salvare byte. Il secondo passaggio sostituisce anche :s con 0s, quindi effettivamente fa questo:

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

Ora controlliamo se abbiamo un numero negativo. Lo facciamo, quindi dobbiamo sbarazzarci del segno e invertire ogni tratto:

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

Infine, sostituiamo !s con -s:

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

Questo è tutto!


2

Stax , 17 byte

ë1·âΓM¿├>Ö≥Er☺à┤3

Esegui ed esegui il debug

La risposta più breve finora, ma dovrebbe essere facilmente battuta da alcune lingue del golf. L'algoritmo è lo stesso della risposta Python di @ xnor.

Equivalente ASCII:

z{"0+-";3%@+,^3/~;wr

1

JavaScript 108 102 (ES6, nessuna chiamata ricorsiva)

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}

Voce originale a 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}

Non elegante come la risposta di @ edc65 ... Apprezzerei qualsiasi aiuto per ridurre ulteriormente questo ...


1

Clojure, 242 byte

#(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))))))))))))

È la risposta Clojure più lunga finora?

Ungolfed (con commenti):

(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 caratteri

Qui è un programma completo in ottava che accetta come input un intero decimale con segno decimale e lo converte in ternario bilanciato

 
: 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
 

Test

 
? 414
+--0+00
 

La prima volta che il programma richiede la conversione di un numero (come richiesto). Quindi, è possibile invocare la parola fper convertire più numeri come nella seguente riga:

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

Produzione

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

Spiegazione del codice

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

Questo è il codice per la gestione degli input. Il nucleo del codice è all'interno della parola f. Lontano dal campo da golf avrei usato la parola >btinvece di f. Ecco una versione non modificata di f(con commenti):

 
: 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 ​​caratteri

Il mio primo tentativo nel golf di codice. Non conosco nessuna di quelle lingue davvero brevi, quindi ecco una soluzione in Java. Gradirei consigli per accorciarlo ulteriormente.

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);}}

Provalo qui: http://ideone.com/fxlBBb

MODIFICARE

Sostituito BufferedReaderda Scanner, permettendomi di rimuovere la throwsclausola, ma ho dovuto cambiare l'importazione (+2 caratteri). Sostituito Integerda int. Purtroppo, il programma non viene compilato se non c'è String[] hin main.


1
Potresti essere in grado di salvare qualche byte usando un Scannerinvece del tuo BufferedReader. Inoltre, String[] he throws java.lang.Exceptionprobabilmente non sono necessari, e potresti salvare qualche altro byte usando intinvece di Integer.

0

JavaScript (ES6), 51 byte

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

Passa attraverso i personaggi. Innanzitutto moltiplica i tempi totali precedenti 3, quindi se isNaN (carattere) è vero, converti la stringa (carattere + "1") in un numero e aggiungilo, altrimenti zero.




0

APL (NARS), 26 caratteri, 52 byte

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

test:

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

possibile potrebbe essere inferiore se si utilizza ⊥ ma è vietato ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.