assemblymultiplicationlittle-man-computervvm

How can I multiply negative numbers using the VVM program editor?


How can I multiply negative numbers using only some functions in like INP, STO, LDA, BR, BRP, SUB, ADD, and OUT?

My code can multiply positive numbers, but it does not work correctly if the second input is negative or zero:

in
sto 99
in
sto 98
lda 97
add 99
sto 97 
lda 98 
sub 90
sto 98
lda 98
brz 13
br 04
lda 97
out
hlt
*90
dat 001

When the second input is zero or less, the program keeps looping and eventually hits a "Data value out of range (1000)" error at add 99, meaning the result exceeded 999.

I'm stuck, I don't know how to fix this. I feel like I need to convert the incoming negative inputs to positive and multiply them like that, but I don't know how to do this and whether it will solve the problem.

How can I make it work for non-positive values for the second input?


Solution

  • Indeed, your code does not work correctly when the second input is negative or zero.

    For the case of zero: your code only checks whether the second input (which serves as a count down) becomes zero after having made one iteration of the loop. This check should better happen at the start of the loop so it is also performed at the very start.

    For the case of a negative value: in this case you should "flip the sign" of both inputs, since (-a)*(-b) == a*b. To "flip" the sign, you can subtract the original value from 0, since 0-a == -a.

    It is a pity that the VVM does not support labels, and so you must use the correct numerical address in the operands. This can be a pain when a program is still under construction and those addresses likely change as you add more code. For that reason I would suggest leaving some gaps between code blocks, so that these jump-to addresses can be kept stable while you edit your code.

    Code:

    in
    sto 99
    in
    brp 20     Normal case: start loop
    // Remove sign from the second input (98)
    sto 98
    lda 91     Zero
    sub 98
    sto 98
    // Toggle sign of the first input (99) to compensate
    lda 91     Zero
    sub 99
    sto 99
    lda 98     Prepare for loop
    br  20     Start the loop
    ///////////////////// LOOP ////////////
    *20
    brz 40     Check immediately for 0
    sto 98
    lda 97
    add 99
    sto 97   
    lda 98    
    sub 90     Subtract one
    br  20     Repeat
    ///////////////////// OUTPUT //////////
    *40
    lda 97
    out
    hlt
    ///////////////////// DATA ////////////
    *90
    dat 001
    dat 000
    

    Remarks:

    The final dat 000 is just to highlight that this memory address (91) is used by the program, and should have value 0. This is the default, and so it is not strictly necessary to include it.

    The initial value for the result (at address 97) is also assumed to be 0 at the start of the program. This is a slightly different case, because this result will be updated by the program. But when the program is reloaded, all memory is first cleared to 000, so that we can assume the result to start with the value 0 at each run.

    However, there is an option in the VVM, in the Execute menu, called Reload @ Restart?. It is on by default. If you turn it off, and restart the program after it has run at least once, then there will be no reload, and so the memory will stay in the state as it was after the preceding run. This means that the result at address 97 will in most cases not be 0. By consequence, the new run will add the new product to the result, giving maybe a surprising result -- it depends what you expect to happen in this case.

    If you want every run to start with the value zero for the result, even when the above mentioned option is turned off, then explicitly initialise the result at the start of your program, by inserting these two instructions at the very top:

    lda 91    Zero
    sto 97    Initialise the result to 0