Сбалансированный троичный преобразователь


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

Python 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
Набб

@ Набб Хорошо, звони 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 Попробуй;)
Оптимизатор

Отличается ли округление в делении CJam?
Исаак

@isaacg - Округление - нет. Целочисленное деление CJam не округляется. Это полы
Оптимизатор

Но пол к нулю или -инф?
Исаак

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 mod 3 должно быть 1, и (-20% 3 + 3)% 3 действительно равно 1
edc65

6

Pyth, 71 24 23

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

Это рекурсивное решение, основанное на 40-символьной рекурсивной функции @ xnor. yстроит сбалансированную троичную часть входа, находя последнюю цифру, используя индекс mod 3, а затем использует тот факт, что остальные цифры равны сбалансированной троичной для (n + 1) / 3, используя расслоенное деление. Затем он вызывает функцию, возвращая результат, или 0, если ввод равен 0.

Попробуй это здесь.


Есть ли онлайн-переводчик Pyth?

Там я добавлю это в пост.
Исаак

Ваша ссылка не работает. Я рекомендую попробовать онлайн! , который вы будете использовать отныне всякий раз, когда вам нужен переводчик для чего-либо. Кстати, ваш код, кажется, не работает, для меня он просто возвращает ввод.
Павел

@Pavel Это сработало два года назад, когда я это написал. Текущий онлайновый интерпретатор Pyth - это pyth.herokuapp.com. Если вы хотите запустить приведенный выше код, вы можете проверить интерпретатор тогда по адресу github.com/isaacg1/pyth , который имеет полную историю языка, контролируемую версией.
Исаак

3

Mathematica - 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

Mathematica, 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 не имеет остатка, поэтому 1s не осталось, и мы знаем, что наш первый трит :(0), поэтому мы заменим его:

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

Теперь у нас есть наше «одно место», поэтому мы знаем, что оставшиеся 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). Это занимает две trits ( +!), что означает, что у нас есть перенос. Как и в десятичной арифметике, это означает, что мы берем самую правую цифру и добавляем остаток к столбцу слева. В нашей системе это означает, что мы поместили !девятку и добавили еще три слева, а затем заменили все 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

8th , 179 171 167 символов

Здесь это полная программа в восьмом, которая принимает десятичное знаковое целое число в качестве входных данных и преобразует его в сбалансированную троичную

 
: 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

РЕДАКТИРОВАТЬ

Заменено 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.