Convert between balanced bases!

13

3

Balanced bases:

Balanced bases are essentially the same as normal bases, except that digits can be positive or negative, while in normal bases digits can only be positive.

From here on, balanced bases of base b may be represented as balb - so balanced base 4 = bal4.

In this challenge's definition, the range of digits in a balanced base of base b is from -(k - 1) to b - k, where

k = ceil(b/2)

Examples of the range of digits in various balanced bases:

bal10:
  k = ceil(10/2) = 5
  range = -(5 - 1) to 10 - 5 = -4 to 5
        = -4, -3, -2, -1, 0, 1, 2, 3, 4, 5
bal5:
  k = ceil(5/2) = 3
  range = -(3 - 1) to 5 - 3 = -2 to 2
        = -2, -1, 0, 1, 2

Representations of numbers in balanced bases is basically the same as normal bases. For example, the representation of the number 27 (base 10) to bal4 (balanced base 4) is 2 -1 -1, because

  2 -1 -1 (bal4)
= 2 * 4^2 + -1 * 4 + -1 * 1
= 32 + (-4) + (-1)
= 27 (base 10)

Task:

Your task is, given three inputs:

  • the number to be converted (n)
    • this input can be flexible, see "I/O Flexibility"
  • the base which n is currently in (b)
  • the base which n is to be converted to (c)

Where 2 < b, c < 1,000.

Return the number in balanced base c representation of n. The output can also be flexible.

The program/function must determine the length of n from the input itself.

I/O Flexibility:

Your input n and output can be represented in these ways:

  • your language's definition of an array
  • a string, with any character as a separator (e.g. spaces, commas)

Examples:

Note that these use a Python array as n and the output. You may use whatever fits your language, as long as it fits within "I/O Flexibility"'s definition.

[2, -1, -1] 4 7 = [1, -3, -1]
[1, 2, 3, 4] 9 5 = [1, 2, 2, -1, 2]
[10, -9, 10] 20 5 = [1, 1, 1, -2, 1, 0]

This is , so shortest code in bytes wins!

clismique

Posted 2017-01-11T04:24:58.773

Reputation: 6 600

In your first answer, 4 is not a legal bal7 digit; I believe the answer should be [1, -3, -1]. And I get different answers for the second test case ([1,2,2,-1,2]) and third test case ([1,1,0,-2,1,0]) as well...? – Greg Martin – 2017-01-11T05:42:53.137

@GregMartin Ah, whoops - I calculated those by hand, so there was bound to be some problems. Thanks for noticing! Can you double-check your solutions, just in case? – clismique – 2017-01-11T05:44:49.370

@GregMartin @Qwerp-Derp Third test case is [1,1,1,-2,1,0] – ngenisis – 2017-01-11T06:36:18.387

Answers

2

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.

JungHwan Min

Posted 2017-01-11T04:24:58.773

Reputation: 13 290

It's usually recommend to talk about your solution a little, and explain it for people who may not know Mathematica. – ATaco – 2017-01-12T01:34:28.047

@ATaco Added explanation! – JungHwan Min – 2017-01-12T03:20:36.850

I'm a little mystified by this. I've never seen optional patterns used anywhere but function definitions. You don't need the outer {...} since there's only one replacement rule. – ngenisis – 2017-01-12T03:34:44.520

@ngenisis Got rid of the extra {}. Thanks! – JungHwan Min – 2017-01-12T03:40:04.397

@ngenisis Well, function definition is actually a replacement rule too. For instance: f[x_] := 3 x; DownValues@f gives {HoldPattern[f[x_]] :> 3 x} – JungHwan Min – 2017-01-12T03:43:32.010

1@JungHwanMin True, I guess what's confusing me is how this affects the match for p___. Does this find the shortest p___ followed by either a_,b_ or b_, or does it check the whole pattern requiring each of the optional patterns and then progressively drop the optional patterns until it finds a match (or some third option)? – ngenisis – 2017-01-12T03:49:28.247

1@ngenisis I believe I was wrong in the previous comment (deleted), observing the result of FixedPointList[k=#3;#/.{p___,a_:0,b_,q___}/;b>⌊k/2⌋:>{p,a+1,b-k,q}&, #~FromDigits~#2~IntegerDigits~#3]&. {p___,a_,b_,q___} is matched first (for all possible p), and then {p___,b_,q___} is matched. The second replacement only applies when b is at the beginning because if there is a b in the middle that satisfies the condition, {p___,a_,b_,q___} would match it instead. – JungHwan Min – 2017-01-12T04:12:13.527

1

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.

smls

Posted 2017-01-11T04:24:58.773

Reputation: 4 352

1

JavaScript (ES6), 89 bytes

(n,b,c,g=(n,d=n%c,e=d+d<c)=>[...(n=n/c+!e|0)?g(n):[],e?d:d-c])=>g(n.reduce((r,d)=>r*b+d))

100 bytes works for negative values of n.

(n,b,c,g=(n,d=(n%c+c)%c)=>[...(n-=d,n/=c,d+d<c||(d-=c,++n),n?g(n):[]),d])=>g(n.reduce((r,d)=>r*b+d))

Neil

Posted 2017-01-11T04:24:58.773

Reputation: 95 035

0

Mathematica, 118 114 bytes

IntegerDigits[#3~FromDigits~#2,k=⌊#/2⌋;#]//.{{a_,x___}/;a>k:>{1,a-#,x},{x___,a_,b_,y___}/;b>k:>{x,a+1,b-#,y}}&

and are the 3-byte characters U+230A and U+230B, respectively. Converts #3 to base 10 from base #2, then converts to base # (so the argument order is reversed from the examples). If any digit is greater than the maximum allowed digit k=⌊#/2⌋, decrement that digit by # and increment the next digit up (may need to prepend 1). Keep doing this until all the digits are less than k.

ngenisis

Posted 2017-01-11T04:24:58.773

Reputation: 4 600