# Decimal “XOR” operator

Many programming language provide operators for manipulating the binary (base-2) digits of integers. Here is one way to generalize these operators to other bases:

Let x and y be single-digit numbers in base B. Define the unary operator ~ and binary operators &, |, and ^ such that:

• ~x = (B - 1) - x
• x & y = min(x, y)
• x | y = max(x, y)
• x ^ y = (x & ~y) | (y & ~x)

Note that if B=2, we get the familiar bitwise NOT, AND, OR, and XOR operators.

For B=10, we get the “decimal XOR” table:

^ │ 0 1 2 3 4 5 6 7 8 9
──┼────────────────────
0 │ 0 1 2 3 4 5 6 7 8 9
1 │ 1 1 2 3 4 5 6 7 8 8
2 │ 2 2 2 3 4 5 6 7 7 7
3 │ 3 3 3 3 4 5 6 6 6 6
4 │ 4 4 4 4 4 5 5 5 5 5
5 │ 5 5 5 5 5 4 4 4 4 4
6 │ 6 6 6 6 5 4 3 3 3 3
7 │ 7 7 7 6 5 4 3 2 2 2
8 │ 8 8 7 6 5 4 3 2 1 1
9 │ 9 8 7 6 5 4 3 2 1 0


For multi-digit numbers, apply the single-digit operator digit-by-digit. For example, 12345 ^ 24680 = 24655, because:

• 1 ^ 2 = 2
• 2 ^ 4 = 4
• 3 ^ 6 = 6
• 4 ^ 8 = 5
• 5 ^ 0 = 5

If the operands are different lengths, then pad the shorter one with leading zeros.

# The challenge

Write, in as few bytes as possible, a program or function that takes as input two integers (which may be assumed to be between 0 and 999 999 999, inclusive) and outputs the “decimal XOR” of the two numbers as defined above.

# Test cases

• 12345, 24680 → 24655
• 12345, 6789 → 16654
• 2019, 5779 → 5770
• 0, 999999999 → 999999999
• 0, 0 → 0
• May we take the input or output as strings or char arrays? – Embodiment of Ignorance Sep 17 at 3:01
• How about a digit array? Is that acceptable? – Embodiment of Ignorance Sep 17 at 3:06
• Is 09 an acceptable result for an input of 90, 99? – Neil Sep 17 at 9:39
• I wish there was a generalisation that maintained A^B^B=A – trichoplax Sep 18 at 18:20
• @trichoplax, you can't have both a^b=b^a and a^b^b=a for bases with an odd prime divisor – mik Sep 28 at 14:57

# Jelly, 14 bytes

DUz0«9_ṚƊṀƊ€UḌ


Try it online!

Grid of all single digit pairs

A monadic link taking a list of two integers as its argument and returning an integer.

## Explanation

D               | Decimal digits
U              | Reverse order of each set of digits
z0            | Transpose with 0 as filler
Ɗ€    | For each pair of digits, do the following as a monad:
«   Ɗ       | - Minimum of the two digits and the following as a monad (vectorises):
9_         |   - 9 minus the digits
Ṛ        |   - Reverse the order
Ṁ      | - Maximum
U   | Reverse the order of the answer to restore the orignal order of digits
Ḍ  | Convert back from decimal digits to integer


If a digit matrix is acceptable input/output:

# Jelly, 12 bytes

Uz0«9_ṚƊṀƊ€U


Try it online!

# Pyth, 31 bytes

LhS,hb-9ebjkmeS,ydy_d_.t_MjRTQ0


Try it online!

LhS,hb-9eb             # Helper function, computes the (x & ~y) part
L                      # y = lambda b:
S                    #               sorted(                )
,                   #                       [    ,        ]
hb                 #                        b[0]
-9eb             #                              9-b[-1]
h                     #                                       [0] # sorted(...)[0] = minimum

jkmeS,ydy_d_.t_MjRTQ0  # Main program (example input Q: [123, 45])
jRTQ   # convert each input to a list of digits -> [[1,2,3],[4,5]]
_M       # reverse each -> [[3,2,1],[5,4]]
.t      0  # transpose, padding right with 0 -> [[3,5],[2,4],[1,0]]
_           # reverse -> [[1,0],[2,4],[3,5]]
m                    # map that over lambda d:
S,                 #   sorted([    ,           ])
yd               #           y(d)
y_d            #                 y(d[::-1])         # reversed
e                   #                             [-1]   # sorted(...)[-1] = maximum
jk                     # ''.join( ^^^ )


# Python 2, 71 bytes

f=lambda n,m,T=10:n+m and max(min(n%T,~m%T),min(m%T,~n%T))+f(n/T,m/T)*T


Try it online!

# Forth (gforth), 111 bytes

: m 10 /mod rot ;
: t 9 swap - min ;
: f 2dup + 0> if m m recurse 10 * -rot 2dup swap t -rot t max + 1 then * ;


Try it online!

### Code Explanation

: m          \ start a new word definition
10 /mod    \ get quotient and remainder of dividing by 10
rot        \ move item in 3rd stack position to top of stack
;            \ end word definition

\ word implementing "not" followed by "and"
: t          \ start a new word definition
9 swap -   \ subtract top stack element from 9
min        \ get the minimum of the top two stack elements
;            \ end word definition

: f          \ start a new word definition
2dup +     \ duplicate top two stack elements and add them together
0> if      \ if greater than 0
m m      \ divide both by 10, move remainders behind quotients
recurse  \ call self recursively
10 *     \ multiply result by 10 (decimal left shift of 1)
-rot     \ get remainders from original division
2dup     \ duplicate both remainders
swap t   \ swap order and call t (b & !a)
-rot t   \ move result back and call t on other pair (a & !b)
max + 1  \ get the max of the two results and add to total. put 1 on top of stack
then       \ end if block
*          \ multiply top two stack results (cheaper way of getting rid of extra 0)
;            \ end word definition


# C# (Visual C# Interactive Compiler), 75 bytes

a=>b=>a.Select((x,y)=>Math.Max(9-x<(y=y<b.Count?b[y]:0)?9-x:y,9-y<x?9-y:x))


Saved 6 bytes thanks to @someone

Try it online!

• 76 bytes. I think this question might be a unique opportunity to use Zip. – someone Sep 17 at 4:02
• @someone Thanks! Regarding Zip, you can't use it as it automatically truncates the longer collection to the length of the shorter one – Embodiment of Ignorance Sep 17 at 4:03

# PHP, 111 109 bytes

for(;''<($a=$argv[1][-++$i]).$b=$argv[2][-$i];)$s=min($a<5?9-$a:$a,max($a<5?$a:9-$a,$a<5?$b:9-$b)).$s;echo$s;


Try it online!

Tests: Try it online!

If we call the digits we want to XOR, $a and $b, I found that:

• When $a is less than 5, XOR = min(9-$a, max($a,$b))
• When $a is equal to or more than 5, XOR = min($a, max(9-$a, 9-$b))

So I implemented this logic plus a hack to handle numbers with different lengths. I take each digit form the end of both input numbers (with negative indexes like input[-1], input[-2], ...) and compute the XOR and put the result in reversed order in a string to be printed at the end. Since I take digits from the end of numbers, XOR results should be put together in reversed order. When one of the inputs is longer than the other one, the negative index on shorter input results in an empty string which is equal to 0.

# Retina, 85 59 bytes

^'0P.+
N$.$.%
¶

/../_(^
$" TdRd.¶. %N. ^N.. L^.  Try it online! Takes input as separate lines, but link is to test suite that reformats comma-separated input. Explanation: ^'0P.+  Left-pad with zeros both lines to the same length. N$.
$.% ¶  Sort each digit by its column index, then delete the newline. This has the effect of pairing the digits together in much the same way as a transpose would. /../_(  Apply separately to each pair of digits, joining the results together. ^$"


Duplicate the pair.

TdRd.¶.


Reverse the second digit of the first pair and the first digit of the second, so we now have x ~y on one line and ~x y on the other.

%N.


Sort the digits of each line in order, so that the first digit is now x & ~y or ~x & y as appropriate.

^N..


Reverse sort the lines.

L^.


And extract the first digit, which is the desired result.