# Challenge

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

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

• Input will always be a 32 bit binary number but your examples are binary lists. Is that also an acceptable input form?
Commented Jan 10, 2020 at 12:49
• Is it allowed to use a string as input instead of a list of binary digits? Commented Jan 10, 2020 at 13:31
• I have added a brief description of how the qaud-dotted notation is formed @LuisMendo. Commented Jan 10, 2020 at 13:31
• @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. Commented Jan 10, 2020 at 13:33
• I'm not clear, can we take in an actual number as input, like 2130706433 to give 127.0.0.1?
– xnor
Commented Jan 11, 2020 at 4:00

# x86-16 machine code, IBM PC DOS, 5447 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:

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!
• 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? Commented Jan 11, 2020 at 20:13
• 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. Commented Jan 11, 2020 at 20:24
• 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). Commented Jan 11, 2020 at 20:27 • @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! Commented Jan 11, 2020 at 21:10 • @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. Commented Jan 13, 2020 at 17:22 # 05AB1E, 6 bytes 4äC'.ý  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)  # 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! • Missing semicolon in for loop. 48 bytes Commented Jan 12, 2020 at 6:38 # 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  • 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) Commented Jan 10, 2020 at 14:52 • Are you counting Ḅ as a single byte? Commented Jan 11, 2020 at 7:13 • @chrylis-onstrike- Jelly uses a custom code page to encode its characters. So, in this instance, yes, it's one byte. Commented Jan 12, 2020 at 15:59 # PHP, 26 bytes <?=long2ip(bindec($argn));


Try it online!

# PHP, 7 bytes

long2ip


Try it online!

• No need for bindec, $argn will be an integer. Commented Jan 18, 2020 at 3:23 • @kerkouch yes, that's true. I think that option was allowed after I posted the original answer. That simplifies this quite a bit. :) Commented Jan 18, 2020 at 14:05 # 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 ""+.

• 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. Commented Jan 10, 2020 at 15:45
• @Malivil Dang, that's a side-effect of removing the "$( )" that I golfed. I'll put that back in. Thanks for the bug catch! Commented Jan 10, 2020 at 16:06 # Python 2, 47 bytes f=lambda n,k=-2:k*nor 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. # 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)  # 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 • Using ⎕r on ⍕'ing the entire list saves a byte Commented Jan 12, 2020 at 7:57 • @KritixiLithos How? – Adám Commented Jan 12, 2020 at 8:16 • ' '⎕r'.'⍕256|... tio.run/… Commented Jan 12, 2020 at 8:20 • @KritixiLithos Oh right, for some reason I thought it was nested and would give too many spaces. – Adám Commented Jan 12, 2020 at 8:21 # JavaScript (V8), 49 44 bytes -5 bytes thanks to Arnauld s=>s.match(/.{8}/g).map(x=>'0b'+x|0).join.  Try it online! • 44 bytes Commented Jan 12, 2020 at 10:37 # 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); }  • by using lambdas, chaining and a hack for ToString() you can reduce it to 73 bytes Commented Jan 13, 2020 at 11:47 • Thanks, @ExpiredData, totally forgot the string hack. Commented Jan 13, 2020 at 15:59 # Japt, 7 bytes ò8 mÍq.  Try it here # 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")  # Java 9, 979492 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  • 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. Commented Jan 13, 2020 at 15:12 • @Holger Oh, I didn't knew that. Thanks! :) Commented Jan 13, 2020 at 16:56 ## Excel. 96 bytes =BIN2DEC(LEFT(A1,8))&"."&BIN2DEC(MID(A1,9,8))&"."&BIN2DEC(MID(A1,17,8))&"."&BIN2DEC(RIGHT(A1,8))  # 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 • 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. Commented Jan 11, 2020 at 8:28 • Here are a few hints for 80 bytes Try it online! Commented Jan 11, 2020 at 8:50 • Thank you @ElPedro for the knowledge. Commented Jan 15, 2020 at 17:43 • 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 :) Commented Jan 15, 2020 at 21:59 • 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. Commented Jan 15, 2020 at 22:00 # Red, 33 bytes func[n][to 1.1.1 debase/base n 2]  Try it online! Takes the input as strings. # 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  # 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 .  # Python 2, 81 $$\\cdots$/extract_tex] 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. • 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! Commented Jan 11, 2020 at 7:50 • @ElPedro Awesome, great minds think alike! Good idea switching to 2 for str() to backticks save. :-) Commented Jan 11, 2020 at 8:31 # 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 • 63 bytes Commented Jan 11, 2020 at 1:51 # 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  # Python 3, 47 bytes lambda n:".".join(map(str,n.to_bytes(4,"big")))  Try it online! # 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 '.')  • Witchcraft! I can't even begin to understand how the second one works -- can you add an explanation? Commented Jan 12, 2020 at 16:09 • Thanks, O' Valley of Plenty. I've added explanation. Commented Jan 13, 2020 at 8:17 # 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. # Ruby, 37 34 bytes ->b{(-3..0).map{|w|255&b<<w*8}*?.}  Try it online! # Perl 6, 28 27 bytes -1 byte thanks to Jo King {chop S:g/.**8/{:2(~/)}./}  Try it online! • Using chop is one byte shorter – Jo King Commented Jan 14, 2020 at 1:39 # 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

• [:#. 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 Commented Jan 16, 2020 at 20:26
• I can't spot the the possibility of using adverb infix in the code Commented Jan 17, 2020 at 9:04

# 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

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

# 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 ;