Excel, 136 bytes
=LET(s,ROW(1:1024),r,s-1,t,TRANSPOSE(s),p,""&2^r,m,IF(t+r>LEN(A1),,MID(A1,s,t)),TEXTJOIN(",",,IFERROR(m*1^MATCH(IF(--m=A1,,m),p,0),"")))
Input is in cell A1 and is limited to 308 digits long since 2^1023 = 8.99e+307 and that's the highest value Excel can handle in that series.
It's a fairly long formula but LET()
allows us to break it into chunks of variable, value
except for the last term which is the output.
s,ROW(1:999)
creates a vertical array of values 1-1024.
r,s-1
offsets that array by 1. This is a wash on bytes vs. using s-1
directly later but it does make the formula look nicer.
t,TRANSPOSE(s)
creates a horizontal array of values 1-1024.
p,""&2^r
creates an array of string values from 2^0 to 2^1023. It's important later on that these are strings and not numbers.
m,IF(t+r>LEN(A1),,MID(A1,s,t))
creates a triangular array of all the various substrings (and also the entire string but that'll get ignored later). For the input of 13248
, that looks like this:
(This is just the top left corner since most of the 1024x1024 table is 0
.)
That's all the variables we define. The last term is the output so we'll break that down bit by bit.
TEXTJOIN(",",,IFERROR(m*1^MATCH(IF(--m=A1,,m),p,0),""))
IF(--m=A1,,m)
let's us ignore the entire input even if it's a power of 2. For instance, 32
. I could have required the input be a string and then drop the --
here to convert the string m
to a number, but Excel defaults to things that look like numbers being numbers and it's worth 2 bytes (to me) to not require funky inputs.
MATCH(IF(--m=A1,,m),p,0)
tries to find an exact match for the m
value in the powers of 2 array. If it doesn't find a match, this will equal #N/A
. This is the part that makes it important for the powers to be strings. If we converted m
to numbers and matched those, them string like 02
would resolve to be just 2
so they would match. Something line 102
would return 1,2,2
instead of just 1,2
.
m*1^MATCH(~)
multiplies m
by either 1
or #N/A
.
IFERROR(~,"")
converts all the errors to blanks. For the input of 13248
, that looks like this:
TEXTJOIN(",",,IFERROR(~))
concatenates all the values with a comma between each term.
The screenshot below shows the formula in B1
, the results for all the test cases, and the snippets showing partial results for input 13248
that are also shown above.