Implement INTERCAL's Binary Operators

29

1

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.

isaacg

Posted 2015-08-10T07:21:22.007

Reputation: 39 268

I was going to suggest doing this in INTERCAL, then I saw Standard Loopholes banned. Damn! Can we use a symbol other than the "change" symbol for the interleave operator? The symbol given is not ASCII, which will be a problem for some languages. According to the linked wikipedia page $ and c have been used. – Level River St – 2015-08-10T08:07:16.260

1@steveverrill I adressed the non-ASCII issue. Using INTERCAL is fine, as long as you take the input from STDIN. INTERCAL has no other concept of a string. – isaacg – 2015-08-10T08:27:14.037

10It's a bit harsh penalising people for the use of the dollar sign. That is something that cannot be helped. – Beta Decay – 2015-08-10T11:14:04.520

1@BetaDecay I don't want submissions which use the wrong symbol just because it saves a single byte - I only want languages that really need to use the $ to do so. – isaacg – 2015-08-10T11:17:08.077

2@isaacg Well why don't you just penalise them for the number of times they use a dollar sign instead of a cent sign? – Beta Decay – 2015-08-10T11:18:48.627

9I just realized that CLWNPA is perfectly pronouncable in Welsh. The W is pronounced as U in Spanish or OO in English. – Level River St – 2015-08-10T11:58:23.023

9I don't get the 5 byte penalty. C-INTERCAL uses the $. – kirbyfan64sos – 2015-08-10T14:42:06.017

2Is ¢ as ASCII 155 (per the old Codepage 437) OK? If so I can remove the penalty. I'm told it works, but I am having difficulty making it work on my own (Spanish) computer due to operating system issues. C doesn't properly support the unicode value 0x00A2. BTW @betadecay, your suggestion would suit me perfectly, as none of the operator symbols appear in my code, heheh! – Level River St – 2015-08-10T16:42:49.220

13What are you all arguing about? A $ is clearly more expensive than a ¢. What, you want 99¢ for nothing? – Max – 2015-08-10T20:15:47.610

6I 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 – 2015-08-10T22:01:13.673

3@NateEldredge The challenge is to implement a feature of INTERCAL, not the whole language. That horrible input format rather neatly means that in this case there is no need to invoke the standard loophole about emulating a language with the language itself. To answer the challenge in (original) INTERCAL (or CLaWNPA / CLOWNPA as I like to call it) you would have to write code for parsing decimal numbers. Some modern variants apparently have easier I/O, but I couldn't find one that takes decimal input. – Level River St – 2015-08-10T23:22:35.870

Answers

9

Pyth, 32 31 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

Jakube

Posted 2015-08-10T07:21:22.007

Reputation: 21 462

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 – 2015-08-10T12:49:07.643

@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 – 2015-08-10T13:00:26.107

2It's really interesting to see Pyth and CJam answers, almost always the same byte count, but Pyth often beats CJam by a few – Kametrixom – 2015-08-10T21:59:29.057

13

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)

Sp3000

Posted 2015-08-10T07:21:22.007

Reputation: 58 729

1+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 – 2015-08-10T11:19:39.880

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 – 2015-08-12T06:33:44.523

@xnor Got it, (b%2+5&4-d). Thanks! – Sp3000 – 2015-08-12T08:11:04.710

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.

Dennis

Posted 2015-08-10T07:21:22.007

Reputation: 196 637

8

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>

edc65

Posted 2015-08-10T07:21:22.007

Reputation: 31 086

5

Python 3, 174 166 148 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)

Trang Oul

Posted 2015-08-10T07:21:22.007

Reputation: 656

2You can use zfill instead of rjust for padding with zeroes – Sp3000 – 2015-08-10T09:25:11.087

Inputs max out at 16 bits, and outputs at 32 bits. 99 bits is more than enough. – isaacg – 2015-08-10T11:13:56.493

I know, but since '99' takes as much characters as '16', there's no benefit of limiting it. – Trang Oul – 2015-08-10T11:20:47.473

1

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 – 2015-08-10T13:02:35.117

1

My solution ended up being too close to yours, so here's as short as I could get yours (126 bytes).

– Kade – 2015-08-10T15:44:11.123

5

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

Luis Mendo

Posted 2015-08-10T07:21:22.007

Reputation: 87 464

5

R, 145 bytes

s=scan(,"");a=as.double(c(s[1],s[3]));i=intToBits;cat(packBits(if(s[2]=="~")c(i(a[1])[i(a[2])>0],i(0))[1:32] else c(rbind(i(a[2]),i(a[1]))),"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[1], s[3]))

o <- if (s[2] == "~") {
    # 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[1])[intToBits(a[2]) == 1], intToBits(0))[1:32]
} else {
    # Interleave the arrays of bits of the operands
    c(rbind(intToBits(a[2]), intToBits(a[1])))
}

# Make an integer from the raw bits and print  it to STDOUT
cat(packBits(o, "integer"))

Alex A.

Posted 2015-08-10T07:21:22.007

Reputation: 23 761

4

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

Sok

Posted 2015-08-10T07:21:22.007

Reputation: 5 592

4I love your profile picture! :) – kirbyfan64sos – 2015-08-10T21:09:10.903

2@kirbyfan64sos Blue Kirby is best Kirby :o) – Sok – 2015-08-11T07:42:20.277

3

CJam, 61 50 46 41 34 bytes

Thanks @Dennis for pointing out a 4 bytes golf.

rrc'~=:X;r]{i2bF0e[}/.{X{{;}|}&}2b

Try it online.

Andrea Biondo

Posted 2015-08-10T07:21:22.007

Reputation: 1 452

1]{}/ is a noop. – Dennis – 2015-08-10T16:00:04.003

1@Dennis Thanks. I should probably get some sleep... – Andrea Biondo – 2015-08-10T18:43:55.540

3

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.

Level River St

Posted 2015-08-10T07:21:22.007

Reputation: 22 049

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=x2|a>>i&1):(x=x4|(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 – 2015-08-10T12:28:46.457

@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 – 2015-08-10T13:37:49.610

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 – 2015-08-10T15:33:30.540

@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 – 2015-08-10T15:38:06.190

@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 – 2015-08-10T21:55:24.437

3

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.

kirbyfan64sos

Posted 2015-08-10T07:21:22.007

Reputation: 8 730

3

Haskell, 77

g=(`mod`2)
h=(`div`2)
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.

proud haskeller

Posted 2015-08-10T07:21:22.007

Reputation: 5 866

2

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.

Oliver Friedrich

Posted 2015-08-10T07:21:22.007

Reputation: 141

You can same a few chars by removing spaces around '==' operator, before 'if' and by passing 'base' as positional argument. – Trang Oul – 2015-08-10T09:14:25.087

Thank you, that and some others have saved 15 chars! but the doubled way of formatting the return is still to much. – Oliver Friedrich – 2015-08-10T09:19:34.480

Also, do you use 4 spaces per indent? One (or tab) is enough. – Trang Oul – 2015-08-10T09:25:01.360

Yes, removed extra spaces and now also undoubled output formatting - almost got ya! ;-) – Oliver Friedrich – 2015-08-10T09:27:32.227

For more I would have to take your splitting into 3 variables and I refuse to do that - and would get to 174C. Thank you @TrangOul! – Oliver Friedrich – 2015-08-10T09:29:53.240

And a last space could be removed. Finally would it end up 173C - got ya! :-) – Oliver Friedrich – 2015-08-10T09:40:44.033

Feel free to use shorter answer. You can save a few chars by unassigning zip (only 2 uses => (len('zipzip') < len('z=zipzz'))) and even more by not wrapping code into a function. – Trang Oul – 2015-08-10T09:58:41.877

Isn't code as a function a part of the game? – Oliver Friedrich – 2015-08-10T10:12:22.920

2@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 – 2015-08-10T10:24:43.460

1You only appear to use e once, can't you just inline it? – Kevin Brown – 2015-08-11T01:39:31.553

2

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

protist

Posted 2015-08-10T07:21:22.007

Reputation: 570

2

Javascript ES6 (3 arguments) 141 138 136 121 119 bytes

b=x=>(65536|x).toString`2`
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).toString`2`
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 ;.

Qwertiy

Posted 2015-08-10T07:21:22.007

Reputation: 2 697

10x10000 == 65536 (save 2 chars) – edc65 – 2015-08-10T21:20:46.873

@edc65, I've updated the answer. – Qwertiy – 2015-08-10T21:43:38.783

265536|x to avoid ~~ – edc65 – 2015-08-10T21:46:48.290

Only the second version is allowed - the input must be in the form of a space delimited string. – isaacg – 2015-08-11T06:16:33.723

@isaacg, ok. But I don't want to delete the first for historical reasons. – Qwertiy – 2015-08-11T06:25:09.980

@Qwertiy No problem. As long as you have a valid submission, that's fine. – isaacg – 2015-08-11T06:28:12.167

0

Mathematica, 155 bytes

f=IntegerDigits[#,2,16]&;
g=#~FromDigits~2&;
¢=g[f@#~Riffle~f@#2]&;
s=g@Cases[Thread@{f@#,f@#2},{x_,1}->x]&;
ToExpression@StringReplace[#,{" "->"~","~"->"s"}]&

Evaluates to an anonymous function taking the string as input. Line breaks added for clarity.

f and g convert to/from base 2. Riffle does exactly what interleave is supposed to. I wanted to use Select for select but Cases is better unfortunately. The last line is a bit of trickery; spaces are changed to ~ which is Mathematica's infix operator, then the string is eval'd.

jcai

Posted 2015-08-10T07:21:22.007

Reputation: 973