32
\$\begingroup\$

Challenge

Write a program or function that converts a 32 bit binary number to its quad-dotted decimal notation (often used for representing IPv4)

Quad-dotted decimal

A quad-dotted decimal is formed like so:

  1. Split the binary representation into its 4 individual bytes
  2. Convert each byte into denary
  3. place "." between each number

Example:

input: 10001011111100010111110001111110 step 1: 10001011 11110001 01111100 01111110 step 2: 139 241 124 126 step 3: 139.241.124.126 

I/O examples

input --> output 10001011111100010111110001111110 --> 139.241.124.126 00000000000000000000000000000000 --> 0.0.0.0 01111111000000000000000000000001 --> 127.0.0.1 11000000101010000000000111111111 --> 192.168.1.255 

Rules

\$\endgroup\$
10
  • 7
    \$\begingroup\$ Input will always be a 32 bit binary number but your examples are binary lists. Is that also an acceptable input form? \$\endgroup\$ Commented Jan 10, 2020 at 12:49
  • 2
    \$\begingroup\$ Is it allowed to use a string as input instead of a list of binary digits? \$\endgroup\$ Commented Jan 10, 2020 at 13:31
  • \$\begingroup\$ I have added a brief description of how the qaud-dotted notation is formed @LuisMendo. \$\endgroup\$ Commented Jan 10, 2020 at 13:31
  • \$\begingroup\$ @Adám this is actually how I meant for the challenge to be interpreted, but I guess I couldn't find the right word. I have added it as an acceptable input form, but left the 32 bit binary number as valid input also. \$\endgroup\$ Commented Jan 10, 2020 at 13:33
  • 2
    \$\begingroup\$ I'm not clear, can we take in an actual number as input, like 2130706433 to give 127.0.0.1? \$\endgroup\$ Commented Jan 11, 2020 at 4:00

49 Answers 49

21
\$\begingroup\$

x86-16 machine code, IBM PC DOS, 54 47 45 bytes

Binary:

00000000: be82 00b3 04b1 08ac d0d8 d0d4 e2f9 8ac4 ................ 00000010: 41d4 0a50 8ac4 84c0 75f6 580c 30b4 0ecd A..P....u.X.0... 00000020: 10e2 f74b 7406 b02e cd10 ebd9 c3 ...Kt........ 

Build and test BIN2IP.COM using xxd -r from above.

Unassembled listing:

BE 0082 MOV SI, 82H ; command line input address B3 04 MOV BL, 4 ; loop 4 bytes BYTE_LOOP: B1 08 MOV CL, 8 ; loop 8 bits BIT_LOOP: AC LODSB ; load next bit char into AL D0 D8 RCR AL, 1 ; put LSB of char into CF D0 D4 RCL AH, 1 ; put CF into LSB of byte value, then shift left E2 F9 LOOP BIT_LOOP ; continue bit loop 8A C4 MOV AL, AH ; put byte result into AL GET_DIGIT: D4 0A AAM ; byte divide by 10, AH = AL / 10, AL = AL % 10 50 PUSH AX ; save remainder in AL on stack 8A C4 MOV AL, AH ; put quotient back into AL 41 INC CX ; increment decimal digit count D4 C0 TEST AL, AL ; quotient = 0? 75 F6 JNZ GET_DIGIT ; if not, continue looping PRINT_DIGIT: 58 POP AX ; restore digit in AL 0C 30 OR AL, '0' ; ASCII convert B4 0E MOV AH, 0EH ; BIOS write char function CD 10 INT 10H ; write to console E2 F7 LOOP PRINT_DIGIT ; loop until done 4B DEC BX ; is last byte? 74 06 JZ END_LOOP ; if so, don't display a '.' B0 2E MOV AL, '.' ; otherwise display '.' CD 10 INT 10H ; write to console END_LOOP: 75 D7 JNZ BYTE_LOOP ; continue byte loop C3 RET ; exit to DOS 

Output:

enter image description here

A standalone PC DOS executable. Input is command line, output to console.

Notes:

The "interesting part" (converting binary string to bytes) is about 15 bytes, whereas the rest of code is writing the itoa() function to convert binary bytes into a decimal string representation for display.

  • -2 bytes eliminating unnecessary PUSH/POP thx to @PeterCordes!
\$\endgroup\$
13
  • \$\begingroup\$ dec cx / jz end_loop could be re-arranged using a loop instruction that either falls through to a ret or jumps forward to mov al/int 10h/jmp byte_loop, for a net saving of I think 1 byte, from replacing dec cx/jcc with loop. Or maybe use DI for that loop counter instead of CX, avoiding push/pop? \$\endgroup\$ Commented Jan 11, 2020 at 20:13
  • \$\begingroup\$ BTW, several size-neutral changes that would make it more efficient (especially on modern CPUs): shr al,1 to shift the low bit into CF, not RCR. You don't need an input dependency on FLAGS. (Or hmm, possibly even scasb with AL='1' instead of loading, but that would invert). adc ah,ah can be 1 uop, RCL isn't. Also, test reg,reg/jcc is more efficient than or reg,reg, and the same size. I think the inefficient or idiom comes from 8080 ORA A, which didn't have an opcode that only set flags. \$\endgroup\$ Commented Jan 11, 2020 at 20:24
  • \$\begingroup\$ The question allows input as a 32-bit binary integer so you could just write a function that takes that (in memory pointed to by DS:SI if you want), instead of converting from a base 2 string. Also, instead of push/pop for digit-order, you could maybe store backwards into a buffer, creating a $-terminated string, and when you're done you have a pointer to the first byte. How do I print an integer in Assembly Level Programming without printf from the c library? shows the algorithm (and using a Linux write system call on it). \$\endgroup\$ Commented Jan 11, 2020 at 20:27
  • 1
    \$\begingroup\$ @PeterCordes yes, I just tried and that's what's happening. I was doing two different LOOPs on the "inner" loop, and since I can count on CX being 0 at the end of the first, I used it as the counter for decimal digits and looped again. Unfortunately DEC / JNZ is 1 byte more than LOOP so my gain there offsets the BX outer loop gain. So, yes, BX would seem to win but it was a great idea and fun exercise to go through! \$\endgroup\$ Commented Jan 11, 2020 at 21:10
  • 1
    \$\begingroup\$ @PeterCordes I experimented with writing in reverse to a string buffer, and was only able to get it down to 48 bytes. Here's the scratchpad (godbolt.org/z/6853--) if you have any thoughts or ideas. \$\endgroup\$ Commented Jan 13, 2020 at 17:22
10
\$\begingroup\$

05AB1E, 6 bytes

4äC'.ý 

Try it online or verify all test cases.

Explanation:

4ä # Convert the (implicit) input-string into 4 equal-sized parts C # Convert each part from binary to an integer '.ý '# Join this list by "." # (after which the result is output implicitly) 
\$\endgroup\$
9
\$\begingroup\$

C (gcc), 48 bytes

i;f(n){for(i=4;i--;)printf(".%hhu"+i/3,n>>i*8);} 

Takes as input a 32-bit integer.

Thanks to ceilingcat and gastropner for getting this answer where it is now!

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Missing semicolon in for loop. 48 bytes \$\endgroup\$ Commented Jan 12, 2020 at 6:38
7
\$\begingroup\$

Jelly, 10 6 bytes

s8Ḅj“. 

Try it online!

s Slice input list 8 into size 8 chunks Ḅ Convert from binary list to integer j“. Join with dots as the separator Implicit output 
\$\endgroup\$
3
  • \$\begingroup\$ If you use (character) rather than (start list of characters) this would be a Link rather than a full program (although submission may want to ba a full-program anyway, since the Link result is not just a list of characters, so we may prefer the implicit printing) \$\endgroup\$ Commented Jan 10, 2020 at 14:52
  • \$\begingroup\$ Are you counting as a single byte? \$\endgroup\$ Commented Jan 11, 2020 at 7:13
  • 1
    \$\begingroup\$ @chrylis-onstrike- Jelly uses a custom code page to encode its characters. So, in this instance, yes, it's one byte. \$\endgroup\$ Commented Jan 12, 2020 at 15:59
5
\$\begingroup\$

Python 2, 47 bytes

f=lambda n,k=-2:k*`n`or f(n>>8,k+1)+'.'+`n%256` 

Try it online!


Python 3, 46 bytes

lambda n:('.%d'*4%(*n.to_bytes(4,"big"),))[1:] 

Try it online!

Shaving a byte from David Foerster's to_bytes solution using string formatting.

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

PHP, 26 bytes

<?=long2ip(bindec($argn)); 

Try it online!

OR taking input as a integer as an anonymous function :

PHP, 7 bytes

long2ip 

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ No need for bindec, $argn will be an integer. \$\endgroup\$ Commented Jan 18, 2020 at 3:23
  • \$\begingroup\$ @kerkouch yes, that's true. I think that option was allowed after I posted the original answer. That simplifies this quite a bit. :) \$\endgroup\$ Commented Jan 18, 2020 at 14:05
4
\$\begingroup\$

PowerShell, 46 bytes

""+[IPAddress]"$([Convert]::ToInt64($args,2))" 

Try it online!

First takes input $args binary string and [System.Convert]s it into Int64. Uses the .NET type call [System.Net.Ipaddress] to parse that Int64 into an IPAddress object, then coerces the .IPAddressToString() method by prepending ""+.

\$\endgroup\$
2
  • \$\begingroup\$ Unfortunately on systems that are LittleEndian (like TIO and most computers... I think?) this parses the binary backwards so the IP in your TIO link has the quads in reverse order. \$\endgroup\$ Commented Jan 10, 2020 at 15:45
  • 1
    \$\begingroup\$ @Malivil Dang, that's a side-effect of removing the "$( )" that I golfed. I'll put that back in. Thanks for the bug catch! \$\endgroup\$ Commented Jan 10, 2020 at 16:06
3
\$\begingroup\$

MathGolf, 6 bytes

8/å'.u 

Try it online.

Explanation:

8/ # Split the (implicit) input-string into parts of size 8 å # Convert each part from a binary-string to an integer '.u '# Join by "." # (after which the entire stack joined together is output implicitly) 
\$\endgroup\$
3
\$\begingroup\$

APL (Dyalog Unicode), 20 19 bytesSBCS

-1 thanks to Kritixi Lithos.

Full program. Prompts for 32-bit integer, optionally as list of bits.

' '⎕R'.'⍕256|83⎕DR⎕ 

Try it online!

 console prompt for numeric input

83⎕DR interpret the bits of that data as 8-bit integers (internal Data Representation type 3)

256| convert to unsigned integers (lit. 256-mod of that)

 stringify (makes space-separated string)

' '⎕R'.'Replace spaces with dots

\$\endgroup\$
4
  • \$\begingroup\$ Using ⎕r on 'ing the entire list saves a byte \$\endgroup\$ Commented Jan 12, 2020 at 7:57
  • \$\begingroup\$ @KritixiLithos How? \$\endgroup\$ Commented Jan 12, 2020 at 8:16
  • \$\begingroup\$ ' '⎕r'.'⍕256|... tio.run/… \$\endgroup\$ Commented Jan 12, 2020 at 8:20
  • \$\begingroup\$ @KritixiLithos Oh right, for some reason I thought it was nested and would give too many spaces. \$\endgroup\$ Commented Jan 12, 2020 at 8:21
3
\$\begingroup\$

JavaScript (V8), 49 44 bytes

-5 bytes thanks to Arnauld

s=>s.match(/.{8}/g).map(x=>'0b'+x|0).join`.` 

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 44 bytes \$\endgroup\$ Commented Jan 12, 2020 at 10:37
3
\$\begingroup\$

C#7+, 117 73 bytes

s=>string.Join('.',(new System.Net.IPAddress(s)+"").Split('.').Reverse()) 

Accepts the bit representation of an IP address to transform it into a four-number notation, converts it to a string array, reverses the elements to account for the endianness differences of machines, then joins them together again with a dot.

Try it online!

  • Reduced to 73 bytes by utilizing the string hack and chaining (c/o @Expired Data)

Initial answer, 117 bytes

string I(long b){var x=new System.Net.IPAddress(b).ToString().Split('.');Array.Reverse(x);return string.Join(".",x);} 

Use it like:

void Main() { Console.WriteLine(I(0b_10001011111100010111110001111110)); } public string I(long b) { var x = new System.Net.IPAddress(b).ToString().Split('.'); Array.Reverse(x); return string.Join(".", x); } 
\$\endgroup\$
2
  • 1
    \$\begingroup\$ by using lambdas, chaining and a hack for ToString() you can reduce it to 73 bytes \$\endgroup\$ Commented Jan 13, 2020 at 11:47
  • \$\begingroup\$ Thanks, @ExpiredData, totally forgot the string hack. \$\endgroup\$ Commented Jan 13, 2020 at 15:59
2
\$\begingroup\$

Japt, 7 bytes

ò8 mÍq. 

Try it here

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

k4, 18 17 bytes

saved a byte by expressing in composed form instead of as a lambda:

("."/:$2/:'4 0N#) 

original explanation: output is string, quad-dot decimal not supported by k

{"."/:$2/:'4 0N#x} { } /lambda with implicit arg x 4 0N#x /cut x into 4 pieces 2/:' /convert each piece to decimal $ /stringify "."/: /join with . 

called on 2 binaries:

{"."/:$2/:'4 0N#x}'(10001011111100010111110001111110b;11000000101010000000000111111111b) ("139.241.124.126";"192.168.1.255") 
\$\endgroup\$
2
\$\begingroup\$

Java 9, 97 94 92 81 bytes

s->{for(int i=0;i<32;)System.out.print((i>0?".":"")+Long.parseLong(s,i,i+=8,2));} 

-2 bytes thanks to @AZTECCO.
-11 bytes thanks to @Holger by combining the Long.parseLong(s.substring(i,i+=8),2) into Long.parseLong(s,i,i+=8,2).

Try it online.

Explanation:

s->{ // Method with String parameter and no return-type for(int i=0;i<32;) // Loop `i` in the range [0, 32): System.out.print( // Print: (i>0? // If `i` is larger than 0 (so it's not the first iteration): "." // Print a dot : // Else: "") // Print nothing instead + // Appended with: Long.parseLong(s,i,i+=8,2));} // A substring of the input `s` from index `i` to `i+8`, // (and increase `i` by 8 for the next loop iteration) // Converted from binary-String to integer 
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Since Java 9, you can use Long.parseLong(s,i,i+=8,2) which will not only improve it from a golfing point of view, even the performance will be better as it saves the substring operations. \$\endgroup\$ Commented Jan 13, 2020 at 15:12
  • \$\begingroup\$ @Holger Oh, I didn't knew that. Thanks! :) \$\endgroup\$ Commented Jan 13, 2020 at 16:56
2
\$\begingroup\$

Excel. 96 bytes

=BIN2DEC(LEFT(A1,8))&"."&BIN2DEC(MID(A1,9,8))&"."&BIN2DEC(MID(A1,17,8))&"."&BIN2DEC(RIGHT(A1,8)) 
\$\endgroup\$
2
\$\begingroup\$

Python 3 (125 bytes)

def f(x): y='' for j in range(4): y+=str(int(x[j*8:j*8+8],2)) if j<4: y+="." return y 

Try it online

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Hi. Small problem in that this outputs an extra "." at the end. Easily fixed by changing j<4 to j<3. Also we normally count bytes and not characters and according to TIO this is 125 bytes. \$\endgroup\$ Commented Jan 11, 2020 at 8:28
  • 1
    \$\begingroup\$ Here are a few hints for 80 bytes Try it online! \$\endgroup\$ Commented Jan 11, 2020 at 8:50
  • \$\begingroup\$ Thank you @ElPedro for the knowledge. \$\endgroup\$ Commented Jan 15, 2020 at 17:43
  • \$\begingroup\$ My pleasure, however there are a couple more golfs that I didn't mention. I'll leave those for you to find. Since OP has said that trailing space is alowed then you can save at least 6 more. Have fun :) \$\endgroup\$ Commented Jan 15, 2020 at 21:59
  • \$\begingroup\$ BTW, even if you don't use the hints, you should really update the answer to correct the identified problem and please feel free to post my suggestions as an improved answer. \$\endgroup\$ Commented Jan 15, 2020 at 22:00
2
\$\begingroup\$

J, 18 bytes

' .'rplc~&":_8#.\] 

Try it online!

Old answer

-2 thanks to Kritixi Lithos

' .'rplc~&":2#.4 8$] 

Try it online!

My first answer in a non-esolang! (kinda). The way this answer works is pretty simple. Let's look first at a non-tacit form of this expression:

(":#.(4 8 $ n))rplc' .' 

Assuming that (for instance) n is:

n =: 1 0 0 0 1 0 1 1 1 1 1 1 0 0 0 1 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 

The expression 4 8 $ n is equal to:

1 0 0 0 1 0 1 1 1 1 1 1 0 0 0 1 0 1 1 1 1 1 0 0 0 1 1 1 1 1 1 0 

Then, the #. verb is applied over the matrix, yielding the following result:

139 241 124 126 

The resulting list is stringified using ":, and using rplc every space in the string representation of list is swapped to a dot, yielding the final form:

139.241.124.126 
\$\endgroup\$
2
  • \$\begingroup\$ [:#. can become 2#., and you can also remove the cap in rplc~[:": with rplc~&":. Also 2#.4 8$] can become shorter with the adverb infix jsoftware.com/help/dictionary/d430.htm \$\endgroup\$ Commented Jan 16, 2020 at 20:26
  • \$\begingroup\$ I can't spot the the possibility of using adverb infix in the code \$\endgroup\$ Commented Jan 17, 2020 at 9:04
1
\$\begingroup\$

Red, 33 bytes

func[n][to 1.1.1 debase/base n 2] 

Try it online!

Takes the input as strings.

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

Burlesque, 13 bytes

8co{b2}]m'.IC 

Try it online!

8co #Break into chunks 8 long {b2}]m #Read each chunk as base-2 and turn to string '.IC #Intercalate "." between each and collapse 
\$\endgroup\$
1
\$\begingroup\$

Stax, 8 bytes

Ç∩0&→Ö¡ 

Run and debug it at staxlang.xyz!

Unpacked (9 bytes) and explanation:

8/{|Bm'.* 8/ Split into length-8 chunks. 4M would work just as well. {|Bm Convert each chunk to decimal '.* Join with . 
\$\endgroup\$
1
\$\begingroup\$

Python 2, 81 \$\cdots\$ 58 55 bytes

lambda s:'.'.join(`int(s[i:i+8],2)`for i in(0,8,16,24)) 

Try it online!

Saved 3 bytes thanks to ElPedro!!!

Lambda function that takes a string of 32 "0"s and "1"s.

\$\endgroup\$
2
  • \$\begingroup\$ Ha, just came up wth the same thing! If you switch to Python 2 you can use backticks instead of str() to save 3 more Try it online! \$\endgroup\$ Commented Jan 11, 2020 at 7:50
  • \$\begingroup\$ @ElPedro Awesome, great minds think alike! Good idea switching to 2 for str() to backticks save. :-) \$\endgroup\$ Commented Jan 11, 2020 at 8:31
1
\$\begingroup\$

C (clang), 66 61 bytes

i;g(*m){for(i=32;i--;)*++m+=i%8?*m*2:!printf(".%d"+i/24,*m);} 

Try it online!

Input as an array of integers (bits)

Adds current number shifted to the next. Every 8 bits it prints instead of adding.

Saved 5 thanks to @gastropner and @ceilingcat

\$\endgroup\$
1
  • 1
    \$\begingroup\$ 63 bytes \$\endgroup\$ Commented Jan 11, 2020 at 1:51
1
\$\begingroup\$

CJam, 10 bytes

l~8/2fb'.* 

Try it online!

Explanation

l~ e# Read a line and evaluate it. Pushes list to the stack 8/ e# Split into sublists of 8 elements each. Gives list of sublists 2fb e# Map "base conversion" with extra parameter 2 over the list of sublists '.* e# Join sublists with character ".". Implicitly display 
\$\endgroup\$
1
\$\begingroup\$

Python 3, 47 bytes

lambda n:".".join(map(str,n.to_bytes(4,"big"))) 

Try it online!

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

PowerShell, 45 44 bytes

$args|%{$r+=+$r+"$_"} [ipaddress]::Parse($r) 

Try it online!


PowerShell, 45 bytes

Pure PowerShell. It does not use external libs.

($args|%{($r=2*$r%256+"$_")[++$i%8]})-join'.' 

Try it online!

Unrolled and commented:

$bytes = $args|%{ # $args is array on character 48 or 49 (bits) $r = 2 * $r # one bit shift left # the first operand is integer, so Powershell converts the second operand to an integer $r = $r % 256 # bitwise and 0xFF $digit = "$_" # convert a char 48, 49 to string "0" or "1" respectively $r = $r + $digit # add a digit # the first operand is integer, so Powershell converts the second operand to an integer # now $r is a byte containing 8 bits to the left of the current one $index = ++$i % 8 # 1,2,3,4,5,6,7,0, 1,2,3,4,5,6,7,0, ... ($r)[$index] # represent $r as an array; take an element of this array # index 0 will give $r, other indexes will give $null # Powershell outputs non $null values only # Compare to `Wrtie-Output ($r)[$index]` } # now $bytes is array of not $null elements Write-Output ($bytes -join '.') 
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Witchcraft! I can't even begin to understand how the second one works -- can you add an explanation? \$\endgroup\$ Commented Jan 12, 2020 at 16:09
  • \$\begingroup\$ Thanks, O' Valley of Plenty. I've added explanation. \$\endgroup\$ Commented Jan 13, 2020 at 8:17
1
\$\begingroup\$

Perl 5, 30 bytes

s/.{8}/oct("0b$&").'.'/ge;chop 

Try it online!

Search-replaces with regexp that takes eight bits (0 or 1) at a time and converts them to their decimal representation with . placed after each, but chops off the last . char. Using a function named oct here seems counter-intuitive since the input string isn't octal. But when the given string starts with 0b the rest is read as the binary string it is.

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

Ruby, 37 34 bytes

->b{(-3..0).map{|w|255&b<<w*8}*?.} 

Try it online!

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

Perl 6, 28 27 bytes

-1 byte thanks to Jo King

{chop S:g/.**8/{:2(~$/)}./} 

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Using chop is one byte shorter \$\endgroup\$ Commented Jan 14, 2020 at 1:39
1
\$\begingroup\$

REXX, 91 bytes

PARSE ARG WITH 1 A 9 B 17 C 25 D SAY X2D(B2X(A))'.'X2D(B2X(B))'.'X2D(B2X(C))'.'X2D(B2X(D)) 

Online REXX interpreter

\$\endgroup\$
1
  • \$\begingroup\$ If REXX had a function that would go directly from binary to decimal I could chop 20 bytes off of this. \$\endgroup\$ Commented Jan 17, 2020 at 23:24
1
\$\begingroup\$

Forth (gforth), 130 bytes.

Requires a Forth that starts in decimal mode, works with gforth.

: p . 8 emit ." ." ; : d dup 255 and swap ; : r 8 rshift d ; : q 32 2 base ! word number drop d r r r drop decimal p p p . ; 

Try it online!

Usage: q 10001011111100010111110001111110 [enter]

Deobfuscated version (or how I would really do it)

\ Forth program to convert a binary IP address to dotted decimal notation. decimal : binary 2 base ! ; \ Get the binary string and convert to a number. : getbin 32 binary word number drop ; \ Shift and mask the byte we are interested in. Put all 4 on the stack. hex : mask rshift dup ff and ; : quad4 dup ff and swap ; : quad 8 mask swap ; : 3more quad quad quad ; \ Print a quad, backspace over it's trailing space, print a dot. : .quad . 8 emit ." ." ; \ Print all 4 quads in decimal. : .4quads decimal .quad .quad .quad . ; \ Get binary number, chop it up into 4 quads, print in decimal. : qdot getbin quad4 3more drop .4quads ; 
\$\endgroup\$
0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.