Implement INTERCAL's Binary Operators

The Compiler Language With No Pronounceable Acronym, abbreviated INTERCAL, is a very unique programming language. Among its unreproducible qualities are its binary operators.

INTERCAL's two binary operators are interleave (also known as mingle), and select. Interleave is represented with a change (¢), and select is represented with a sqiggle (~).

Interleave works by taking two numbers in the range 0-65535 and alternating their bits. For instance:

234 ¢ 4321
234   = 0000011101010
4321  = 1000011100001
Result: 01000000001111110010001001
Output: 16841865

Select works by taking two numbers in the range 0-65535, taking the bits in the first operand which are in the same position as 1s in the second operand, and right packing those bits.

2345 ~ 7245
2345  = 0100100101001
7245  = 1110001001101
Taken : 010   0  10 1
Result: 0100101
Output: 37

In this challenge, you will be given a binary expression using either the interleave or select operation. You must calculate the result, using the fewest possible bytes.

The expression will be given as a space separated string, consisting of an integer in 0-65535, a space, either ¢ or ~, a space, and an integer in 0-65535.

Input and output may be through any standard system (STDIN, function, command line, etc.). Standard loopholes banned.

Examples:

5 ¢ 6
54

5 ~ 6
2

51234 ¢ 60003
4106492941

51234 ~ 60003
422

This is code golf - fewest bytes wins. Good luck.

EDIT: Since some languages do not support INTERCAL's change (¢) symbol, you may use the big money ($) symbol instead, at a 5 byte penalty. • It's a bit harsh penalising people for the use of the dollar sign. That is something that cannot be helped. – Beta Decay Aug 10 '15 at 11:14 • I just realized that CLWNPA is perfectly pronouncable in Welsh. The W is pronounced as U in Spanish or OO in English. – Level River St Aug 10 '15 at 11:58 • I don't get the 5 byte penalty. C-INTERCAL uses the$. – kirbyfan64sos Aug 10 '15 at 14:42
• What are you all arguing about? A $is clearly more expensive than a ¢. What, you want 99¢ for nothing? – Max Aug 10 '15 at 20:15 • I didn't think INTERCAL would allow you to input numbers with decimal numerals. Don't you have to write FIVE ONE TWO THREE FOUR? And shouldn't the output be in Roman numerals? – Nate Eldredge Aug 10 '15 at 22:01 16 Answers Pyth, 3231 29 bytes isummFdG}\~zCm.[Z16jvd2%2cz)2 Try it online: Regular Input / Test Suite Thanks to @isaacg for golfing off one byte. Explanation: cz) split input at spaces %2 only take every second item (the numbers) m map each number d to: vd convert d to int j 2 convert to base 2 .[Z16 pad zeros at the left C zip u }\~z apply the following function ("~" in input) times: m G map each pair d to: mFd convert [x,0] to [] and [x,1] to [x] s take sum (unfold all lists) i 2 convert back from base 2 and print • You can save one byte by changing hMfeT to smmFd and then moving the duplicate s outside the ternary. Also, your current code is 32 bytes, not 33. – isaacg Aug 10 '15 at 12:49 • @isaacg Wow. I would never have thought that clever golf. Thanks. And yeah, did a last minute golf while writing the explanation and didn't update the byte count. – Jakube Aug 10 '15 at 13:00 • It's really interesting to see Pyth and CJam answers, almost always the same byte count, but Pyth often beats CJam by a few – Kametrixom Aug 10 '15 at 21:59 Python 2, 115 112 bytes x,y,z=input().split() d=y<"" f=lambda a,b:a+b and(b%2+5&4-d)*f(a/2,b/2)+(a%2*2+b%2)/3**d print f(int(x),int(z)) The string on the second line contains a single unprintable character \x7d, the next char after ~. All hopes of a nice, single lambda get crushed by the input format. There's probably a better way to read in input. Input like "51234 ¢ 60003" via STDIN. The function f combines the following two recursive functions: g=lambda a,b:a+b and 4*g(a/2,b/2)+a%2*2+b%2 # ¢ h=lambda a,b:a+b and(b%2+1)*h(a/2,b/2)+a*b%2 # ~ (-3 bytes with the help of @xnor) • +1 for the first really competitive Python answer. I was wondering why you bothered with the lambda and didn't just use an expression, but it looks like there's some recursion in there? I don't know Python, I look forward to an explanation. – Level River St Aug 10 '15 at 11:19 • Some great bit bashing! I'm looking at compressing the constant term expression. The expression (a%2*2+b%2)/3**d saves 3 chars but uses the complement d=1-c. Do you have a way to do -~(3*c|b%2) with the complement? At worst it loses 2 chars with 3-3*d. Also, the format and-~x+y can be andy-~x as long as y starts with a symbol or number. – xnor Aug 12 '15 at 6:33 • @xnor Got it, (b%2+5&4-d). Thanks! – Sp3000 Aug 12 '15 at 8:11 CJam, 31 bytes rrc\r]{i2bF0e[}%(7=\zf{_)*?~}2b Try it online in the CJam interpreter. How it works rr e# Read two tokens from STDIN. c\ e# Cast the second to char and swap with the first. r e# Read a third token from STDIN. ] e# Wrap everything in an array. { }% e# For all three elements: i2b e# Cast to int and convert to base 2. F0e[ e# Left-pad with zeroes to complete 15 digits. ( e# Shift out the first base 2 array. 7= e# Select its eighth MSB (1 for '¢', 0 for '~'). \ e# Swap with the array of base 2 arrays. z e# Zip to transpose rows with columns. f{ } e# For each pair of base 2 digits: e# Push the bit, then the pair. _ e# Copy the pair. ) e# Pop the second digit. * e# Repeat the first digit that many times. ? e# Ternary if. Select the pair if the bit is e# truthy, the repeated first bit if it's falsy. ~ e# Dump the selected array on the stack. 2b e# Convert from base 2 to integer. JavaScript (ES6), 103 117 119 124 Edit now working with numbers instead of strings (not counting leading spaces, newlines and comments) Test running the snippet on any EcmaScript 6 compliant browser (notably not Chrome not MSIE. I tested on Firefox, Safari 9 could go) I=s=> (i=>{ for(m=r=0,[a,o,b]=s.split ;i>0;i<<=1) // loop until bit 31 of i is set o>'~'?r+=(b&i)*i+(a&i)*2*i:b&i?r+=(a&i)>>m:++m })(1)||r // TEST out=x=>O.innerHTML+=x+'\n\n'; [ ['234 ¢ 4321', 16841865], ['2345 ~ 7245', 37] , ['5 ¢ 6', 54], ['5 ~ 6', 2] , ['51234 ¢ 60003',4106492941], ['51234 ~ 60003', 422]] .forEach(([i,o,r=I(i)])=>{ out('Test '+ (o==r?'OK':'Fail')+'\nInput: '+ i+'\nResult: '+r+'\nExpected: '+o)}) <pre id=O></pre> Matlab, 119 113 bytes function f(s) t=dec2bin(str2double(strsplit(s,{'¢' '~'}))');u=any(s>'~');[~u u]*bin2dec({t(1,t(2,:)==49) t(:)'}) Ungolfed: function f(s) % input s is a string t = dec2bin(str2double(strsplit(s,{'¢' '~'}))'); % get the two numbers and convert to % two-row char array of zeros of ones u = any(s>'~'); % 1 indicates '¢'; 0 indicates '~' [~u u]*bin2dec({t(1,t(2,:)==49) t(:)'}) % compute both results and display % that indicated by u Examples: >> f('234 ¢ 4321') ans = 16841865 >> f('2345 ~ 7245') ans = 37 R, 145 bytes s=scan(,"");a=as.double(c(s,s));i=intToBits;cat(packBits(if(s=="~")c(i(a)[i(a)>0],i(0))[1:32] else c(rbind(i(a),i(a))),"i")) Ungolfed + explanation: # Read a string from STDIN and split it on spaces s <- scan(, "") # Convert the operands to numeric a <- as.double(c(s, s)) o <- if (s == "~") { # Get the bits of the first operand corresponding to ones in # the second, right pad with zeros, and truncate to 32 bits c(intToBits(a)[intToBits(a) == 1], intToBits(0))[1:32] } else { # Interleave the arrays of bits of the operands c(rbind(intToBits(a), intToBits(a))) } # Make an integer from the raw bits and print it to STDOUT cat(packBits(o, "integer")) Python 3, 174166148 126 Pretty straightforward, string operations, then conversion back to integer. Limited to numbers which in binary have 99 digits (max 2^99-1 = 633825300114114700748351602687). Thanks, Sp3000 and Vioz! a,o,b=input().split() print(int(''.join([(i+j,i[:j>'0'])[o>'~']for i,j in zip(*[bin(int(j))[2:].zfill(99)for j in(a,b)])]),2)) Or 165 chars, without limit: a,o,b=input().split() a,b=[bin(int(j))[2:]for j in(a,b)] print(int(''.join([(i if j=='1'else'')if o=='~'else i+j for i,j in zip(a.zfill(len(b)),b.zfill(len(a)))]),2)) Ungolfed: a, op, b = input().split() a, b = [bin(int(j))[2:] for j in(a,b)] #convert to int (base 10), then to binary, remove leading '0b' m = max(len(a), len(b)) a = a.zfill(m) #fill with leading zeroes b = b.zfill(m) if op == '~': ret = [i if j=='1' else'' for i, j in zip(a, b)] else: ret = [i + j for i, j in zip(a, b)] ret = ''.join(ret) #convert to string ret = int(ret, 2) #convert to integer from base 2 print(ret) • You can use zfill instead of rjust for padding with zeroes – Sp3000 Aug 10 '15 at 9:25 • Inputs max out at 16 bits, and outputs at 32 bits. 99 bits is more than enough. – isaacg Aug 10 '15 at 11:13 • I know, but since '99' takes as much characters as '16', there's no benefit of limiting it. – Trang Oul Aug 10 '15 at 11:20 • A few more: 1) You don't need to save a,b, just put it in the zip with a * splat, 2) (i if j=='1'else'') -> i[:j>'0'] 3) You can use this tip to save on the other if/else – Sp3000 Aug 10 '15 at 13:02 • My solution ended up being too close to yours, so here's as short as I could get yours (126 bytes). – Kade Aug 10 '15 at 15:44 Pyth, 43 bytes Part of me feels nervous posting such a long Pyth answer on isaacg's question... :oP J.(Kczd1Am.BvdKiu?qJ\~u+G?qeH\1hHk+VGHk.iGH2 Explaination: Implicit: z=input(), k='', d=' ' Kczd Split z on spaces, store in K J.( 1 Remove centre element from K, store in J m K For each d in K .Bvd Evaluate as int, convert to binary string A Store pair in G and H ~ processing: +VGH Create vectorised pairs ([101, 110] -> [11, 01, 10]) u k Reduce this series, starting with empty string ?qeH\1 If 2nd digit == 1... hHk ... take the 1st digit, otherwise take '' +G Concatenate .iGH ¢ processing: interleave G with H ?qJ\~ If J == ~, take ~ processing, otherwise take ¢ i 2 Convert from binary to decimal • I love your profile picture! :) – kirbyfan64sos Aug 10 '15 at 21:09 • @kirbyfan64sos Blue Kirby is best Kirby :o) – Sok Aug 11 '15 at 7:42 C, 127 123 bytes + 5 penalty = 128 scanf counts the unicode symbol as more than one character which complicates things a lot, so I'm applying the 5-byte penalty for using$.

a,b,q,x,i;main(){scanf("%d %c %d",&a,&q,&b);for(i=65536;i/=2;)q%7?x=x*4|a/i*2&2|b/i&1:b/i&1&&(x=x*2|a/i&1);printf("%u",x);}

The changes from the original version are:

-The test for $or ~ has been revised from q&2 to q%7. This reverses the true/false values, allowing the code for$ operator to go before the : which means a set of parentheses can be eliminated.

-The i loop now counts down in powers of 2 which is longer, but permits >> to be substituted by / and saves some parentheses.

Original version 127 bytes

a,b,q,x,i;
main(){
scanf("%d %c %d",&a,&q,&b);
for(i=16;i--;)
q&2?
b>>i&1&&(x=x*2|a>>i&1):    // ~ operator. && used as conditional: code after it is executed only if code before returns truthy.
(x=x*4|(a>>i&1)*2|b>>i&1); // $operator printf("%u",x); } I went with a single loop with the conditionals inside to avoid the overhead of two loops. In both cases I rightshift the bits of the operands down to the 1's bit, and build up the result from the most significant to least significant bit, leftshifting the result (multiplying by 2 or 4) as I go. • I golfed it for you: main(a,b,q,x,i){scanf("%d %c %d",&a,&q,&b);for(i=16;i--;)q&2?b>>i&1&&(x=x*2|a>>i&1):(x=x*4|(a>>i&1)*2|b>>i&1);printf("%u",x);} I tried golfing away the >>i&1 parts, but couldn't find a cost effective way to do it. I was able to save 1 character however by putting the variable definitions in main. Note: untested. – LambdaBeta Aug 10 '15 at 12:28 • @LamdaBeta thanks, I couldn't find a macro for >>i&1 but I have managed to golf it another way. Putting the variables as arguments of main causes q to be corrupted on my machine, which is strange. I expect the real problem is with scanf, but because of that I have left them as normal declarations. – Level River St Aug 10 '15 at 13:37 • I hadn't thought of that. You are right, q will be corrupted. The reason is that while we learn that main takes two arguments, the count of command-line arguments and an array of the arguments itself, most systems actually provide a third argument (typically called char*envp[]) which describes the environment the code is run in (granting access to EG: environment variables). Thus the third value in main may also be assigned a value by the system, scanf is innocent this time. – LambdaBeta Aug 10 '15 at 15:33 • @steveverill I think you can also remove the 5 byte penalty. I just tested your code (using ALT+155 to make ¢) and it seems to work fine. :) – LambdaBeta Aug 10 '15 at 15:38 • @LambdaBeta actually experimentation shows it's a combination of both. With the normal declaration q is guaranteed to be zero, but with the declaration as a function parameter q contains 32-bit garbage. That wouldn't be a problem if I assigned a value to q, but scanf with "%c" only overwrites the least significant 8 bits of the garbage, leaving the other 24 undefined. I might get lucky on another compiler! – Level River St Aug 10 '15 at 21:55 K5, 53 52 bytes {b/({,/x,'y};{x@&y})[*"~"=y][b\.x;(b:20#2)\.z]}." "\ 53-byte version: {b/({,/x,'y};{x@&y})[*"¢~"?y][b\.x;(b:20#2)\.z]}." "\ Still needs a bit more golfing. CJam, 61504641 34 bytes Thanks @Dennis for pointing out a 4 bytes golf. rrc'~=:X;r]{i2bF0e[}/.{X{{;}|}&}2b • ]{}/ is a noop. – Dennis Aug 10 '15 at 16:00 • @Dennis Thanks. I should probably get some sleep... – Andrea Biondo Aug 10 '15 at 18:43 Haskell, 77 g=(mod2) h=(div2) 0¢0=0 a¢b=g a+2*b¢h a a?0=0 a?b=g a*g b+(1+g b)*h a?h b input is given by applying the input to the functions/operators ? and ¢ defined in the code (Haskell can't define an operator ~ for technical reasons). basically works the old recursive approach. J, 173 f=:|."1@(>@(|.&.>)@(#:@{:;#:@{.)) m=:2&#.@:,@:|:@:|.@:f s=:2&#.@#/@:f a=:{&a.@-. (1!:2)&2(s@".@:a&126)^:(126 e.i)((m@".@:a&194 162)^:(1 e.194 162 E.i)i=._1}.(a.i.((1!:1)3))) expects one line of input input expected to terminate after new line with EOF Javascript ES6 (3 arguments) 141138136121 119 bytes b=x=>(65536|x).toString2 f=(x,o,y)=>+eval('0b'+(b(y)+b(x)).replace(/^1|${o=='~'?1:'(.)'}(?=.{16}(.)())|./g,'$2$1'))

Test:

;[f(234,'¢',4321),f(2345,'~',7245)]=="16841865,37"

Javascript ES6 (1 argument) 135 133 bytes

b=x=>(65536|x).toString2
f=s=>([x,o,y]=s.split )|eval('0b'+(b(y)+b(x)).replace(/^1|${o=='~'?1:'(.)'}(?=.{16}(.)())|./g,'$2\$1'))

Test:

;[f('234 ¢ 4321'),f('2345 ~ 7245')]=="16841865,37"

PS: New line is counted as 1 byte as it can be replaced by ;.

• 0x10000 == 65536 (save 2 chars) – edc65 Aug 10 '15 at 21:20
• @edc65, I've updated the answer. – Qwertiy Aug 10 '15 at 21:43
• 65536|x to avoid ~~ – edc65 Aug 10 '15 at 21:46
• Only the second version is allowed - the input must be in the form of a space delimited string. – isaacg Aug 11 '15 at 6:16
• @isaacg, ok. But I don't want to delete the first for historical reasons. – Qwertiy Aug 11 '15 at 6:25

Python 3, 157 bytes

a,x,y=input().split()
i=int
b=bin
print(i(''.join(([c for c,d in zip(b(i(a)),b(i(y)))if d=='1'],[c+d for c,d in zip(b(i(a))[2:],b(i(y))[2:])])['¢'==x]),2))

Full and explanatory version can be found on my pastebin.

• You can same a few chars by removing spaces around '==' operator, before 'if' and by passing 'base' as positional argument. – Trang Oul Aug 10 '15 at 9:14
• Thank you, that and some others have saved 15 chars! but the doubled way of formatting the return is still to much. – Oliver Friedrich Aug 10 '15 at 9:19
• Also, do you use 4 spaces per indent? One (or tab) is enough. – Trang Oul Aug 10 '15 at 9:25
• @BeowulfOF Unless otherwise specified, you can submit a full program or a function. Generally, which is shorter will depend on the way your language parses the specific input for the challenge (ruby is surprisingly clumsy with numbers from stdin for example). You also have two possible ways to output: stdout or return value, which are applicable to both (though return values from programs are rare.) – Level River St Aug 10 '15 at 10:24
• You only appear to use e once, can't you just inline it? – Kevin Brown Aug 11 '15 at 1:39

Mathematica, 155 bytes

f=IntegerDigits[#,2,16]&;
g=#~FromDigits~2&;
¢=g[f@#~Riffle~f@#2]&;