Write the shortest program or function that mimics the addition in this XKCD strip:

## Input

Two positive decimal integers containing only the digits 150.

## Output

The positive decimal integer result of adding the two inputs together in the manner shown above. This output should also only have the digits 150.

## Specification

### Input and Output

Input and output are numbers only containing digits 150.

### Roman Numerals

This challenge will use Standard Form numerals:

Thousands Hundreds Tens Units
1 M C X I
2 MM CC XX II
3 MMM CCC XXX III
4 MMMM CD XL IV
5 MMMMM D L V
6 MMMMMM DC LX VI
7 MMMMMMM DCC LXX VII
8 MMMMMMMM DCCC LXXX VIII
9 MMMMMMMMM CM XC IX

Note the subtractive notation on multiples of 40 and 90, and additive notation on multiples of 1000.

## Worked Example

Consider a test case below, 1010111 + 101051 = 1050110 (23 + 26 = 49).

Convert the inputs to Roman numerals, then to Arabic numerals:

1010111 => XXIII => 23
101051  => XXVI  => 26


23 + 26 => 49


Convert the output back to Roman numerals, then for each Roman numeral substitute its Arabic numeral value:

49 => XLIX => 10 50 1 10 => 1050110


## Test Cases

A + B = C (explanation)
=========
1 + 1 = 11 (1 + 1 = 2)
11 + 11 = 15 (2 + 2 = 4 == IV)
15 + 5 = 110 (4 + 5 = 9 == IX)
101010 + 1 = 1010101 (30 + 1 = 31)
1010 + 111 = 1010111 (20 + 3 = 23)
1010 + 15 = 101015 (20 + 4 = 24)
1010 + 5 = 10105 (20 + 5 = 25)
1010111 + 101051 = 1050110 (23 + 26 = 49)
101015 + 51 = 101010 (24 + 6 = 30)
1010015 + 15 = 101005111 (94 + 4 = 98)
100010010010101015 + 1000100010010010010505 = 100010001000500501010110 (1234 + 2345 = 3579)
100010010010101015 + 1000100010001000100010001000100050010010050105 = 100010001000100010001000100010001000100100010100110 (1234 + 8765 = 9999)


## Other Notes

As seen in the comic, Randall is doing a simple substitution of Roman numerals with their decimal equivalents:

• I => 1
• V => 5
• X => 10

Presumably, this will be extended for all Roman numerals (up to 1000):

• L => 50
• C => 100
• D => 500
• M => 1000

This is , so shortest code wins!

• Based on the same XKCD: ro1000an nu1000era50 en100o501ng Jun 27 at 13:22
• @Arnauld, Steffan yeah that testcase had two extra zeroes, fixed now Jun 27 at 15:43
• @Arnauld thanks for letting me know, these test case issues should've been caught in sandbox but weren't somehow? Jun 27 at 16:20
• The last test case is wrong too. 100010001000100010001000100010001010010050105 is MMMMMMMMXCCLXV, but it should be MMMMMMMMDCCLXV (1000100010001000100010001000100050010010050105). Jun 27 at 16:30
• May we take the string sum as input instead of 2 separate arguments? (e.g. "1010+15") Jun 28 at 15:27

# Vyxal, 21 bytes

ƛ.0*Ẏ⌊øṘṅøṘ;∑øṘvøṘṅ


Try it Online!

## How?

ƛ.0*Ẏ⌊øṘṅøṘ;∑øṘvøṘṅ
ƛ                      # Map, and for both strings:
.0*Ẏ                #  Get all regex matches ".0*"
⌊               #  Convert each to integers
øṘ             #  Convert each to their roman numeral
ṅ            #  Join together to a single string
øṘ          #  Convert from roman numeral to number
;         # Close map
∑        # Sum
øṘ      # Convert to roman numeral
vøṘ   # Convert each character from roman numeral to number
ṅ  # Join together to a string


# Factor + roman, 117 114 bytes

[ [ R/ .0*/ all-matching-subseqs [ dec> >roman ] f map-as concat ] bi@
roman+ 1 group [ roman> >dec ] map-concat ]


Needs modern Factor for >dec, but here's a version that works on ATO for 3 more bytes:

Attempt This Online!

-3 bytes thanks to @Steffan

• You can use .0* instead of [15]0* Jun 27 at 15:25
• @Steffan Good point, thanks! Jun 27 at 15:32

# JavaScript (ES6), 204 bytes

Expects (a)(b), where both arguments are strings.

a=>b=>(h=(n,k)=>n?h(n/10|0,k+0)+[k%8?[,k,d=k+k,d+k,k+(x=k*5),x,x+k,x+d,x+d+k,d+0][n%10]:k.repeat(n)]:'')((g=s=>s.replace(p=/.0*/g,s=>s-p?(t+=s<p?n:s-n,p=s<p?n=+s:0/(n=0)):n+=p=+s,t=n=0)&&t+n)(a)+g(b),'1')


Try it online!

### Parsing the input strings

g = s =>                    // s = input string
s.replace(                  // search in s:
p = /.0*/g,               //   each non-zero digit followed by some 0's
s =>                      //   given this substring s:
s - p ?                   //     if s is not equal to the previous match:
(                       //
t +=                  //       add to t:
s < p ? n           //         either n if s < p
: s - n,      //         or s - n otherwise (e.g. 1 10 -> 9)
p =                   //       set p to:
s < p ? n = +s      //         s (also loaded in n) if s < p
: 0 / (n = 0) //         or NaN otherwise (and set n to 0)
)                       //
:                         //     else:
n +=                    //       add s to the accumulator n
p = +s,               //       and copy s in p
t = n = 0                 //   start with t = n = 0
)                           // end of replace()
&& t + n                    // return the sum of t and the accumulator


### Formatting the output

h = (n, k) =>               // n = number to convert, k = current prefix
n ?                         // if n is not equal to 0:
h(                        //   do a recursive call with:
n / 10 | 0,             //     floor(n / 10)
k + 0                   //     a '0' appended to k
) +                       //   end of recursive call
[                         //   append:
k % 8 ?                 //     if k is not equal to '1000':
[ ,                   //       0 : nothing
k,                  //       1 : k           --> e.g. '10'
d = k + k,          //       2 : k+k         --> '1010'
d + k,              //       3 : k+k+k       --> '101010'
k + (x = k * 5),    //       4 : k+(5*k)     --> '1050'
x,                  //       5 : 5*k         --> '50'
x + k,              //       6 : (5*k)+k     --> '5010'
x + d,              //       7 : (5*k)+k+k   --> '501010'
x + d + k,          //       8 : (5*k)+k+k+k --> '50101010'
d + 0               //       9 : k+k+0       --> '10100'
][n % 10]             //       select the correct entry
:                       //     else:
k.repeat(n)           //       just repeat '1000' n times
]                         //
:                           // else:
''                        //   stop the recursion

• 157 bytes
– tsh
Jun 28 at 5:54
• @tsh That's a really neat idea. I'll update my answer later when/if the OP confirms that it's a valid input format. Jun 28 at 15:28

# 05AB1E, 2423 20 bytes

εDSĀÅ¡J.XJ.v}O.XS.vJ


-3 bytes thanks to @CommandMaster

X3FD5*x}r)D.X:.vO.XS.vJ


ASCII only. :)

Explanation:

ε            # Map over both integers in the (implicit) input-pair:
D           #  Duplicate the current integer
S          #  Convert the copy to a list of digits
Ā         #  Check for each digit that it's NOT 0 (0 if 0; 1 otherwise)
Å¡       #  Split the number on the truthy (==1) values
J      #  Join each inner list together
.X    #  Convert each from an integer to a Roman Numeral
J   #  Join it together to a single string
.v # Convert it from a Roman Numeral to an integer
}O           # After the map: sum the two integers together
.X         # Convert this sum back to a Roman Numeral
S        # Convert it to a list of characters
.v      # Convert each character from a Roman Numeral back to an integer
J     # Join them together
# (after which the result is output implicitly)

X3FD5*x}r)   # Push list [1000,500,100,50,10,5,1]:
X            #  Push 1
3F          #  Loop 3 times:
D         #   Duplicate the current value
5*       #   Multiply the copy by 5
x      #   Double it (without popping)
}r    #  After the loop: reverse all values on the stack
)   #  Then wrap the entire stack into a list
D            # Duplicate this list
.X          # Convert each to a Roman Numeral: ["M","C","D","L","T","V","I"]
:         # Replace all integers to these characters in the (implicit) input-pair
.v           # Convert both strings from Roman Numerals to integers
O.XS.vJ    # Same as above

• You can split on non-zero digits instead of creating the list of all values, for a -3: εD€ĀÅ¡J.XJ.v}O.XS.vJ Try it online! (although you lose the ASCII-onlyness) Jun 30 at 15:17