Convert between balanced bases!

Mathematica, 85 bytes

#~FromDigits~#2~IntegerDigits~#3//.{p___,a_:0,b_,q___}/;b>⌊#3/2⌋:>{p,a+1,b-#3,q}&

Explanation

#~FromDigits~#2

Convert #1 (1 is implied--input 1, a list of digits) into an integer base #2 (input 2).

... ~IntegerDigits~#3

Convert the resulting integer into base #3 (input 3), creating a list of digits.

... //.{p___,a_:0,b_,q___}/;b>⌊#3/2⌋:>{p,a+1,b-#3,q}

Repeatedly replace the list of digits; if a digit is greater than floor(#3/2), then subtract #3 from it and add 1 to the digit to the left. If there is nothing on the left, insert a 0 and add 1.


APL (Dyalog Unicode), 47 bytes

{z↓⍨⊥⍨0=⌽z←m+u⊤v-⍺⊥m←⌈.5×1-u←⍺⍴⍨1+⌈⍺⍟1⌈|v←⍺⍺⊥⍵}

Try it online!

A dop that takes n, b, c as three separate values. Call it like c (b f) n where f is the submission.

Dyalog APL has a dfns library function bt that does various arithmetic in balanced ternary. Part of it is encode/decode, i.e. conversion between balanced ternary and plain integer:

encode←{                            ⍝ balanced ternary from integer.
    digs←1+⌈3⍟1⌈|⍵                  ⍝ number of ternary digits.
    tlz ¯1+(digs⍴3)⊤⍵+3⊥digs⍴1      ⍝ vector of bt digits.
}                                   ⍝ :: ∇ num → bt
decode←{3⊥⍵}                        ⍝ integer from balanced ternary.

(the hidden function tlz trims leading zeros.)

This submission is just a generalization of the above code.

Ungolfed with comments

{                    ⍝ Input: ⍵←n, ⍺⍺←b, ⍺←c
    v←⍺⍺⊥⍵           ⍝ v← plain integer from base b

    u←⍺⍴⍨1+⌈⍺⍟1⌈|v   ⍝ u← copies of c with the size enough to fit the answer
              1⌈|v   ⍝ max(1,abs(v)) so that it works well with log(⍟)
           ⌈⍺⍟       ⍝ number of digits enough to fit v in plain base c
         1+          ⍝ ...enough to fit v in balanced base c
      ⍺⍴⍨            ⍝ that many copies of c

    m←⌈.5×1-u    ⍝ m← the minimum value in balanced base c with that many digits

    z←m+u⊤v-⍺⊥m  ⍝ z← n in balanced base c, possibly with leading zeros
            ⍺⊥m  ⍝ m as plain integer
          v-     ⍝ subtract from v (or, since m<0, add abs(m) to v)
        u⊤       ⍝ encode that value to plain base c, with that many digits
      m+         ⍝ revert the offset

    z↓⍨⊥⍨0=⌽z    ⍝ remove leading zeros from z and return it
       ⊥⍨0=⌽z    ⍝ count trailing zeros (⊥⍨) on reversed z
    z↓⍨          ⍝ drop that many items from z
}

Perl 6, 121 bytes

->\n,\b,\c{sub f{sum [R,](@^n)Z*($^b X**0..*)}
first {f(b,n)==f c,$_},map {[$_-($_>floor c/2)*c for .base(c).comb]},0..*}

Slow brute-force solution.

How it works:

  • map {[ .base(c).comb]}, 0..* -- Generate the lazy infinite sequence of natural numbers in base c, with each number represented as an array of digits.
  • $_ - ($_ > floor c/2) * c -- Transform it by subtracting c from each digit that is greater than floor(c / 2).
  • first { f(b, n) == f(c, $_) }, ... -- Get the first array of that sequence which when interpreted as a base c number, equals the input array n interpreted as a base b number.
  • sub f { sum [R,](@^n) Z* ($^b X** 0..*) } -- Helper function that turns an array @^n into a number in base $^b, by taking the sum of the products yielded by zipping the reversed array with the sequence of powers of the base.