Збалансований термінальний перетворювач


32

Кредити на виклик ідеї переходять до @AndrewPiliser. Його первісна пропозиція в пісочниці була покинута, і оскільки він не був активним тут уже кілька місяців, я взяв на себе виклик.

Збалансований трійник - це нестандартна система числення. Це як трикомпонентної в томущо збільшити цифри в ціні в 3 разияк ви йдете далі вліво - так100це9і1001є 28.

Однак замість значень 0, 1 і 2 цифри мають значення -1, 0 і 1 . (Ви все ще можете використовувати це для вираження будь-якого цілого числа.)

Для цього виклику значення цифри +1буде записано як +, -1буде записано як -і 0є справедливим 0. Збалансований трійник не використовує -символ перед цифрами, щоб заперечувати їх, як це роблять інші системи числення - див. Приклади.

Ваше завдання полягає в тому, щоб написати повну програму, яка приймає як вхідне 32-розрядне ціле число з десятковим знаком і перетворює його на збалансований потрійний. Ніякі вбудовані базові функції перетворення будь-якого типу не дозволені (у Mathematica, мабуть, є одна ...). Введення може бути на стандартному вході, аргументах командного рядка тощо.

Провідні нулі можуть бути присутніми на вході, але не у виході, якщо тільки це не вхід 0, в цьому випадку також повинен бути вихід 0.

Приклади

Це перетворення з збалансованого потрійного в десятковий; вам доведеться конвертувати іншим способом.

+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

О, чекайте, я щойно помітив, що є питання про збалансований дозенал - це дублікат?

Як я вже згадував у пісочниці, я думаю, що це ближче до виклику щодо стандартних фінальних уявлень . Але це, мабуть, не дублікат жодного з них.
Мартін Ендер

Відповіді:


22

Пітон 2: 58 символів

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

Створює збалансований потрійний розряд з кінця з кінця. Остання цифра дається залишок n%3істоти -1, 0або +1. Потім ми видаляємо останню цифру і ділимо на 3, використовуючи підлогу Python-поділу n=(n+1)/3. Потім рекурсивно переходимо до нової останньої цифри, поки число не дорівнює 0.

Особливий випадок необхідний для введення , 0щоб дати , 0а не порожній рядок.


Технічні характеристики цього не дозволяють, але якби можна було замість програми написати функцію та вивести порожній рядок на 0, можливе рішення 40 знаків.

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

Краще використовувати n*"."andв корпусі, призначеному лише для функцій. Також print s or 0працює краще: P
Nabb

@Nabb Добрий дзвінок s or 0. Я намагався n*"."and, але коли це не вдається n<0.
xnor

@ Більш довга відповідь MartinBüttner Pyth була лише завдяки використанню неоптимального алгоритму.
Оптимізатор

@Optimizer Ну, очевидно, і саме тому я підтримав відповідь Python, який першим отримав кращий алгоритм. : P
Мартін Ендер

6

CJam, 24 байти

Я придумав це самостійно і думаю, що це, мабуть, єдиний спосіб впоратися з цим.

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

Алгоритмічно це схоже на відповідь xnor.

Спробуйте його онлайн тут

Як це працює :

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

Чи потрібен біт "приріст, якщо позитивний, декремент, якщо негативний"? чому не просто приріст?
isaacg

@isaacg Спробуйте;)
Оптимізатор

Чи відрізняється округлення підрозділу CJam?
isaacg

@isaacg - Округлення - ні. Ціле ділення CJam не округляється. Це підлоги
Optimizer

Але підлогу до нуля або -в?
isaacg

6

JavaScript (E6) 68

Повна програма, за потребою, з вводу-виводу через спливаюче вікно. Ядро - функція R, 49 байт.

Я не так відрізняється від інших рекурсивних рішень, я думаю. Користуючись автоматичним перетворенням між рядком і числом, щоб уникнути особливого випадку для "0"

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

Тестуйте в консолі FireFox / FireBug, використовуючи лише функцію R

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

Вихід

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

Я щось пропускаю? Який сенс, d=(n%3+3)%3коли d=n%3дає однакове значення d?
RLH

@RLH не для негативних значень (не в JavaScript). -20% 3 === -2% 3 === -2. Натомість -20 мод 3 має бути 1, а (-20% 3 + 3)% 3 дійсно є 1
edc65

6

Піта, 71 24 23

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

Це рекурсивне рішення, засноване на 40-ти символьній рекурсивній функції @ xnor. yконструює урівноважений потрійний вхід, знаходячи останню цифру за допомогою індексу mod 3, а потім використовує той факт, що решта цифр дорівнює врівноваженому потрійному для (n + 1) / 3, використовуючи floored поділ. Потім він викликає функцію, повертаючи результат, або 0, якщо вхід 0.

Спробуйте тут.


Чи є онлайн-перекладач Pyth?

Є, я додам його до посади.
isaacg

Ваше посилання розірвано. Рекомендую Спробуйте в Інтернеті! , який ви зараз будете використовувати, коли вам потрібен перекладач для будь-чого. До речі, ваш код, здається, не працює, для мене він просто поверне введення.
Павло

@Pavel Це працювало два роки тому, коли я це писав. Поточний інтерпретатор Pyth в Інтернеті - pyth.herokuapp.com Якщо ви хочете запустити вищевказаний код, ви можете перевірити інтерпретатора з того часу з github.com/isaacg1/pyth , який має повну історію мови, що контролюється версією.
isaacg

3

Математика - 157 154 146 128

Версія для гольфу:

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

І з відступом для розбірливості:

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

Використання:

f[414]

Вихід:

+--0+00

Велике спасибі Мартіну Бюттнеру за зменшення кількості персонажів.


3

Математика, 54 символи

Аналогічно рекурсії xnor

Символи Unicode використовуються для заміни Floor, Part,!=

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

Вихід

Збережено fдля стислості та написано без унікоду, який ви не можете переглянути

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 байт

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

Спробуйте в Інтернеті!

Пояснення

Перша половина коду (за винятком першого рядка) перекладає десятковий на одинарний і походить прямо з " Поради щодо гольфу в седі ". Тоді це перекладається уніарно на балансований потрійний по одному триті за раз, що я продемонструю, працюючи на прикладі вручну.

До остаточного висновку, потрійні цифри -, 0і +представлені !, :і +, відповідно.

Для цікавого результату ми почнемо з того -48, що було перетворено в одинарне (з -неушкодженим). Щоб обчислити перший (найправіший) трит, треба обчислити залишок 48 ÷ 3. Це можна зробити, замінивши 111s на 3s:

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

48 ÷ 3 не має залишку, тому не 1залишається s, і ми знаємо, що наш перший трит :(для 0), тому ми його замінюємо:

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

Тепер у нас є своє "one place", тому ми знаємо, що решта 3s представляють місце трійки. Щоб математика не працювала, ми повинні їх розділити на 3, тобто замінити їх на 1s:

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

Давайте ще раз перевіримо нашу математику: у нас у трійці 16 (одинарних 1111111111111111) і в тих - нуль ( :). Це 3✕16 + 1✕0 = 48. Поки що добре.

Тепер ми починаємо заново. Замініть 111s на 3s:

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

Цього разу наше залишок є 1, тому ми ставимо +в трійку місце і замінюємо решту 3s на 1s:

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

Час перевірки розумності: у нас 5 (одинарний 11111) у місці дев'яти, 1 ( +) у місці трійки та 0 ( :) у тому місці: 9✕5 + 3✕1 + 1✕0 = 48. Чудово! Знову замінюємо 111s на 3s:

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

Цього разу наш залишок - 2 ( 11). Це займає два трити ( +!), це означає, що ми несемо. Як і в десятковій арифметиці, це означає, що ми беремо найменший правий розряд і додаємо решту до стовпця зліва. У нашій системі це означає, що ми ставимо !в дев'ять місце і додаємо ще три зліва, а потім замінюємо всі 3s на 1s, щоб представляти місце 27-х:

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

Тепер у нас не залишилося жодних 3-х, тому ми можемо замінити будь-які залишилися одинарні цифри відповідними тритами. Два ( 11) - це +!:

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

У фактичному коді це робиться в два етапи, s/1/+/і y/1:/!0/, щоб зберегти байти. Другий крок також замінює :s на 0s, тому він насправді робить це:

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

Тепер ми перевіряємо, чи є у нас від’ємне число. Ми це робимо, тому ми повинні позбутися знаку, а потім перевернути кожен трит:

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

Нарешті, замінюємо !s на -s:

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

Це воно!



1

JavaScript 108 102 (ES6, без рекурсивних дзвінків)

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}

Оригінальний запис за номером 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}

Не настільки вигадливий, як відповідь @ edc65 ... Я буду вдячний за будь-яку допомогу, щоб зменшити цю проблему далі ...


1

Clojure, 242 байти

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

Це найдовша відповідь Clojure досі?

Ungolfed (з коментарями):

(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 символів

Ось це повна програма у 8-му, яка приймає як вхідне число з десятковим підписаним цілим числом і перетворює його на врівноважений тернар

 
: 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
 

Тест

 
? 414
+--0+00
 

Перший раз програма запитує номер для перетворення (у міру необхідності). Потім можна викликати слово fдля перетворення більшої кількості цифр, як у наступному рядку:

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

Вихід

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

Пояснення коду

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

Це код для обробки вводу. Ядро коду знаходиться всередині слова f. Вдалині від поля для гольфу я б використав це слово >btзамість цього f. Ось це неперевершена версія f(з коментарями):

 
: 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 ​​символів

Моя перша спробу кодування в гольф. Я не знаю жодної з цих дійсно коротких мов, тому ось рішення на Java. Буду вдячний поради щодо подальшого скорочення.

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

Спробуйте тут: http://ideone.com/fxlBBb

EDIT

Замінено BufferedReaderна Scanner, що дозволило мені видалити throwsпункт, але довелося змінити імпорт (+2 символи). Замінено Integerна int. На жаль, програма не буде компілюватися , якщо немає String[] hв main.


1
Можливо, ви зможете зберегти кілька байт, скориставшись Scannerзамість свого BufferedReader. Крім того , String[] hі , throws java.lang.Exceptionймовірно , не потрібні, і ви могли б заощадити кілька байт, використовуючи intзамість Integer.

0

JavaScript (ES6), 51 байт

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

Прокрутіть символи. Спочатку помножте попередні загальні рази 3, потім, якщо isNaN (символ) є істинним, перетворіть рядок (символ + "1") у число і додайте його, інакше до нуля.




0

APL (NARS), 26 символів, 52 байти

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

тест:

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

можливо, вона може бути меншою, якщо використовується ⊥, але це заборонено ...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.