How can I multiply negative numbers using only some functions in vvm 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?
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
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