I have written a Little Man Computer program to solve the following code challenge. But it doesn't produce the expected results.
The code challenge
The program should convert a given Little Man number into a number using the base-10 number system.
A Little Man number is encoded by 6 inputs, inspired by the Roman numeral system:
- Input #1 represents a coefficient for the number 500, like how many
Dyou would have in a roman numeral - Input #2 represents a coefficient for the number 100, like how many
Cyou would have in a roman numeral - Input #3 represents a coefficient for the number 50, like how many
Lyou would have in a roman numeral - Input #4 represents a coefficient for the number 10, like how many
Xyou would have in a roman numeral - Input #5 represents a coefficient for the number 5, like how many
Vyou would have in a roman numeral - Input #6 represents a coefficient for the number 1, like how many
Iyou would have in a roman numeral
The program should calculate the sum of these and output it.
Examples
If we give an input like 1,1,1,1,1,1 the output should be 666, as that is D+C+L+X+V+I with Roman numerals. Similarly if I give an input 0,0,0,0,0,1 the output should be 1.
If the user provides the inputs 0, 0, 0, 1, 2, 2, then this will be the equivalent of X+V+V+I+I (=0+0+0+10+25+21) = 22.
The program should only be able to calculate a natural number up to and including 999. If the user enters a Little Man numeral that exceeds this, the output is to be 999.
My code
This is my attempt at solving this challenge:
| Input section
IN | Read values for D, C, L, X, V, and I
STO D | Store D
IN
STO C | Store C
IN
STO L | Store L
IN
STO X | Store X
IN
STO V | Store V
IN
STO I | Store I
| Calculate the base-10 number
LDA D
BRZ SKIP_HUNDRED_THOUSANDS | If D is zero, skip calculation
ADD FIVEHUNDRED | Add the value of 500 times the hundred thousands place
STO RESULT | Store the result in memory location RESULT
SKIP_HUNDRED_THOUSANDS: LDA C
BRZ SKIP_TEN_THOUSANDS | If C is zero, skip calculation
ADD HUNDRED | Add the value of 100 times the ten thousands place
STO TEMP | Store the intermediate result in TEMP
LDA RESULT | Load the accumulated result
ADD TEMP | Add the intermediate result
STO RESULT | Store the updated result
SKIP_TEN_THOUSANDS: LDA L
BRZ SKIP_THOUSANDS | If L is zero, skip calculation
ADD FIFTY | Add the value of 50 times the thousands place
STO TEMP | Store the intermediate result in TEMP
LDA RESULT | Load the accumulated result
ADD TEMP | Add the intermediate result
STO RESULT | Store the updated result
SKIP_THOUSANDS: LDA X
BRZ SKIP_HUNDREDS | If X is zero, skip calculation
ADD TEN | Add the value of 10 times the hundreds place
STO TEMP | Store the intermediate result in TEMP
LDA RESULT | Load the accumulated result
ADD TEMP | Add the intermediate result
STO RESULT | Store the updated result
SKIP_HUNDREDS: LDA V
BRZ SKIP_TENS | If V is zero, skip calculation
ADD FIVE | Add the value of 5 times the tens place
STO TEMP | Store the intermediate result in TEMP
LDA RESULT | Load the accumulated result
ADD TEMP | Add the intermediate result
STO RESULT | Store the updated result
SKIP_TENS: LDA I
BRP EXCEEDS_LIMIT | If I is positive, jump to EXCEEDS_LIMIT
| Output section
LDA RESULT | Load the accumulated result
OUT | Output the result
HLT | Halt the program
| Handle case where input exceeds limit
EXCEEDS_LIMIT: LDA LIMIT_OUTPUT
OUT
HLT
| Data section
D: DAT 000
C: DAT 000
L: DAT 000
X: DAT 000
V: DAT 000
I: DAT 000
RESULT: DAT 000
TEMP: DAT 000
FIVEHUNDRED: DAT 500
HUNDRED: DAT 100
LIMIT_OUTPUT: DAT 999
FIFTY: DAT 050
TEN: DAT 010
FIVE: DAT 005
But this code is not giving the proper output, not for any of the above given examples.
What am I doing wrong here?
There are several issues in your attempt:
The last instruction adds 500 to the accumulator, not to the result. At that moment the accumulator has the value of
D, and so now you haveD+500. WhenDis 1, this means you now have 501, which is not what you want.A similar thing happens with the other inputs, so also
C+100is stored inTEMP, but actually you want to storeC * 100inTEMP(a product, not a sum). To multiply in LMC you need to create a loop and in this case add 100 repeatedly (Ctimes).Another issue occurs here:
There is no reason why a positive
Iwould mean the result exceeds the limit. Moreover,BRPwill check if the last subtraction resulted in overflow (on some LMC implementations also when the last addition resulted in overflow).Secondly, there is no part of your code that attempts to add
Ito the result.Solution
As discussed above, you need to implement loops to calculate a product (to calculate things like
C * 100,L * 50, ...). There are two exceptions:Dshould be 0 or 1, because if it is 2 or more, the result exceeds 999. So you don't really need a loop here and can just distinguish the three cases:Dis 0: nothing to do to the resultDis 1: account for 500Irepresents unit values, so you can just add the value ofIto the result.There is another behaviour to take into account: there is no strict specification for LMC what should happen if an addition leads to overflow. Wikipedia on LMC says about the
ADDinstruction:So it could be that a particular LMC emulator will set the negative flag when
ADDleads to overflow, but it is not guaranteed that this will happen on all compliant LMC emulators. We should thus not rely on such behavior. However, it is guaranteed that whenSUBleads to overflow that the negative flag will be set. So to detect overflow, we should perform subtractions, not additions. This we can do by starting with the value 999 in the result, and then subtracting values from it. At the end we should not forget to invert that result before outputing it.Implementation
Here is a runnable implemenation: