# Not Quite Roman Ternary

Given an integer n ≥ 0 , output it in a non-positional base-3 notation, using digits 139ABCDE… and a 1-character separator. Every digit is a consecutive power of 3 and the digits on the left side of the separator are negated, e.g. A931|B → 81−(1+3+9+27) → 41. A digit may appear only once.

Rigorously, let the value of a digit be:

• its value if the digit is 1, 3 or 9
• 27 if the digit is A
• 3 times the value of the digit right before it for B..Z

Your output should satisfy sum(value of digits to the right of |) - sum(value of digits to the left of |) == input .

### Examples

input     output
----------------
0         |
1         |1
7         3|91
730       |D1
9999      FEDC|GA9


You may use a different non-space character as a separator. You are also allowed to have no separator, in which case the largest digit starts the positive sequence. You don’t need to handle anything larger than 232−1 (PMIGDCBA9|RQNLH3).

You may write a full program or function, and input and output may be provided on any of the usual channels.

• (related doesn't mean duplicate, calm down) Mar 28 '18 at 13:47
• Am I the only one who has no clue what's being asked here? Mar 28 '18 at 13:47
• @Shaggy Express the input as a sum of powers of 3 and their negatives. Put the negatives left of a | and the positives to the right of it. Mar 28 '18 at 13:48
• @KevinCruijssen "no, the order is free." -- OP Mar 28 '18 at 15:39
• @user202729 Ah, missed that comment. Thanks. That's what happens when rules are in the comments instead of edited into the challenge.. (FrownyFrog, could you add that rule to the challenge: either order on either side of the delimiter is fine?) Mar 28 '18 at 15:51

# Java 10, 120113112109107102 92 bytes

n->{var r="|";for(var c='1';n++>0;c+=c>64?1:c*4%22%9,n/=3)r=n%3<1?c+r:n%3>1?r+c:r;return r;}


-3 bytes by using part of the trick of @Arnauld's JavaScript (ES6) answer,
changing i=0 and i++<1?49:i<3?51:i<4?57:i+61 to i=4 and ++i>9?i+55:i>8?57:++i+43.
-6 bytes thanks to @Arnauld directly, by getting rid of i.
-10 bytes thanks to @ceilingcat.

Order of output: Highest-to-lowest, |-delimiter, lowest-to-highest.

Explanation:

Try it online.

n->{              // Method with integer parameter and String return-type
var r="|";      //  Result-String, starting at the delimiter "|"
for(var c='1';  //  Character, starting at '1'
n++>0       //  Loop as long as n is larger than 0
//  Increasing it by 1 with n++ at the start of every iteration
;           //    After every iteration:
c+=        //     Change character c to:
c>64?   //      If the current c is an uppercase letter:
1  //       Simply go to the next letter using c+=1
:   //      Else:
c*4%22%9,
//       Change '1' to '3', '3' to '9', or '9' to 'A'
n/=3)      //     Integer-divide n by 3
r=           //   Change the result to:
n%3<1?     //    If n modulo-3 is 0:
c+r       //     Prepend the character to the result
:n%3>1?    //    Else-if n modulo-3 is 2:
r+c       //     Append the character to the result
:          //    Else (n modulo-3 is 1):
r;        //     Leave r unchanged
return r;}     //  Return the result-String

• I think this works: 103 bytes Mar 29 '18 at 9:59
• @Arnauld Nice one! And -1 more byte by putting r in the loop body. Thanks! Mar 29 '18 at 10:06
• @Arnauld Out of curiosity, what does the brute-forcers look like you've used for these last two magic numbers (when you still used i, and when you re-use c)? Mar 29 '18 at 10:11
• I've already thrown it away ... :-/ But here is the last one. (Very inefficient, but that's OK for such small values.) Mar 29 '18 at 10:22
• (Also, I really should test whether p=1 and don't include *1 in the code if it is -- even though it doesn't lead to a better formula in that case.) Mar 29 '18 at 10:30

# Python 3, 10399 91 bytes

4 bytes thanks to Lynn.

8 bytes thanks to ovs.

def f(n,s="|",b=0):c=('139'+chr(b+62)*b)[b];return n and f(-~n//3,[s,s+c,c+s][n%3],b+1)or s


Try it online!

Credits to xnor for the logic.

# JavaScript (ES6), 8280 79 bytes

Outputs in lowercase, which should hopefully be fine.

f=(n,s=(k=4,'|'),c=++k>8?k.toString(36):++k-5)=>n?f(++n/3|0,[c+s,s,s+c][n%3]):s


Try it online!

Similar to Leaky "Ninja Master" Nun's answer and also based on xnor's answer.

### Digit conversion

We start with k = 4. While k is less than 9, we increment it twice at each iteration and subtract 5. After that, we increment it only once and convert it to base-36.

  k  | ++k > 8       | k.toString(36) | ++k - 5  | result
-----+---------------+----------------+----------+--------
4  | k=5  -> false |                | k=6 -> 1 | 1
6  | k=7  -> false |                | k=8 -> 3 | 3
8  | k=9  -> true  | '9'            |          | '9'
9  | k=10 -> true  | 'a'            |          | 'a'
10 | k=11 -> true  | 'b'            |          | 'b'
... | ...           | ...            | ...      | ...


# Jelly, 26 bytes

‘:3Ɗ⁹Ð¡‘%3ẹÐ€0,2ị139D;ØA¤Y


Try it online!

Use a newline as the separator.

• 26 bytes Mar 29 '18 at 0:53
• 25 bytes Mar 29 '18 at 0:56

# Perl 6, 80 bytes

{map({|(1,3,9,|('A'..'Z'))[grep :k,*%3==$^v,($_,-+^*div 3...0)]},1,2).join.flip}


Try it online!

No separator. Based on xnor's answer.

# Stax, 30 29 bytes

£└≤☻╘pÿ╖╡A[ô%æτ⌐}►ºôßHl4⌡π%^


Run and debug it

Port of my Stax answer in Balanced Ternary Converter.

## Explanation

Uses the unpacked version to explain.

139$VA+cz{;3%+,^3/~;wY1|I@'|ay2|I@L 139$VA+c                               "139AB...Z", make a copy
z                              Empty array to store the digits
{         w                  Do the following until 0.
;3%+                           Append b%3 to the digits
Originally, b is the input
,^3/                        b=(b+1)/3
~;                       Make a copy of b which is used as the condition for the loop

Y                 Save array of digits in y for later use
1|I              Find index of 1's
@             Find the characters in "139AB...Z" corresponding to those indices
'|           A bar
ay2|I@     Do the same for 2's
L    Join the two strings and the bar and implicit output


('931',~u:90-i.26){~0(>,&I.<)(29$3)((+1&|.-3&*)]-*)^:_@#:]  Try it online! # Perl 5-p, 71 69 bytes uses no separator. The negative and positive parts are in "roman order" (largest digit first) #!/usr/bin/perl -p$n=$_}{s/@{[$n++%3]}\K/]/,$n/=3,y/?-]/>-]/for($_=21)x31;y/>?@12/139/d


Try it online!

# Ruby, 8784 82 bytes

Saved 2 bytes thanks to @benj2240.

->n,s=[?1,?3,?9,*?A..?Z],r=[""]*3{r[-m=n%3]+=s.shift
n=n/3+m/2
n>0?redo:r[1,2]*?|}


Try it online!

• I'd be lying if I said I'm completely following this code, but I do know you shave off 2 bytes with the redo trick: Try it online! Mar 28 '18 at 22:26

# J, 129 bytes

f=:3 :0
a=.'139',u:65+i.26
s=.'|'while.y>0 do.if.1=c=.3|y do.s=.s,{.a end.y=.<.y%3
if.c=2 do.s=.s,~{.a
y=.1+y end.a=.}.a end.s
)


Try it online!

Too lengthy, especially for a J program...

## Explanation:

f =: 3 : 0
a =. '139',u:65+i.26   NB. a list '139ABC...Z'
s =. '|'               NB. initialize the list for the result
while. y>0 do.         NB. while the number is greater than 0
c =. 3|y            NB. find the remainder (the number modulo 3)
y =. <.y%3          NB. divide the number by 3
if. c = 1 do.       NB. if the remainder equals 1
s =. s,{.a       NB. Append the current power of 3 to the result
end.
if. c = 2 do.       NB. if the remainder equals 2
s =. s,~{.a      NB. prepends the result with the current power of 3
y =. 1+y         NB. and increase the number with 1
end.
a =. }.a            NB. next power of 3
end.
s                      NB. return the result
)


# C, int: 138 123 bytes, long: 152 131 bytes

I have created two versions of this, as the challenges' limit of a working max input of 0x100000000 seemed a bit odd. One version works with 32 bit integers (which fails the limit for obvious reasons), the other version works with 64 bits (which goes way beyond the given limit, at the cost of 14 8 extra bytes).

32 bit version:

char b[22],*r=b;f(v,l)char*l;{v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}


64 bit version:

char b[22],*r=b;f(long v,char*l){v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(long v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}


This is identical except that it declares the integer variable to be long (which is 64 bits on linux).

The ungolfed long version:

char buffer[22],*result=buffer;
f(long value,char*letter){
if(value%3>1){
*result++=*letter,value++;
}
if(value){
f(value/3,letter+1);
}
if(value%3){
*result++=*letter;
}
}
g(long value){
f(value,"139ABCDEFGHIJKLMNOPQR");
*result=0;
result=buffer;
}


As you can see, this works by recursive decent: If the remainder is 1, the respective character is appended to the output string after the recursive call. If the remainder is 2, the output is performed before the recursing. In this case, I also increment the value by one to handle the negative digit correctly. This has the added benefit of changing the remainder to zero, allowing me to use value%3 as the condition for the post-recursion if.

The result of the conversion is placed into the global buffer. The g() wrapper has the job of zero terminating the resulting string correctly, and to reset the result pointer to its start (which is also how g() "returns" the result).

Test the long version with this code:

#include <stdio.h>

char b[22],*r=b;f(long v,char*l){v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(long v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}

void printConversion(long value) {
g(value);
printf("%ld: %s\n", value, r);
}

int main() {
for(long i = 0; i <= 40; i++) {
printConversion(i);
}
printConversion(0x7fffffff);
printConversion(0xffffffffu);
printConversion(0x100000000);
}


Possible further, but destructive golfing:

• -4 bytes: make the function a one-shot by removing the pointer reset in g().

• -5 bytes: force the caller to perform the string termination, returning the string without termination in buffer, and the end of the string in result.

# Charcoal, 36 bytes

ＮθＦ³⊞υ⟦⟧Ｆ⁺139α«⊞§υθι≔÷⊕θ³θ»Ｆ²«×|ι↑⊟υ


Try it online! Link is to verbose version of code. Explanation:

Ｎθ


Input the value.

Ｆ³⊞υ⟦⟧


Push three empty lists to the predefined empty list.

Ｆ⁺139α«


Loop through the characters 139 and the uppercase alphabet.

⊞§υθι


Cyclically index the list of lists with the value and push the current character to it.

≔÷⊕θ³θ»


Divide the value by 3 but round it by adding 1 first.

Ｆ²«×|ι


Loop twice. The second time, print a |.

↑⊟υ


Each loop we pop the last entry from the list; the first time this gives us the entries that had a remainder of 2 (which corresponds to a balanced ternary digit of -1), while the second time this gives us the entries corresponding to a balanced ternary digit of 1. The resulting array would normally print vertically, but rotating the print direction upwards cancels that out.

# C# .NET, 103 100 bytes

n=>{var r="|";for(var c='1';n++>0;c+=(char)(c>64?1:c*4%22%9),n/=3)r=n%3<1?c+r:n%3>1?r+c:r;return r;}


-3 bytes thanks to @ceilingcat.

Port of my Java 10 answer. If a direct port (except for n-> to n=>) would have been possible, I would have edited my Java answer with this polyglot. Unfortunately however, having c=49 isn't possible in C#, nor the c+= without (char) cast, hence this loose ported answer.

Try it online.

# Perl 5, 92 89 bytes

Inspired by the java and python answers.

sub n{($n,$r,$c,@a)=(@_,'|',1,3,9,'A'..'Z');$n?n(int++$n/3,($c.$r,$r,$r.$c)[$n%3],@a):$r}


Try it online!

With some white space:

sub n {
($n,$r, $c, @_) = (@_, "|", 1, 3, 9, 'A' .. 'Z');$n ? n( int++$n/3, ($c.$r,$r, $r.$c)[$n%3], @_) :$r
}


# PHP, 73 bytes

for(;0|$n=&$argn;$n/=3)${$n++%3}.=_139[++$i]?:chr(61+$i);echo${2},_,${1};  ## port of xnor´s answer, 53 bytes for(;0|$n=&$argn;$n/=3)$s="0+-"[$n++%3].$s;echo$s??0;


Run as pipe with -nr or try them online.