13
\$\begingroup\$

The title says it all; Given a number in the binary (base-2) number system, output the same number expressed in unary (base-1).

You should take the binary number as a string (optionally with a separator), list, or equivalent structure of digits, using any number or digit you like for the digits. The unary output can use any aforementioned format, and it should use a single-digit throughout the number but does not have to be consistent for different input values. You may choose to assume that the binary number will have no more than 8 bits, and/or that it will always be left-padded with zero bits to a certain length.

One method you may use to achieve this task is documented at this esolangs.org article:

  1. Replace all 1s with 0* (Using * as the unary digit; you may use any character.)
  2. Replace all *0s with 0**.
  3. Remove all 0s.

Here are some examples, using 0 and 1 for the binary digits and * for the unary digit:

  • 1001*********
  • 1010**********
  • 00111111***************************************************************
  • 00000 → (empty output)

This is , so the shortest answer in each language wins.

\$\endgroup\$
13
  • \$\begingroup\$ May the unary output be a mixture of multiple characters, instead of one distinct one (as long as its length is correct of course)? \$\endgroup\$ Aug 11, 2023 at 19:21
  • 2
    \$\begingroup\$ @KevinCruijssen I’m going to say no, since it doesn’t really feel like base-1 at that point. \$\endgroup\$
    – noodle man
    Aug 11, 2023 at 20:05
  • 1
    \$\begingroup\$ any reasonable input & output format I'm guessing taking the input as an integer is not acceptable, but it would be good to state it explicitly. \$\endgroup\$ Aug 11, 2023 at 22:26
  • 1
    \$\begingroup\$ In other words, a binary integer in a register is a normal way for a function to accept binary numbers as input, and the most obvious / simple / efficient. If you mean a base 2 string representation of a number, say that. I agree with @LevelRiverSt on this. Your examples are string-like, but that could be assumed to be catering to languages that don't natively have binary integer types. (e.g. Javascript, where numbers are floating-point, not binary integer.) Also, a string of 1-bit digits can be packed into a register (or C unsigned int); that's a good way to store binary! \$\endgroup\$ Aug 12, 2023 at 19:29
  • 1
    \$\begingroup\$ @PeterCordes Thanks for explaining, now I understand I didn’t quite account for that interpretation. Clarifying now. \$\endgroup\$
    – noodle man
    Aug 14, 2023 at 13:13

40 Answers 40

11
\$\begingroup\$

TypeScript's Type System, 130 128 bytes

//@ts-ignore
type R<S,F,X>=S extends`${infer A}${F}${infer B}`?R<`${A}${X}${B}`,F,X>:S;type B<S>=R<R<R<S,1,"02">,20,"022">,0,"">

Try it at the TypeScript Playground!

Uses 2 as the unary digit. Defines a utility type to recursively remove all occurrences of a given string with a different string, and then defines the main type which is a series of nested calls to the utility type.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Do you need //@ts-ignore? Seems like there's a warning, but not an error, given that it works with and without that ignore comment. Related: Untyped functions in static languages "As code compiles just fine without them, there is no need to add them in." \$\endgroup\$ Aug 14, 2023 at 3:45
  • \$\begingroup\$ @Samathingamajig This is the standard for TS submissions but it might make sense to change it \$\endgroup\$
    – noodle man
    Aug 14, 2023 at 13:05
10
\$\begingroup\$

Vyxal, 2 bytes

BI

Try it Online! or see it with asterisks instead

Same as my Thunno 2 answer.

Explanation

BI  # Implicit input
B   # From binary
 I  # That many spaces
    # Implicit output
\$\endgroup\$
1
9
\$\begingroup\$

Excel, 20 bytes

=REPT(9,BIN2DEC(A1))

Input in cell A1.

\$\endgroup\$
8
\$\begingroup\$

Haskell, 26 bytes

f l=10^foldl((+).(2*))0l-1

Try it online!

Input is a list of 0/1, output is a number like 9999999999 made of the digit 9.

Haskell is interesting for this challenge because it lacks base-conversion built-ins without imports, so we have to do it ourselves. This answer folds the operation \n b->n*2+b over the list of bits to get a number k, then computes 10^k-1 to get a number made of k 9-digits. The 9's trick is shorter than more natural methods like replicate k 1 or 1<$[1..k] or take k[0,0..].

It's slightly longer to do the power-of-10 within the fold and decrement after:

27 bytes

pred.foldl(\n b->n^2*10^b)1

Try it online!

though if we bend the rules and represent bits as 1 or decimal 10, we can do

21 bytes

pred.foldl((*).(^2))1

Try it online!

Haskell, 26 bytes

foldl(\s b->s++s++[1|b])[]

Try it online!

Input is list of Booleans, output is a list of 1's. This iterates over the list of Booleans, each time doubling the current string then appending an additional 1 if the bit is True.

\$\endgroup\$
1
  • \$\begingroup\$ I think using other things to represent the digits should be okay, so your 21 byte version is valid. \$\endgroup\$
    – noodle man
    Aug 12, 2023 at 6:29
6
\$\begingroup\$

Python 3, 21 bytes

lambda s:"*"*int(s,2)

Try it online!

\$\endgroup\$
5
\$\begingroup\$

APL (Dyalog Extended), 3 bytes

Anonymous tacit prefix function. Takes list of binary digits and returns list of 1s

⊥⍴≡

Try it online!

 the base-2 evaluation

reshapes

 the depth (nesting level, which is always 1 for a list)

\$\endgroup\$
5
\$\begingroup\$

TypeScript Type System, 79 bytes

type B<S>=S extends`${infer Q}${infer V}`?`${B<V>}${B<V>}${Q extends"1"?Q:""}`:S

Try it on the Typescript Playground!

Note: This works with little-endian binary, not big-endian.

While the algorithm in the post allows simply performing replacements, we can take advantage of Typescript's ability to anchor string matches for a much simpler algorithm.

Essentially, S extends`${infer Q}${infer V}` matches the first character Q and the rest of the string V. We recurse on V twice, and append a 1 if Q is a 1.

\$\endgroup\$
3
  • \$\begingroup\$ Wow, nice, good job! I totally missed this \$\endgroup\$
    – noodle man
    Aug 12, 2023 at 18:45
  • \$\begingroup\$ I can’t use the TS playground on the device I have access to right now, could you confirm this doesn’t hit the recursion limit for any 8-bit binary numbers? Thanks \$\endgroup\$
    – noodle man
    Aug 12, 2023 at 18:48
  • 2
    \$\begingroup\$ @noodleman While this has time complexity proportional to the size of the output, the recursive calls only go log(n) layers deep, so it wouldn't hit the recursion limit until 50-bit binary numbers (and it'd take multiple years to do that anyway) \$\endgroup\$
    – emanresu A
    Aug 12, 2023 at 20:49
5
\$\begingroup\$

x86+MMX machine code, 10 bytes

Despite the question only saying the input has to be "binary", comments seem to imply they're thinking of a text string of base-2 digits, not 1-bit digits packed into an integer which a computer can already use directly as an unsigned integer. If that's allowed, see my 7-byte answer on Output / Convert to unary number.

This is that answer plus conversion from 8 bytes to an 8-bit integer, by extracting the high bit of each input. Input is in mm0, an MMX vector register, with the lowest element being the least significant. (If stored to memory, this would be opposite of standard printing order where the most significant goes first, at the lowest address of a string.)

   ; machine code    |   NASM source
                       ; RDI or ES:EDI = output buffer of size n+1
                       binary_to_unary:
                       ;  pslld    mm0, 7     ; 4 bytes. For input digits '0' / '1', shift the low bit to high
  0FD7C8                pmovmskb ecx, mm0    ; pack the binary digits into an integer in ECX
                                             ; memset(dst, '1', n)
  B031                  mov      al, '1'
  F3AA                  rep stosb
  880F                  mov byte [rdi], cl   ; terminate the C-style string
  C3                    ret

For ASCII '0' / '1' input, we'd start with pslld mm0, 7 to shift the low bit to the high position of each byte. Also, if the digit-string was loaded from a string in memory in printing order (most significant at lowest address), we'd need to byte-reverse. In that case scalar code to read input would be smaller than movbe or load+bswap in an integer register + movq mm0, rax, or psufb with an 8-byte vector constant.

In this current version, our input string in an MMX register is effectively big-endian, most significant digit in the highest element number (on the left when writing it in the notation Intel manuals use to document vector instructions).

x86 scalar machine code, 14 bytes, input from a C string in printing order

  • RDI or ES:EDI points to an input buffer of base-2 ASCII digits, terminated by a 0 byte (or any byte below ASCII '0'), padded to at least 32 digits.
  • RSI or ES:ESI points to an output buffer of size n+1, will be filled with '0' digits and terminated with a 0.

Callable from C with the x86-64 System V calling convention as void binary_string_to_unary(const char *binary_src, char *unary_dst);. Use the x32 ABI for 32-bit pointers, or change the mov edi, esi to push rsi/pop rdi to copy a 64-bit register with the same code size. (Or use the same binary machine code in 32-bit mode.)

               binary_string_to_unary:
  B030           mov      al, '0'    ; input digit to compare against, also the output digit
               .loop:
  11C9           adc    ecx, ecx     ; ECX = 2*ECX + CF
  AE             scasb               ; set FLAGS like cmp al, [rdi] then increment RDI.   CF=1 for digit='1', CF=0 for digit='0'.
  76FB           jbe   .loop         ; while('0' <= digit);   i.e. while digit >= '0', false for digit = 0 terminator

  89F7           mov   edi, esi      ; x32 ABI, or for 32-bit mode.  For full 64-bit pointers, push rsi / pop rdi 
  F3AA           rep stosb           ; memset(rdi, al='0', rcx)
  880F           mov   [rdi], cl     ; terminate the C-style string
  C3             ret

Note that we don't xor ecx,ecx before the loop. Instead we rely on the input string being '0'-padded to at least 32 digits, so the previous contents get shifted out.

There might be a way (with same code size) to take the input pointer in RSI like you'd expect from the traditional meanings of those registers, perhaps with lodsb / cmp al, '0' (3 bytes instead of 1 for scasb, but avoiding the 2-byte mov edi, esi after the loop). Change the branch conditions accordingly for comparing in the other direction. Except that would get CF=0 for digit='1'. So maybe add al, 255-'0' so '1' produces a carry-out but '0' doesn't? And the terminator is a value that results in some FLAGS condition that the other two don't, perhaps a signed overflow and/or the sign flag.

\$\endgroup\$
3
  • \$\begingroup\$ Ah yes, this is what I came here for! \$\endgroup\$
    – Galaxy
    Aug 14, 2023 at 6:44
  • \$\begingroup\$ The question allows different unary characters for different inputs, but for implicit-length string output we need to avoid AL=0 for non-zero input. So I don't see a way to save the mov al, '1' or reduce it to 1 byte. Taking another input there and doing xchg eax, edi would be 1 byte, but would just swap in whatever garbage is there. salc with non-zero CF could work, or lahf to get non-zero AH if we were using stosw UTF-16 strings in 16-bit mode. (stosw takes 2 bytes in other modes.) \$\endgroup\$ Aug 14, 2023 at 17:04
  • \$\begingroup\$ @PeterCordes you should checkout the brainfuck question. I got to 104 bytes but would be cool to see what you come up with. \$\endgroup\$
    – Noah
    Aug 15, 2023 at 20:15
5
\$\begingroup\$

brainfuck, 53 bytes

Takes a string of 0 and 1 characters, outputs a string of 1s.

>,[>-[<->-----]<+++<[->++<]>>,]>-[<+>-----]<--<[->.<]

Explaination

>,[                 read a character
>-[<->-----]<+++    subtract 48 to turn it into 0/1
<[->++<]            double the existing sum and add it to the new digit
>>,]                read another character and repeat if not EOF
>-[<+>-----]<--     make 49
<[->.<]             print 49 the necessary number of times

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Golf, and nice answer! \$\endgroup\$ Aug 16, 2023 at 4:10
4
\$\begingroup\$

Husk, 3 bytes

B1ḋ

Try it online!

  ḋ  # interpret input as binary digits
B    # and convert this to base
 1   # 1
\$\endgroup\$
3
\$\begingroup\$

Mathematica, 14 bytes

As a list of '1's:

Table[1,2^^#] &

Anonymous function. Would probably be 10 bytes in the hypothetical mthmca golfing language.

\$\endgroup\$
3
  • \$\begingroup\$ The output can be a list. Also, the character doesn't have to be "*" if using, say, a digit, would be shorter. \$\endgroup\$
    – noodle man
    Aug 11, 2023 at 16:37
  • \$\begingroup\$ @noodleman Thanks. Revised accordingly and saving 13 bytes. \$\endgroup\$ Aug 11, 2023 at 16:40
  • \$\begingroup\$ What version does this work in? AFAIK ^^ only works in number literals. \$\endgroup\$
    – att
    Sep 3, 2023 at 7:55
3
\$\begingroup\$

TI-Basic, 15 bytes

1 or rand(.5sum(Ans2^cumSum(1 or Ans

Input is taken as a list of 0s and 1s in little-endian binary in Ans. Output is a list of 1s.

\$\endgroup\$
3
\$\begingroup\$

Perl 5, 15 bytes

$_=9x oct"0b$_"

Try it online!

Outputs 9 (my chosen char) the number of times given in the input binary number.

\$\endgroup\$
3
\$\begingroup\$

R, 22 bytes

\(x)rep(1,strtoi(x,2))

Attempt This Online!

Convert from binary and repeat 1 that many times.

Unfortunately shorter than the more-interesting (I think):

R, 36 34 bytes

Edit: -2 bytes thanks to pajonk

\(x)Reduce(\(a,b)c(a,a,b[b]),x,{})

Attempt This Online!

Input is a vector of binary digits; fold over (Reduce) this from the left, starting with an empty vector (NULL), at each step duplicating whatever we've got so far, and appending the new digit if it's a 1.

\$\endgroup\$
2
  • \$\begingroup\$ -2 on the second one by using {} for the empty vector. \$\endgroup\$
    – pajonk
    Aug 12, 2023 at 12:43
  • \$\begingroup\$ @pajonk - Ah, yes, thanks! \$\endgroup\$ Aug 12, 2023 at 13:23
3
\$\begingroup\$

Ruby, 20 bytes

->(b){?**b.to_i(2)} 

Try it online!

It goes from binary to a decimal integer, and becomes a factor by which an asterisk char is multiplied.

(Idea to switch to char from string was suggested by Travis. Thanks!)


Ruby, 21 bytes | (old)

->(b){"*"*b.to_i(2)} 

Try it online!

Same as the upper one, but the upper one has been improved.

\$\endgroup\$
3
  • \$\begingroup\$ Welcome to Code Golf, and nice answer! \$\endgroup\$ Aug 12, 2023 at 17:47
  • \$\begingroup\$ Thank you! Glad to be here :) \$\endgroup\$
    – kait0u
    Aug 12, 2023 at 18:03
  • 1
    \$\begingroup\$ You can remove a byte by using ?* for "*" instead of quotes. \$\endgroup\$
    – Travis
    Aug 14, 2023 at 16:28
3
\$\begingroup\$

C (clang), 60 58 bytes

i;f(char*s){for(i=0;*++s;i+=i+*s-48);i&&printf("%0*d",i);}

Attempt This Online!

\$\endgroup\$
3
  • \$\begingroup\$ It feels like there should be a way to omit the ,0 arg to printf and just have it print whatever garbage was left. Or just spaces? But printf("%*c",i) prints a byte of garbage at the end, and we probably can't consider that a "terminator". Perhaps for(;i--;)puts(""); to use newline as the unary character? \$\endgroup\$ Aug 14, 2023 at 22:44
  • \$\begingroup\$ Or if you want to write a function that returns a string instead of printing, perhaps memset(s,7,i);s[i]=0; to replace the input string with that many ASCII "BEL" characters and a terminator, but that might not be shorter. Or memset(...); return i; for an explicit-length string. (And relies on the caller to allocate a large enough buffer without having parsed the string of binary digits, so only a larger fixed-size buffer could work.) \$\endgroup\$ Aug 14, 2023 at 22:47
  • 1
    \$\begingroup\$ @PeterCordes Good ideas, but I only managed to get the first one to work (leaving off ,0). Thanks anyways! \$\endgroup\$
    – corvus_192
    Aug 16, 2023 at 18:11
2
\$\begingroup\$

JavaScript (Node.js), 21 bytes

x=>'x'.repeat('0b'+x)

Try it online!

\$\endgroup\$
0
2
\$\begingroup\$

J, 4 or 5 bytes

#.##

Uses the length of the input digit list for the unary digit.

Attempt This Online!

Like 05AB1E, uniformity is one extra byte, with alternatives.

\$\endgroup\$
2
\$\begingroup\$

PowerShell, 28 bytes

"*"*[Convert]::ToInt32($_,2)

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Kotlin, 22 bytes

{"*".repeat(toInt(2))}

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Thunno 2, 2 bytes

Ḃṣ

Try it online! or see it with asterisks instead

Uses spaces.

Explanation

Ḃṣ  # Implicit input
Ḃ   # From binary
 ṣ  # That many spaces
    # Implicit output
\$\endgroup\$
1
\$\begingroup\$

Charcoal, 3 bytes

⍘S²

Try it online! Link is to verbose version of code. Outputs a string of -s. Explanation:

 S  Input string
⍘   Convert from base
  ² Literal integer `2`
    Print as row of `-`s

Unfortunately BaseString(2, InputString()) performs a different operation, which means I can't use implicit input to save a byte.

\$\endgroup\$
1
\$\begingroup\$

Arturo, 23 bytes

$=>[@.of:from.binary&1]

Try it!

Returns a list of digits.

$=>[             ; a function where input is assigned to &
    from.binary& ; convert input from binary string to decimal integer
    @.of: _ 1    ; create list of that many 1s
]                ; end function
\$\endgroup\$
1
\$\begingroup\$

Retina 0.8.2, 16 bytes

1
01
+`10
011
0

Try it online! Link includes test cases. Explanation: A direct interpretation of the method given in the question, except using 1 instead of * for obvious reasons. Note that the method in Retina's own tutorial is slightly different preferring to use ^0+ presumably for a slight performance improvement.

\$\endgroup\$
1
\$\begingroup\$

MathGolf, 3 bytes

Some different alternatives are available:

  • Output as *s: å⌂*; åÄ⌂; å{⌂.
  • Output as spaces: å *; åÄ ; å{ .
  • All six above should have been also possible with a binary-list instead of binary-string as input, replacing the å with ä, but unfortunately there seems to be a bug with leading 0s apparently.. - Try ä⌂* online.

Explanation:

å    # Convert the (implicit) input binary-string to a base-10 integer
 ⌂*  # Repeat that many "*" as string
  *  # Or alternatively, repeat that many spaces as string
     # (after which the entire stack is output implicitly as result)

å    # Convert the (implicit) input binary-string to a base-10 integer
 Ä   # Pop and loop that many times, using the following character as inner code-block:
 {   # Or alternatively, use everything after it as code-block:
  ⌂  #  Push an "*" to the stack every iteration
     #  Or alternatively, push a space character to the stack every iteration
     # (after which the entire stack is joined together and output implicitly as result)
\$\endgroup\$
1
\$\begingroup\$

PHP, 32 bytes

echo str_repeat('*',bindec($i));

Where $i is the input string.

\$\endgroup\$
1
\$\begingroup\$

05AB1E, 3 bytes

Since outputting the unary as a single character is required, there are a couple of 3 bytes alternatives:

If a mixture of multiple characters for the unary output would have been allowed, since only the length matters in unary, it could have been 2 bytes with:

C∍

Outputs a mixture of 1s and 0s (depending on the input) for its unary output.

Try it online or verify all test cases.

Explanation:

C   # Convert the (implicit) input binary-string to a base-10 integer
 ð× # Pop and push a string with that many spaces
    # (after which the result is output implicitly)
  
$   # Push 1 and the input binary-stringC×
Î   # Or alternatively, push 0 and the input binary-string
 C  # Convert the binary-string to a base-10 integer
  × # Repeat the 1 or 0 that many times as string
    # (after which the result is output implicitly)

C   # Convert the (implicit) input binary-string to a base-10 integer
 Å9 # Pop and push a list with that many 9s (or any other digit)
    # (after which the result is output implicitly)
C   # Convert the (implicit) input binary-string to a base-10 integer
 ∍  # Extend/shorten the (implicit) input binary-string to that length
    # (after which the result is output implicitly)
\$\endgroup\$
1
\$\begingroup\$

///, 18 bytes

/1/0*//*0/0**//0//

Try it online!

I didn't write this, I borrowed it from the esolangs wiki. Here's how it works:

Let's start with the string 10101, which represents 21.

/1/0*/ replaces 1s with 0*. The string becomes 0*00*00*. In this, each * represents a sort of place value - for example, the first * has 4 0s after it, so it represents 24 = 16.

/*0/0**/ replaces each * before a zero with two copies of it after the zero, each with half the place value. The first replacement this would do would be replacing 0*00*00* with 00**0*00*, replacing a * representing 16 with 2 *s each representing 8.

In ///, replacements are repeated until nothing is left to replace, so this will eventually result in a string with some amount of 0s at the start, followed by 21 *s each representing 1.

Finally, /0// removes the leading zeros, leaving just 21 *s, which is the output in unary.

\$\endgroup\$
1
\$\begingroup\$

sed 4.2.2, 28

:
s/1/0u/
s/u0/0uu/
t
s/0//g

Implementation algorithm as per the question.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

dc, 17

[q]sz2iA?^9/d0=zn

Try it online!

Explanation

[ ]                # define a macro to...
 q                 #   quit (i.e. print the empty string)
   sz              # save the macro to register z
     2i            # set input radix to 2 (binary)
       A           # pop 10
        ?          # read input
         ^         # exponentiate 10 to the power of the input
          9/       # divide by 9.  This gives a number consisting of n 1s, or 0
            d      # duplicate top of stack
             0=z   # if equal to 0, call macro stored in z register to print the empty string
                n  # otherwise print the unary number
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.