Konverter Ternary Seimbang

32

Kredit untuk gagasan tantangan masuk ke @AndrewPiliser. Proposal aslinya di kotak pasir ditinggalkan dan karena dia tidak aktif di sini selama beberapa bulan, saya telah mengambil alih tantangan.

Terner seimbang adalah sistem angka non-standar. Ini seperti ternary di mana angka kenaikan nilainya dengan faktor 3 ketika Anda melangkah lebih jauh ke kiri - begitu100juga9dan100128.

Namun, alih-alih memiliki nilai 0, 1 dan 2, angka-angka tersebut memiliki nilai -1, 0, dan 1 . (Anda masih dapat menggunakan ini untuk mengekspresikan bilangan bulat apa pun.)

Untuk tantangan ini, makna digit +1akan ditulis sebagai +, -1akan ditulis sebagai -, dan 0adil 0. Terner seimbang tidak menggunakan -simbol di depan angka untuk meniadakannya seperti sistem angka lainnya - lihat contoh.

Tugas Anda adalah menulis program lengkap yang mengambil bilangan bulat bertanda desimal 32-bit sebagai input dan mengubahnya menjadi ternary berimbang. Tidak ada fungsi konversi basis bawaan dalam bentuk apa pun yang diizinkan (Mathematica mungkin memiliki satu ...). Input dapat berupa input standar, argumen baris perintah, dll.

Angka nol terdepan mungkin ada dalam input tetapi tidak dalam output, kecuali inputnya 0, dalam hal ini output juga seharusnya 0.

Contohnya

Ini adalah konversi dari terner seimbang ke desimal; Anda harus mengonversi dengan cara lain.

+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
Komunitas
sumber
Oh, tunggu, saya baru saja memperhatikan ada pertanyaan tentang dozenal seimbang - apakah ini duplikat?
Seperti yang saya sebutkan di kotak pasir, saya pikir ini lebih dekat dengan tantangan tentang representasi standar phinary . Tapi itu mungkin juga bukan duplikat.
Martin Ender

Jawaban:

22

Python 2: 58 karakter

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

Menghasilkan digit terner seimbang per digit dari akhir. Digit terakhir diberikan oleh residu n%3makhluk -1, 0atau +1. Kami kemudian menghapus digit terakhir dan membaginya dengan 3 menggunakan pembagian lantai Python n=(n+1)/3. Kemudian, kami melanjutkan secara rekursif dengan digit terakhir yang baru hingga angkanya 0.

Kasing khusus diperlukan agar input 0memberi 0daripada string kosong.


Spesifikasi tidak mengizinkan ini, tetapi jika seseorang dapat menulis fungsi alih-alih sebuah program dan menghasilkan string kosong untuk 0, solusi char 40 akan dimungkinkan.

g=lambda n:n and g(-~n/3)+"0+-"[n%3]or""
Tidak
sumber
Lebih baik digunakan n*"."anddalam kasus fungsi saja. Juga print s or 0berfungsi lebih baik: P
Nabb
@Nabb Panggilan baik aktif s or 0. Saya sudah mencoba n*"."and, tetapi gagal ketika n<0.
xnor
@ MartinBüttner Jawaban Pyth yang lebih panjang adalah hanya karena penggunaan algoritma yang tidak optimal.
Pengoptimal
@Optimizer Yah, jelas, dan itulah sebabnya saya telah memutakhirkan jawaban Python yang mendapatkan algoritma yang lebih baik terlebih dahulu. : P
Martin Ender
6

CJam, 24 byte

Saya datang dengan ini secara independen dan saya pikir ini, kemungkinan besar, satu-satunya cara untuk menangani ini.

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

Secara algoritmik, mirip dengan jawaban xnor.

Cobalah online di sini

Cara kerjanya :

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)";
Pengoptimal
sumber
Apakah "kenaikan jika positif, sedikit jika negatif" perlu? mengapa tidak kenaikan saja?
isaacg
@isaacg Cobalah;)
Pengoptimal
Apakah pembulatan di divisi CJam berbeda?
isaacg
@isaacg - Pembulatan - no. Divisi integer CJam tidak bulat. Itu lantai
Pengoptimal
Tapi lantai menuju nol atau -inf?
isaacg
6

JavaScript (E6) 68

Program lengkap, seperti yang diminta, dengan I / O via popup. Inti adalah fungsi R, 49 byte.

Tidak jauh berbeda dengan solusi rekursif lainnya, kurasa. Manfaatkan konversi otomatis antara string dan angka untuk menghindari kasus khusus untuk "0"

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

Uji di konsol FireFox / FireBug, hanya menggunakan fungsi R

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

Keluaran

["0: 0", "8: +0-", "19: +-0+", "-14: -+++", "414: +--0+00"]
edc65
sumber
Apakah saya melewatkan sesuatu? Apa gunanya d=(n%3+3)%3kapan d=n%3menghasilkan nilai yang sama d?
RLH
@RLH bukan untuk nilai negatif (bukan dalam JavaScript). -20% 3 === -2% 3 === -2. Sebaliknya -20 mod 3 harus 1, dan (-20% 3 + 3)% 3 memang 1
edc65
6

Pyth, 71 24 23

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

Ini adalah solusi rekursif, berdasarkan fungsi rekursif 40 karakter @ xnor. ymembangun terner baanced dari input, dengan menemukan digit terakhir menggunakan mod mod 3, dan kemudian menggunakan fakta bahwa sisa digit sama dengan terner seimbang untuk (n + 1) / 3, menggunakan pembagian lantai. Kemudian, ia memanggil fungsi, mengembalikan hasilnya, atau 0 jika inputnya 0.

Coba di sini.

isaacg
sumber
Apakah ada penerjemah Pyth online?
Ada, saya akan menambahkannya ke posting.
isaacg
Tautan Anda rusak. Saya merekomendasikan Cobalah online! , yang akan Anda gunakan mulai sekarang kapan pun Anda membutuhkan juru bahasa untuk apa pun. Omong-omong, kode Anda tampaknya tidak berfungsi, bagi saya itu hanya mengembalikan input.
Pavel
@ Pavel Ini bekerja dua tahun lalu, ketika saya menulisnya. Penerjemah Pyth online saat ini adalah pyth.herokuapp.com. Jika Anda ingin menjalankan kode di atas, Anda dapat memeriksa penerjemah dari saat itu dari github.com/isaacg1/pyth , yang memiliki versi lengkap yang mengontrol sejarah bahasa.
isaacg
3

Mathematica - 157 154 146 128

Versi golf:

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

Dan dengan lekukan untuk keterbacaan:

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

Pemakaian:

f[414]

Keluaran:

+--0+00

Banyak terima kasih kepada Martin Büttner dalam mengurangi jumlah karakter.

Menghitung
sumber
3

Mathematica, 54 karakter

Mirip dengan rekursi xnor

Simbol Unicode digunakan untuk menggantikan Floor, Part,!=

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

Keluaran

Disimpan funtuk singkat dan ditulis tanpa memetikan unicode Anda tidak dapat melihat

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

+0-
+-0+
-+++
+--0+00
mil
sumber
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/!/-/

Cobalah online!

Penjelasan

Bagian pertama dari kode (kurang dari baris pertama) menerjemahkan desimal ke unary dan langsung berasal dari " Tips untuk bermain golf dalam sed ." Kemudian itu menerjemahkan unary ke terary seimbang satu trit pada satu waktu, yang saya akan menunjukkan dengan bekerja contoh secara manual.

Sebelum hasil akhir, terner angka -, 0dan +diwakili oleh !, :dan +masing-masing.

Untuk hasil yang menarik, kita mulai dengan -48, yang telah dikonversi menjadi unary (dengan -utuh). Untuk menghitung trit pertama (paling kanan), kita harus menghitung sisa 48 ÷ 3. Kita dapat melakukan ini dengan mengganti 111s dengan 3s:

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

48 ÷ 3 tidak memiliki sisa, jadi tidak ada 1yang tersisa, dan kami tahu trit pertama kami adalah :(untuk 0), jadi kami menggantinya:

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

Sekarang kita memiliki "tempat" kita, jadi kita tahu sisanya 3mewakili tempat bertiga. Agar matematika tetap berfungsi, kita harus membaginya dengan 3, yaitu ganti dengan 1s:

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

Mari kita periksa matematika kita: Kita memiliki 16 (unary 1111111111111111) di tempat bertiga dan nol ( :) di tempat itu. Itu 3✕16 + 1✕0 = 48. Sejauh ini bagus.

Sekarang kita mulai lagi. Ganti 111s dengan 3s:

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

Kali ini sisanya adalah 1, jadi kami taruh +di tempat bertiga dan ganti yang tersisa 3dengan 1s:

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

Waktu cek kewarasan: Kami memiliki 5 (tidak sama 11111) di tempat sembilan, 1 ( +) di tempat bertiga, dan 0 ( :) di tempat yang: 9✕5 + 3✕1 + 1✕0 = 48. Hebat! Sekali lagi kita ganti 111s dengan 3s:

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

Kali ini sisanya adalah 2 ( 11). Itu membutuhkan dua trits ( +!), yang berarti kita memiliki carry. Sama seperti dalam aritmatika desimal itu berarti kita mengambil digit paling kanan dan menambahkan sisanya ke kolom di sebelah kiri. Dalam sistem kami, itu berarti kami menempatkan !di tempat sembilan dan menambahkan tiga di sebelah kirinya, lalu mengganti semua 3dengan 1s untuk mewakili tempat ke-27:

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

Sekarang kami tidak memiliki 3 angka yang tersisa, jadi kami dapat mengganti sisa digit yang belum diketahui dengan trits yang sesuai. Dua ( 11) adalah +!:

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

Dalam kode aktual ini dilakukan dalam dua langkah, s/1/+/dan y/1:/!0/, untuk menghemat byte. Langkah kedua juga menggantikan :s dengan 0s, jadi ia melakukan ini:

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

Sekarang kami memeriksa apakah kami memiliki angka negatif. Kami melakukannya, jadi kami harus menyingkirkan tanda dan kemudian membalikkan masing-masing tanda:

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

Akhirnya, kami ganti !s dengan -s:

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

Itu dia!

Jordan
sumber
2

Stax , 17 byte

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

Jalankan dan debug itu

Jawaban terpendek sejauh ini, tetapi harus mudah dikalahkan oleh beberapa bahasa golf. Algoritma ini sama dengan jawaban Python @ xnor.

Setara ASCII:

z{"0+-";3%@+,^3/~;wr
Weijun Zhou
sumber
1

JavaScript 108 102 (ES6, tidak ada panggilan rekursif)

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}

Entri asli pada 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}

Tidak semewah jawaban @ edc65 ... Saya menghargai bantuan yang mengurangi ini ...

WallyWest
sumber
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))))))))))))

Apakah ini jawaban Clojure terpanjang sejauh ini?

Tidak digabungkan (dengan komentar):

(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])
clismique
sumber
1

8 , 179 171 167 karakter

Ini adalah program lengkap di 8 yang mengambil bilangan bulat bertanda desimal sebagai input dan mengubahnya menjadi ternary berimbang

 
: 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
 

Uji

 
? 414
+--0+00
 

Pertama kali program meminta nomor untuk dikonversi (sesuai kebutuhan). Kemudian, dimungkinkan untuk menggunakan kata funtuk mengonversi angka lebih banyak seperti pada baris berikut:

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

Keluaran

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

Penjelasan kode

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

Ini adalah kode untuk penanganan input. Inti dari kode ada di dalam kata f. Jauh dari lapangan golf, saya akan menggunakan kata itu >btsebagai ganti f. Ini dia versi ungolfed dari f(dengan komentar):

 
: 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
;
 
Kekacauan Manor
sumber
0

Java, 327 269 ​​karakter

Percobaan pertama saya dalam kode golf. Saya tidak tahu bahasa yang benar-benar singkat, jadi inilah solusi di Jawa. Saya menghargai saran untuk lebih mempersingkatnya.

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

Coba di sini: http://ideone.com/fxlBBb

EDIT

Digantikan BufferedReaderoleh Scanner, memungkinkan saya menghapus throwsklausa, tetapi harus mengubah impor (+2 karakter). Diganti Integeroleh int. Sayangnya, program tidak dapat dikompilasi jika tidak ada String[] hdi main.

Thrax
sumber
1
Anda mungkin dapat menyimpan beberapa byte dengan menggunakan Scannerbukan BufferedReader. Juga, String[] hdan throws java.lang.Exceptionmungkin tidak perlu, dan Anda mungkin menyimpan beberapa byte lagi dengan menggunakan intalih-alih Integer.
0

JavaScript (ES6), 51 byte

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

Ulangi karakter. Pertama, kalikan total sebelumnya 3 kali sebelumnya, lalu jika isNaN (karakter) benar, ubah string (karakter + "1") menjadi angka dan tambahkan, jika tidak nol.

Grax32
sumber
0

APL (NARS), 26 karakter, 52 byte

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

uji:

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

mungkin bisa lebih sedikit jika ⊥ digunakan tetapi dilarang ...

RosLuP
sumber