平衡三元转换器


32

有关挑战构想的功劳归@AndrewPiliser。他最初在沙盒中的提议被放弃了,因为他已经几个月没有活跃在这里了,所以我已经接受了挑战。

平衡三进制是非标准数字系统。这就像在数字的3倍的价值增加,因为你进一步去左边三元-所以10091001是28。

但是,数字的值为-1、0和1而不是0、1和2 。(您仍然可以使用它来表示任何整数。)

对于此挑战,数字含义+1将被写为+-1将被写为-,并且0是just 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

哦,等等,我刚刚注意到在平衡打法上有一个问题 -这是重复的吗?

正如我在沙盒中提到的那样,我认为它更接近于有关标准鸟巢表示的挑战。但这可能不是两者的重复。
Martin Ender 2014年

Answers:


22

Python 2:58个字符

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

从末尾逐位生成平衡的三进制。最后一个数字是由残留给出n%3之中-10+1。然后,我们删除最后一位数字,并使用Python的floor-divide除以3 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 2014年

@MartinBüttnerPyth的较长答案只是由于使用了非最佳算法。
Optimizer

@Optimizer好吧,显然,这就是为什么我赞成首先获得更好算法的Python答案。:P
Martin Ender 2014年

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 2014年

@isaacg尝试一下;)
Optimizer

CJam部门的四舍五入是否有所不同?
isaacg 2014年

@isaacg-舍入-不。CJam整数除法不舍入。它
Optimizer

但是要降到零还是-inf?
isaacg 2014年

6

JavaScript(E6)68

根据要求的完整程序,通过弹出窗口具有I / O。R函数的核心是49字节。

我猜想与其他递归解决方案没什么不同。利用字符串和数字之间的自动转换来避免“ 0”的特殊情况

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

仅使用R函数在FireFox / FireBug控制台中进行测试

['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 '16

6

佩斯,71 24 23

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

This is a recursive solution, based on @xnor's 40 character recursive function. y constructs the baanced ternary of the input, by finding the last digit using the mod 3 index, and then uses the fact that the rest of the digits are equal to the balanced ternary for (n+1)/3, using floored division. Then, it calls the function, returning the result, or 0 if the input is 0.

Try it here.


Is there an online Pyth interpreter?

There is, I'll add it to the post.
isaacg

Your link is broken. I reccomend Try it online!, which you will use from now on whenever you need an interpreter for anything. By the way, your code appears to not work, for me it just return the input.
Pavel

@Pavel It worked two years ago, when I wrote it. The current online Pyth interpreter is pyth.herokuapp.com If you want to run the above code, you can check out the interpreter from back then from github.com/isaacg1/pyth , which has a complete version controlled history of the language.
isaacg

3

Mathematica - 157 154 146 128

The golfed version:

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

And with indentation for legibility:

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

Usage:

f[414]

Output:

+--0+00

Many thanks to Martin Büttner in reducing the number of characters.


3

Mathematica, 54 characters

Similar to xnor's recursion

Unicode symbols are used to replace Floor,Part,!=

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

Output

Stored as f for brevity and written without unicode incase you can't view

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

Try it online!

Explanation

The first half of the code (less the first line) translates decimal to unary and comes straight from "Tips for golfing in sed." Then it translates unary to balanced ternary one trit at a time, which I'll demonstrate by working an example manually.

最终输出之前,三元位数-0+由下式表示!:+分别。

为了获得有趣的结果,我们从开始-48,将其转换为一元(-完整无缺)。要计算第一个(最右边的)三重奏,我们必须计算其余的48÷3。我们可以通过将111s 替换为s来实现3

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

48÷3没有余数,所以也没有余数,1我们知道我们的第一个trit是:(对于0),因此我们将其替换:

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

现在我们有了“一个地方”,因此我们知道其余的3s代表三个地方。为了使数学有效,我们必须将它们除以3,即用1s 代替它们:

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

Let's double-check our math: We have 16 (unary 1111111111111111) in the threes place and zero (:) in the ones place. That's 3✕16 + 1✕0 = 48. So far so good.

Now we start again. Replace 111s with 3s:

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

This time our remainder is 1, so we put + in the threes place and replace the remaining 3s with 1s:

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

Sanity check time: We have a 5 (unary 11111) in the nines place, 1 (+) in the threes place, and 0 (:) in the ones place: 9✕5 + 3✕1 + 1✕0 = 48. Great! Again we replace the 111s with 3s:

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

这次我们的余数是2(11)。这需要两个trits(+!),这意味着我们有一个进位。就像十进制算术一样,这意味着我们采用最右边的数字并将其余部分添加到左侧的列中。在我们的系统中,这意味着我们将放!第九个位置,并在其左边再添加三个,然后将所有3s 替换为1s来代表第27个位置:

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

现在我们没有3了,因此我们可以用任何剩余的一进制数字替换其对应的Trit。两个(11)为+!

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

在实际代码中,分两个步骤完成,s/1/+/y/1:/!0/以节省字节。第二步还将:s 替换为0s,因此实际上是这样的:

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

Now we check if we have a negative number. We do, so we have to get rid of the sign and then invert each trit:

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

Finally, we replace !s with -s:

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

That's it!


2

Stax, 17 bytes

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

Run and debug it

Shortest answer so far, but should be easily beaten by some golfing languages. The algorithm is the same as @xnor's Python answer.

ASCII equivalent:

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

1

JavaScript 108 102 (ES6, no recursive calls)

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}

Original entry at 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}

Not as fancy as @edc65's answer... I'd appreciate any help reducing this further...


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

Is this the longest Clojure answer so far?

取消高尔夫(带评论):

(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

第八名179 171 167 characters

这是第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,327269个字符

我第一次尝试打高尔夫球。我不知道那些真正的短语言,所以这里是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

编辑

替换BufferedReaderScanner,允许我删除throws子句,但必须更改import(+2个字符)。替换Integerint。不幸的是,如果没有程序将无法编译String[] hmain


1
您可能可以使用Scanner而不是来节省一些字节BufferedReader。此外,String[] hthrows 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(character)为true,则将字符串(character +“ 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

如果使用⊥则可能会更少,但禁止使用...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.